4 androidQMIメカニズム--- QCRILメッセージ送信



4 Android Qmi Mechanism Qcril Message Transmission



元の: https://blog.csdn.net/u012439416/article/details/74276765

4QCRILメッセージの送信
rilにリクエストがあると、rilライブラリのonRequest()メソッドが呼び出されます。この時点で、現在のQcrilに登録されている機能のリストに基づいています。



qcril_request_apiのonRequest_ridメソッドを入力します。したがって、onRequest_ridメソッドはQCRILのエントリになります。

方法。呼び出しのプロセスは次のとおりです。



Qcril_execute_eventは、最初にqcril_hash_table_lookupメソッドを呼び出して、テーブルから現在のイベントを検索します(そうでない場合)。

現在のリクエストを見つけます。違法と見なされます。見つけたら、qcril_dispatch_event()と入力してイベントをディスパッチします。

(entry_ptr->ハンドラー)(params_ptr、&ret)



Retは戻りの結果であり、現在のイベントハンドラーはentry_ptr-> handlerによって呼び出されます。ここに対応するハンドラー

qcril_hash_tableのアイテム。最初の章では、qcril_event_tableテーブルのデータがqcril_hash_tableにコピーされます。

したがって、ここでのハンドラーは、qcril_event_tableのアイテムとして理解できます。

プロセスが特定のリクエストの処理機能に入ると、たとえば、対応するリクエストはRIL_REQUEST_DIALであり、

その処理機能は次のとおりです。qcril_qmi_voice_request_dial電話を切るための要求はRIL_REQUEST_HANGUPです。

その処理関数はqcril_qmi_voice_request_hangupです

qcril_qmi_voice_request_hangupメソッドはさらにqcril_qmi_client_send_msg_asyncを呼び出してQMIレイヤーに送信します。

もちろん、qcril_qmi_client_send_msg_asyncは非同期で処理され、qcril_qmi_client_send_msg_syncは同期的に処理されます。

最後に、両方のメソッドがqmi_client_send_msg_syncを呼び出して送信を完了します。

他のいくつかの処理メソッドは、これら2つのメソッドを呼び出してQMIレイヤーに送信するか、qmi_client_send_msg_syncを直接呼び出して送信する場合があります。
2.1QMI層のメッセージ処理

通話フローチャートは次のとおりです。

ril_err = qcril_qmi_client_send_msg_async(QCRIL_QMI_CLIENT_VOICE、
QMI_VOICE_ANSWER_CALL_REQ_V02、
&ans_call_req_msg、
sizeof(ans_call_req_msg)、
ans_call_resp_msg_ptr、
sizeof(* ans_call_resp_msg_ptr)、
(void *)(uintptr_t)user_data)

ここで選択したqmi_serviceは音声です。音声が伝送チャネルとして選択される理由は、2番目のパラメータがQMI_VOICE_GET_CONFIG_REQ_V02であるためです。

qcril_qmi_client_send_msg_asyncメソッドの主なロジックは次のとおりです。

