4 android QMI机制---QCRIL消息发送

原文:https://blog.csdn.net/u012439416/article/details/74276765

4 QCRIL消息发送
当ril有请求过来时,就会调用ril库的onRequest()方法,此时就会根据当前Qcril注册的函数列表

进入到qcril_request_api的onRequest_rid方法中,因此, onRequest_rid方法是QCRIL中的入口

方法。调用的流程如如下,

qcril_execute_event首先调用qcril_hash_table_lookup方法从表中查找当前的Event,如果没有

找到当前的Request,就认为非法,找到之后,进入qcril_dispatch_event()中派发该Event,

(entry_ptr->handler)(params_ptr, &ret);

ret是返回的结果,通过entry_ptr->handler调用当前Event的处理函数。这里的handler对应

qcril_hash_table中的某一项。第一章中将qcril_event_table表中的数据拷贝给了qcril_hash_table,

所以这里的handler可以理解为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是同步处理的。

最后,这2个方法都会调用qmi_client_send_msg_sync完成发送。

一些其他的处理方法或者会调用这两个方法发送到QMI层,或者直接调用qmi_client_send_msg_sync发送。
2.1 QMI层消息处理

调用流程图如下,

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是voice。之所以选择voice作为发送通道,是因为第二个参数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],
   •••

这个函数首先会去判断我们调用的这个voice的服务类型是否存在于QMI定义的服务列表中,如果不存在,

还需要自己添加该service,如果存在,执行QMI client端发送消息的接口函数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的响应所以函数的最后一个参数是一个timeout,

而异步消息不需要。

qmi_client_send_msg_sync方法首先计算请求消息的长度和设定返回消息的最大长度,然后对请求

消息按QMUX格式进行编码通过函数qmi_service_send_msg_sync_millisec()发送出去,最后

等待BP侧返回的响应,将返回的response进行解码。

2.2 QMUX层消息处理

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,这个txn在稍后跟进代码中会发现,

就是QMUX消息中的tranciationID

/* Initialize Id fields */
  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;
  /* Initialize fields */
  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)
  {
    return QMI_INTERNAL_ERR;
  }
  if ( qmi_qcci_internal_public_service_id_to_bookkeeping_service_id ( service_id ) >= 
QMI_MAX_SERVICES)
  {
    return QMI_INTERNAL_ERR;
  }

首先调用qmi_service_write_std_srvc_msg_hdr,方法给发送过来的消息加上message ID和Length,

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格式进行编解码。再走到这步加上message ID和Length,整个QMUX SDU中的QMI service message

已完成。qmi_service_write_std_srvc_msg_hdr方法如下,

static
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;
  /* Back pointer up by 4 bytes */
  *msg_buf -= QMI_SRVC_STD_MSG_HDR_SIZE;
  *msg_buf_size += QMI_SRVC_STD_MSG_HDR_SIZE;
  tmp_msg_buf = *msg_buf;
  /* Write the message ID field (16 bits) */
  WRITE_16_BIT_VAL (tmp_msg_buf,msg_id);
  /* Write the length field */
  WRITE_16_BIT_VAL (tmp_msg_buf,length);
  return 0;
}

加message ID和Length的方法:消息指针的偏移。指针向前偏移,消息长度增加。随后用类似方法,

通过函数qmi_service_write_std_txn_hdr_and_inc_txn_id()将control flags和tranciation ID加上,

完成整个QMUX SDU。最后通过函数qmi_qmux_if_send_qmi_msg()发送到QMUX层,到这里,

整个QMI interface的流程走完,主要作用:获取上层发送的请求,选择相应的serviceid,conn_id,client id,

对消息完成整个QMUX SDU的封装,发送到QMUX。

     函数qmi_qmux_if_send_qmi_msg()的工作是,对上层发过来打包好的QMUX SDU完成加

QMUX HEADER的工作。添加QMUX header的方法同样是指针偏移。

qmi_qmux_if_send_qmi_msg方法直接调用qmi_qmux_if_send_to_qmux方法进行处理,

首先将QMUX header里面的控制位,QMI服务ID,QMI客户端ID打包到结构体hdr,再通过Memcpy完成,
/* Set up message for sending */
  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; // Unused for TX to QMUX, only valid for RX
  /* Decrement msg pointer and increment msg_len */
  msg -= QMI_QMUX_IF_HDR_SIZE;
  msg_len += (int)QMI_QMUX_IF_HDR_SIZE;
  /* Copy header into message buffer */
  memcpy ((void *)msg, (void *)&hdr, QMI_QMUX_IF_HDR_SIZE);

到这里整个QMUXMessage完成封装。然后会把封装好的QMUXmessage发到下层,通过调用宏

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方法,

该方法通过socket,将消息发到linux_qmi_qmux_if_server的接口。

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

 

猜你喜欢

转载自blog.csdn.net/keyanting_2018/article/details/83543833