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)