if(NULL!= client_info.qmi_svc_clients [svc_type])
{{
qmi_error = qmi_client_send_msg_async_with_shm(client_info.qmi_svc_clients [svc_type]、
•••

この関数は、最初に、呼び出している音声のサービスタイプがQMIによって定義されたサービスリストに存在するかどうかを判別します。存在しない場合は、

また、自分でサービスを追加する必要があります。存在する場合は、メッセージをQMIクライアントに送信するインターフェース関数qmi_client_send_msg_async_with_shmを実行します。

このメソッドは、qmi_client_send_msg_syncメソッドを直接呼び出します。
rc = qmi_client_send_msg_sync(user_handle、
msg_id、
req_c_struct、
req_c_struct_len、
resp_c_struct、
resp_c_struct_len、
timeout_msecs)

同期メッセージがQMUXレイヤーのBP側に送信された後、BPの応答を待機するため、関数の最後のパラメーターはタイムアウトです。

非同期メッセージは必要ありません。

qmi_client_send_msg_syncメソッドは、最初に要求メッセージの長さを計算し、返されるメッセージの最大長を設定し、次に要求を設定します

メッセージはQMUX形式でエンコードされ、関数qmi_service_send_msg_sync_millisec()を介して送信されます。最後に、

BP側から返される応答を待ち、返された応答をデコードします。

2.2QMUXレイヤーのメッセージ処理

QMUXメッセージ処理フローチャートは以下のとおりです。

qmi_service_send_msg_sync_millisecメソッドは、最初にQMUXレイヤーに必要ないくつかのメッセージを取得し、チャネルのconn_idを送信します。

QMUXメッセージ形式で使用されるClient_id

conn_id = QMI_SRVC_CLIENT_HANDLE_TO_CONN_ID(user_handle)

client_id = QMI_SRVC_CLIENT_HANDLE_TO_CLIENT_ID(user_handle)

次に、メッセージqmi_service_txn_info_type * txnを転送する構造体にパッケージ化されます。これは、フォローアップコードの後半にあります。

QMUXメッセージのtranciationIDです。

/ * Idフィールドを初期化します* /
txn-> conn_id = conn_id
txn-> service_id = service_id
txn-> client_id = client_id
txn-> msg_id = msg_id
txn-> api_flag = api_flag
/ *フィールドを初期化します* /
txn-> srvc_txn_info.txn_type = QMI_TXN_SYNC
txn-> srvc_txn_info.sync_async.sync.user_reply_buf = NULL
txn-> srvc_txn_info.sync_async.sync.user_reply_buf_size = 0
txn-> srvc_txn_info.sync_async.sync.rsp_rc = QMI_NO_ERR
txn-> srvc_txn_info.sync_async.sync.qmi_err_code = QMI_SERVICE_ERR_NONE


これらが完了すると、qmi_service_send_msgメソッドが呼び出されて送信されます。このメソッドは、サービスIDとチャネルのconn_idが有効かどうかを判別します。

if((int)conn_id> =(int)QMI_MAX_CONN_IDS)
{{
QMI_INTERNAL_ERRを返します
}
if(qmi_qcci_internal_public_service_id_to_bookkeeping_service_id(service_id)> =
QMI_MAX_SERVICES)
{{
QMI_INTERNAL_ERRを返します
}

最初にqmi_service_write_std_srvc_msg_hdrを呼び出します。このメソッドは、送信されたメッセージにメッセージIDと長さを追加します。

if(qmi_service_write_std_srvc_msg_hdr(&msg_buf、
&msg_buf_size、
msg_id、
msg_buf_size)<0)

したがって、QMI送信側のインターフェイス関数qmi_client_send_msg_sync()のコーデックの原則がQMUXに従っていることを推測するのは難しくありません。

メッセージのTLV形式はコード化されています。次に、このステップに加えて、メッセージIDと長さ、QMUXSDU全体のQMIサービスメッセージに進みます。

完了しました。 qmi_service_write_std_srvc_msg_hdrメソッドは次のとおりです。

静的
int qmi_service_write_std_srvc_msg_hdr(unsigned char ** msg_buf、
int * msg_buf_size、unsigned long msg_id、int length)
{{
unsigned char * tmp_msg_buf
/ *ポインタを4バイト上にバックアップします* /
* msg_buf- = QMI_SRVC_STD_MSG_HDR_SIZE
* msg_buf_size + = QMI_SRVC_STD_MSG_HDR_SIZE
tmp_msg_buf = * msg_buf
/ *メッセージIDフィールド(16ビット)を書き込みます* /
WRITE_16_BIT_VAL(tmp_msg_buf、msg_id)
/ *長さフィールドを書き込みます* /
WRITE_16_BIT_VAL(tmp_msg_buf、length)
0を返す
}

メッセージIDと長さを追加する方法:メッセージポインタのオフセット。ポインタが前方に移動し、メッセージの長さが長くなります。次に、同様の方法を使用します。

制御フラグと切り捨てIDは、関数qmi_service_write_std_txn_hdr_and_inc_txn_id()によって追加されます。

QMUXSDU全体を完了します。最後に、関数qmi_qmux_if_send_qmi_msg()を介してQMUXレイヤーに送信されます。

QMIインターフェイスプロセス全体が終了した後、主な機能は、上位層から送信された要求を取得し、対応するserviceid、conn_id、client id、を選択することです。

メッセージは、QMUX SDU全体のカプセル化を完了し、QMUXに送信されます。

関数qmi_qmux_if_send_qmi_msg()の関数は、パッケージ化されたQMUXSDUを上位層に追加することです。

QMUXHEADERは機能します。 QMUXヘッダーを追加する方法も、ポインターオフセットです。

qmi_qmux_if_send_qmi_msgメソッドは、処理のためにqmi_qmux_if_send_to_qmuxメソッドを直接呼び出します。

まず、QMUXヘッダーの制御ビット、QMIサービスID、およびQMIクライアントIDが構造体hdrにパッケージ化され、Memcpyによって完成されます。
/ *送信するメッセージを設定します* /
memset(&hdr、0、sizeof(qmi_qmux_if_msg_hdr_type))
hdr.msg_id = msg_id
hdr.qmux_client_id = qmux_client_id
hdr.qmux_txn_id = qmux_txn_id
hdr.qmi_conn_id = qmi_conn_id
hdr.qmi_service_id = qmi_service_id
hdr.qmi_client_id = qmi_client_id
hdr.control_flags = 0 // TXからQMUXには使用されず、RXにのみ有効です
/ * msgポインタをデクリメントしてmsg_lenをインクリメントします* /
msg- = QMI_QMUX_IF_HDR_SIZE
msg_len + =(int)QMI_QMUX_IF_HDR_SIZE
/ *ヘッダーをメッセージバッファにコピーします* /
memcpy((void *)msg、(void *)&hdr、QMI_QMUX_IF_HDR_SIZE)

QMUXMessage全体がここにパッケージ化されています。次に、パッケージ化されたQMUXメッセージは、マクロを呼び出すことによって下位層に送信されます。

QMI_QMUX_IF_PLATFORM_TX_MSG()。このマクロは、関数linux_qmi_qmux_if_client_tx_msg()を定義します。

qmi_platform_qmux_if.hのマクロQMI_QMUX_IF_PLATFORM_TX_MSGは、次のように定義されています。

#define QMI_QMUX_IF_PLATFORM_TX_MSG(client、msg、msg_len)

linux_qmi_qmux_if_client_tx_msg(client、msg、msg_len)

したがって、マクロQMI_QMUX_IF_PLATFORM_TX_MSGを呼び出すことは、linux_qmi_qmux_if_client_tx_msgメソッドを呼び出すことです。

このメソッドは、ソケットを介してlinux_qmi_qmux_if_serverのインターフェースにメッセージを送信します。

if((rc = send(client_fd、
(void *)msg、
(size_t)msg_len、
MSG_DONTWAIT | MSG_NOSIGNAL))<0)