第1章 RILD及Qcril初始化流程
Rild是android提供的框架,位置位于AP侧(AP主处理器),对接Phone进程和BP侧modem。(BP从处理器)
图1
双卡手机在phone进程中会有2个phone的实例对应各个卡槽,相应的RILD进程也会有2个,phone和RILD之间通过Socket保持连接,各卡槽之间的操作互相独立。
高通用qcril+qmi机制实现,而MTK则直接使用AT指令与modem通信。
1.1 RILD进程的启动
Rild是系统服务,在init.rc中能找到启动的描述。
/hardware/ril/rild/rild.rc中启动第一个rild
图1 rild.rc中启动第一个rild
/device/qcom/common/rootdir/etc/init.qcom.rc中启动第二个rild:
图2启动第二个rild(这里除了rild2还有rild3)
2.1 RILD主函数
根据init.qcom.rc可以看出,rild的入口函数名字为main。/hardware/ril/rild/rild.c
接着看一下rild.c的main函数。
int main(int argc, char **argv) {
…….
//1. 从启动参数中获取clientID,代表几就是第几个RILD
for (i = 1; i < argc ;) {……
if (0 == strcmp(argv[i], "-l") && (argc - i > 1)) {……
clientId = argv[i+1];
//2. 使用clientID设置RILD的socket名字
if (strncmp(clientId, "0", MAX_CLIENT_ID_LENGTH)) {……}
//3. 获取vendor ril库路径(3.1)
if (rilLibPath == NULL) {
if ( 0 == property_get(LIB_PATH_PROPERTY, libPath, NULL)) {
goto done;
} else { rilLibPath = libPath; } }
//4. 打开vendor ril库(3.1)
dlHandle = dlopen(rilLibPath, RTLD_NOW);
//5. 启动消息循环,LIdRIL开始循环监听socket事件(3.2)
RIL_startEventLoop();
//6. 获取vendor RIL的初始化入口方法(3.3)
rilInit =(const RIL_RadioFunctions *(*)(const struct RIL_Env *, int, char **))dlsym(dlHandle, "RIL_Init");
//7. 调用reference-ril.so动态链接库的RIL_Init方法,传递s_rilEnv参数给reference-ril.so,并返回funcs(3.3)
rilArgv[argc++] = "-c";
rilArgv[argc++] = (char*)clientId;
rilArgv[0] = argv[0];
funcs = rilInit(&s_rilEnv, argc, rilArgv);
//8. 调用libril.so的RIL_register函数,将funcs传递给libril.so(3.4)
RIL_register(funcs);
总结main函数的主要内容:
1)获取vendor ril并打开;(第3、4步,对应3.1)
2)启动消息循环;调用RIL_startEventLoop函数,LibRIL开启循环监听socket连接,即可开始接收RILJ发起的socket连接请求和RIL solicited消息请求。(第5步,对应3.2)
3)获得vendor ril入口方法,并取得vendor ril的消息处理函数列表;(6、7步,对应3.3)
4)注册vendor ril回调方法。(第8步,对应3.4)
S_rilEnv对应RIL_Env;
Funcs对应RIL_RadioFunctions。
LibRIL运行环境的加载过程,体现在rild.c代码的main函数中RIL_startEventLoop和RIL_register两个函数的调用。
3.1 深入分析main函数
3.1.1 获取vendor RIL库文件路径
Main函数中通过getprop获取了vendor ril文件的路径,property名为“rild.libpath”。/hardware/ril/rild/rild.c文件中:
首先定义LIB_PATH_PROPERTY的值;
#define LIB_PATH_PROPERTY "rild.libpath"
然后在main函数中获取vendor ril文件的路径:
property_get(LIB_PATH_PROPERTY, libPath, NULL)。
1. 找到libril-qc-qmi-1.so库文件路径;
2. 在/vendor/qcom/proprietary/qcril/qcril_qmi/qcril_qmi.mk中有描述;
图3库文件路径描述
在取得了vendor ril库文件路径之后,打开库并取得文件句柄,流程似乎即将进入到vendor ril。但在此之前,rild会先启动一个子线程消息循环,然后再开始qcril的流程。
3.2 RIL_startEventLoop启动监听消息循环
RIL_startEventLoop创建了一个线程,用于执行eventLoop这个函数。
1. Ril.cpp中的RIL_startEventLoop():
启动线程,执行eventLoop函数,在eventLoop函数中会将s_started置为1.
S_started会在eventLoop被执行后置为1,保证了线程启动后才离开这个函数
图4在while循环主要是通过判断s_started的值,保证线程已经启动且eventLoop已经开始被执行,因为在eventLoop函数中会将s_started值置为1。
2. eventLoop是Rild中消息获取和分发的中心,接下来来详细查看一下:
// 1.初始化fd_set(readFds)3.2.1;
// 2.初始化几个消息链表(watch_table/pending_list/timer_list);
//使RIL_startEventLoop退出;
//获得读&写管道3.2.2;