技术开发 频道

深入详解Android GSM驱动模块

  明白了event队列的基本运行流程,我们可以来看看request是怎么传入和dispatch的了.
上层的部分,核心代码在 frameworks/base/telephony/java/com/android/internal/telephony/gsm/RIL.java, 这是android java框架处理radio(gsm)的核心组件.本文因为主要关注rild,也就是 驱动部分,所以这里只作简单介绍.
我们看一个具体的例子,RIL.java中的dial函数:
public void
dial (String address, int clirMode, Message result)
{
RILRequest rr = RILRequest.obtain(RIL_REQUEST_DIAL, result);

rr.mp.writeString(address);
rr.mp.writeInt(clirMode);

if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));

send(rr);
}

  rr是以RIL_REQUEST_DIAL为request号而申请的一个RILRequest对象.这个request 号在java框架和rild库中共享(参考RILConstants.java中这些值的由来)。

  RILRequest初始化的时候,会连接名为rild的socket(也就是rild中 s_listen_event绑定的socket),初始化数据传输的通道.
rr.mp是Parcel对象,Parcel是一套简单的序列化协议,用于将对象(或对象的成 员)序列化成字节流,以供传递参数之用.这里可以看到 String address和int clirMode都是将依次序列化的成员.在这之前,rr初始化的时候,request号跟 request的序列号(自动生成的递增数),已经成为头两个将被序列化的成员.这为 后面的request解析打下了基础。

  接下来是send到handleMessage的流程,send将rr直接传递给另一个线程的 handleMessage,handleMessage执行data = rr.mp.marshall()执行序列化操作, 并 将data字节流写入到rild socket。

  接下来回到我们的rild,select发现rild socket有了请求链接的信号,导致 s_listen_event被挂入pending_list,执行event->func,即
static void listenCallback (int fd, short flags, void *param);。

  接下来,s_fdCommand = accept(s_fdListen, (sockaddr *) &peeraddr, &socklen),获取传入的socket描述符,也就是上层的java RIL传入的连接。

  然后,通过record_stream_new建立起一个record_stream, 将其与s_fdCommand绑 定, 这里我们不关注record_stream 的具体流程, 我们来关注command event的回 调, processCommandsCallback函数, 从前面的event机制分析, 一旦s_fdCommand 上有数据, 此回调函数就会被调用. (略过onNewCommandConnect的分析)。

  processCommandsCallback通过record_stream_get_next阻塞读取s_fdCommand上发 来的 数据, 直到收到一完整的request(request包的完整性由record_stream的机 制保证), 然后将其送达processCommandBuffer。

  进入processCommandBuffer以后,我们就正式进入了命令的解析部分. 每个命令将 以RequestInfo的形式存在。
 

typedef struct RequestInfo {
int32_t token;
//this is not RIL_Token
CommandInfo *pCI;
struct RequestInfo
*p_next;
char cancelled;
char local; // responses to local commands do not go back to command process
} RequestInfo;

  这里的pRI就是一个RequestInfo结构指针, 从socket过来的数据流, 前面提到是 Parcel处理过的序列化字节流, 这里会通过反序列化的方法提取出来. 最前面的是 request号, 以及token域(request的递增序列号). 我们更关注这个request号, 前 面提到, 上层和rild之间, 这个号是统一的. 它的定义是一个包含ril_commands.h 的枚举, 在ril.cpp中
 

static CommandInfo s_commands[] = {
#include
"ril_commands.h"
};
pRI直接访问这个数组, 来获取自己的pCI.
这是一个CommandInfo结构:
typedef struct {
int requestNumber;
void (*dispatchFunction) (Parcel &p, struct RequestInfo *pRI);
int(*responseFunction) (Parcel &p, void *response, size_t responselen);
} CommandInfo;

  基本解析到这里就完成了, 接下来, pRI被挂入pending的request队列, 执行具体 的pCI->dispatchFunction, 进行详细解析.

0
相关文章