转载:
https://blog.csdn.net/qq_27540925/article/details/79356799
https://blog.csdn.net/u010961631/article/details/9446377
一、概述
RIL分为RILJ和RILD两部分,RILJ属于Java层,RILD属于C层。RILD处于android系统HAL层,是RILJ与modem(基带芯片)沟通的桥梁。
二、RIL 代码框架
如上图所示RIL 整体架构分为三层,最上层为RIL-Java 适配层,中间层即为RILD, 下层为Modem. RIL-Java 通过socket与RILD 层对接,RILD层与Modem通过串口对接。
三、RILD 简介
Radio Interface Layer Demon,简称RIL,是手机上Modem(基带芯片,WCDMA,CDMA2000等就是指基带芯片的不同技术)与android系统通讯的桥梁,RIL的角色非常重要,RIL被设计成能够可靠的高效的传输数据一个模块
Android RILD可以分成2个模块,一个部分RIL Demon(RILD),用于通过socket和framework通讯以及处理整个RIL的event;另一部分是手机厂商自己实现的部分,在这里暂时称之为vendor RIL。 之所以这样设计是因为不同的厂商使用的Modem不一样,而RIL又和Modem紧密联系,所以Android有把和Modem联系紧密的部分和公共部分剥离开,让不同的厂商可以自己实现vendor RIL以适应厂商自己的Modem。所以又可以细化如下图所示:
但就目前来说,不同的芯片厂商都是自己实现了RILD,但基本的架构是沿用了Google rild。
四、RILD 文件结构
Android系统的ril代码在hardware/ril 目录如下图所示:
rild: 包括rild.c
libril: 主要包括ril.cpp, ril_event.cpp 等,该包生成动态共享库libril.so, 与rild结合相当紧密。组成部分为ril.cpp,ril_event.cpp。libril.so驻留在 rild这一守护进程中,主要完成同上层通信的工作,接受rilJ request并传递给reference-ril.so, 同时把来自reference -ril.so的response回传给调用进程。
reference-ril: 该文件中内容将生成动态库reference-ril.so, 包括的文件主要有atchannel.c,at_tok.c,misc.c等。reference-ril so 和 rild 结合比较松散,通过dlopen去打开库,这也是因为reference-ril.so主要负责跟Modem硬件通信,这样的设计可以方便适配更多不同的Modem。它转换来自libril.so的请求为AT命令,同时监控Modem的反馈信息,并传递回libril.so。在初始化时, rild通过符号RIL_Init获取一组函数指针并以此与之建立联系。atchannels负责处理提交的at commnd, 并通过串口发送给modem, 以及使用reader-loop循环监控串口modem上报的信息。
1、rild.c
rild.c 为RILD 的入口,负责初始化事件循环(libril.so),启动关联modem的串口监听(librefrence_ril.so)。
init event loop. 使用ril.cpp 中的RIL_startEventLoop 方法。ril_event_init完成后,通过ril_event_set来配置一新ril_event,并通过ril_event_add加入队列之中(实际通常用rilEventAddWakeup来添加),add会把队列里所有ril_event的fd,放入一个fd集合readFds中。这样 ril_event_loop能通过一个多路复用I/O的机制(select)来等待这些fd,如果任何一个fd有数据写入,则进入分析流程processTimeouts(),processReadReadies(&rfds, n),fire Pending()。并且我们可以看到,在进入ril_event_loop之前,已经挂入了一s_wakeupfd_event,通过pipe的机制实现,这个event的目的是可以在一些情况下,能内部唤醒ril_event_loop的多路复用阻塞,比如一些带timeout的命令timeout到期的时候。
start serial port. 通过动态加载动态库的方式执行reference-ril.c(reference-ril.so)中的RIL_Init.
RIL_Init首先通过参数获取硬件接口的设备文件. 接下来便新开一个线程继续初始化, 即mainLoop。
mainLoop的主要任务是建立起与硬件的通信,然后通过read方法阻塞等待硬件的主动上报或响应。在注册一些基础回调(timeout,readerclose)后,mainLoop首先打开硬件设备文件,建立起与硬件的通信,s_device_path和s_port是前面获取的设备路径参数,将其打开(两者可以同时打开并拥有各自的reader,这里也很容易添加双卡双待等支持)。
接下来通过at_open函数建立起这一设备文件上的reader等待循环,这也是通过新建一个线程完成, ret = pthread_create(&s_tid_reader, &attr, readerLoop, &attr),入口点readerLoop。readerLoop 负责监听modem 发送过来的讯息。
extern void RIL_register (const RIL_RadioFunctions *callbacks);
由RIL_Init的返回RIL_RadioFunctions结构的指针。
typedef struct {
int version; /* set to RIL_VERSION */
RIL_RequestFunc onRequest;
RIL_RadioStateRequest onStateRequest;
RIL_Supports supports;
RIL_Cancel onCancel;
RIL_GetVersion getVersion;
} RIL_RadioFunctions;
其中最重要的是onRequest域,上层来的请求都由这个函数进行映射后转换成对应的AT命令发给硬件。rild通过RIL_register注册这一指针。
RIL_register中要完成的另外一个任务,注册registerService,建立HIDL 通信
hardware/ril/rild/rild.c
extern "C" void RIL_register (const RIL_RadioFunctions *callbacks) {
.....
//注册RIL service,从这里开始和socket版本已经不一样。
//跳至下一代码片段
radio::registerService(&s_callbacks, s_commands);
.....
}
这个方法定义在文件 hardware/ril/libril/ril.cpp 中
void radio::registerService(RIL_RadioFunctions *callbacks, CommandInfo *commands) {
//HIDL server端的名字,即 slot1、slot2...,每个卡槽一个 HIDL server端
const char *serviceNames[] = {
android::RIL_getServiceName()
.....
};
....
//为每个卡槽创建且注册一个RadioImpl(HIDL server端)
for (int i = 0; i < simCount; i++) {
//保存在radioService[]数组中
radioService[i] = new RadioImpl;
radioService[i]->mSlotId = i;
//注册 HIDL 服务
android::status_t status = radioService[i]->registerAsService(serviceNames[i]);
}
}
2、reference-ril .c & atchannel.c
hardware/ril/reference-ril 包中的两个主体文件,同时也是Android 实现电话功能的两个主体文件,这个库必须实现的是一个名称为RIL_Init的函数,这个函数执行的结果是返回一个RIL_RadioFunctions结构体的指针,指针指向函数指针。即整个库的入口,这个库在执行的过程中需要创建一个线程来执行实际的功能。在执行的过程中,这个库将打开一个/dev/ttySXXX的终端,然后利用这个终端控制硬件执行。
在rild.c 中使用RIL_Init 获取的RIL_RadioFunctions, 实际为reference_ril.c 中的s_callbacks。
关键的入口方法有:
static void onRequest (int request, void *data, size_t datalen, RIL_Token t); reference-ril 的入口函数。
关键的出口方法有:
1、static void onUnsolicited (const char *s, const char *sms_pdu); 执行URC类型的响应。
2、atchannel.c hardware\ril\reference-ril
static void handleFinalResponse(const char *line); 执行非URC类型的响应,激活s_commandcond 信号,使send_command_xxxx方法返回,从而导致onRequest返回。
/** assumes s_commandmutex is held */
static void handleFinalResponse(const char *line)
{
sp_response->finalResponse = strdup(line);
pthread_cond_signal(&s_commandcond);
}
libril.so动态库
libril.so库的目录是:hardware/ril/libril
其中主要的文件为ril.cpp.
RIL_startEventLoop(void);
void RIL_setcallbacks (const RIL_RadioFunctions *callbacks);
RIL_register (const RIL_RadioFunctions *callbacks);
RIL_onRequestComplete(RIL_Token t, RIL_Errno e, void *response, size_t responselen);
void RIL_onUnsolicitedResponse(int unsolResponse, void *data, size_t datalen);
RIL_requestTimedCallback (RIL_TimedCallback callback, void *param, const struct timeval *relativeTime);
这些函数也是被rild守护进程调用的,不同的vendor可以通过自己的方式实现这几个接口,这样可以保证RIL可以在不同系统的移植。其中 RIL_register()函数把外部的RIL_RadioFunctions结构体注册到这个库之中,在恰当的时候调用相应的函数。在Android 电话功能执行的过程中,这个库处理了一些将请求转换成字符串的功能。
RIL_startEventLoop 将启动整个的Event-loop。
RIL_onRequestComplete 当reference-ril执行onRequest完毕后,将执行,把对应的结果返回给上层。
RIL_onUnsolicitedResponse 当reference-ril 执行URC 类型的响应完毕后,将对应的结果返回给上层。
RIL_requestTimedCallback 注入一个新的timer-event到event-loop中。
五、RILD 流程分析
RILD主要分为四部分main,readerLoop, mainLoop, EventLoop如下图所示:
注:RILD初始化过程主要是创建3个主要的线程,readerLoop, mainLoop, EventLoop.
Android O的版本对RIL的框架的通信功能进行了改动,不在使用sockect进行通讯,而改用HIDL进行通信,这里结合7.0和8.0的源码,分析目前的RIL框架,如有错误还请不吝指正。
RIL的入口
/hardware/ril/rild/rild.c
int main(int argc, char **argv) {
//设置服务名
if (strncmp(clientId, "0", MAX_CLIENT_ID_LENGTH)) {
snprintf(ril_service_name, sizeof(ril_service_name), "%s%s", ril_service_name_base,
clientId);
}
//设置lib库地址
if (rilLibPath == NULL) {
if ( 0 == property_get(LIB_PATH_PROPERTY, libPath, NULL)) {
goto done;
} else {
rilLibPath = libPath;
}
}
//链接lib库
dlHandle = dlopen(rilLibPath, RTLD_NOW);
if (dlHandle == NULL) {
exit(EXIT_FAILURE);
}
//1.开启loop循环
RIL_startEventLoop();
//从链接库中(也就是reference-ril.c)寻找RIL_Init函数地址
rilInit =
(const RIL_RadioFunctions *(*)(const struct RIL_Env *, int, char **))
dlsym(dlHandle, "RIL_Init");
...
//2.调用reference-ril.c中的RIL_Init函数进行初始化INIT,同时得到reference-ril的回调函数
funcs = rilInit(&s_rilEnv, argc, rilArgv);
RLOGD("RIL_Init rilInit completed");
//3.注册得到的reference的回调函数
RIL_register(funcs);
}
主要做的操作:
1.开启loop循环
2.RIL_Init初始化
3.注册得到的reference的回调函数
这里主要对这些初始操作进行对比分析,完整RIL流程见RIL框架分析二
开启loop循环
继续跟踪RIL_startEventLoop
/hardware/ril/libril/ril.cpp
extern "C" void
RIL_startEventLoop(void) {
...
//创建线程并运行eventLoop
int result = pthread_create(&s_tid_dispatch, &attr, eventLoop, NULL);
...
}
继续分析eventLoop函数
static void *
eventLoop(void *param) {
//event初始化
ril_event_init();
//创建event
ril_event_set (&s_wakeupfd_event, s_fdWakeupRead, true,
processWakeupCallback, NULL);
//加入到队列中唤醒
rilEventAddWakeup (&s_wakeupfd_event);
// Only returns on error
//开启event循环
ril_event_loop();
return NULL;
}
一)、继续跟踪event_init函数
/hardware/ril/libril/ril_event.cpp
// Initialize internal data structs
void ril_event_init()
{
MUTEX_INIT();
FD_ZERO(&readFds);
init_list(&timer_list);
init_list(&pending_list);
memset(watch_table, 0, sizeof(watch_table));
}
初始化文件句柄和,两个列表,timer_list和pending_list还有一个watch_table。
追踪其定义的类型看到两个表是ril_event变量,watch_table是一个指针数组
static struct ril_event * watch_table[MAX_FD_EVENTS];
static struct ril_event timer_list;
static struct ril_event pending_list;
分析ril_event的类型
/hardware/ril/libril/ril_event.h
typedef void (*ril_event_cb)(int fd, short events, void *userdata);
//双向链表进行管理,持有句柄文件
struct ril_event {
struct ril_event *next;
struct ril_event *prev;
int fd;
int index;
bool persist;
struct timeval timeout;
ril_event_cb func;
void *param;
};
可以看到其实该类型是双向链表,而timer_list和pending_list还有一个watch_table都是链表
二)、接着跟踪eventLoop循环的具体实现
/hardware/ril/libril/ril_event.cpp
void ril_event_loop()
{
n = select(nfds, &rfds, NULL, NULL, ptv);
//主要循环调用三个方法
for (;;) {
// Check for timeouts
processTimeouts();
// Check for read-ready
processReadReadies(&rfds, n);
// Fire away
firePending();
}
}
处理timer_list列表
static void processTimeouts()
{
//如果timer_list中的事件超时,则从timer_list列表中移除,并添加到pending_list中
while ((tev != &timer_list) && (timercmp(&now, &tev->timeout, >))) {
// Timer expired
dlog("~~~~ firing timer ~~~~");
next = tev->next;
removeFromList(tev);
addToList(tev, &pending_list);
tev = next;
}
}
处理watch_table列表
static void processReadReadies(fd_set * rfds, int n)
{
//添加到pending_list中,设置persist为false后从watch_table中移除
for (int i = 0; (i < MAX_FD_EVENTS) && (n > 0); i++) {
struct ril_event * rev = watch_table[i];
if (rev != NULL && FD_ISSET(rev->fd, rfds)) {
addToList(rev, &pending_list);
if (rev->persist == false) {
removeWatch(rev, i);
}
n--;
}
}
}
处理pengding_list列表,从pending_list中移除,调用ev->func处理事件
static void firePending()
{
struct ril_event * ev = pending_list.next;
while (ev != &pending_list) {
struct ril_event * next = ev->next;
removeFromList(ev);
ev->func(ev->fd, 0, ev->param);
ev = next;
}
}
总结event事件的处理
RIL的Event管理体系中存在3个链表结构:watch_table,timer_list,pending_list
watch(如果驻留的话就每次都处理)和timer(如果时间到了的话就分配进去处理)只是分配,实际最后处理的场所是pending_list,),并使用了一个设备句柄池readFDS,把所有的Socket管道的文件句柄保存起来。
而管理的过程可以归纳为以下6点:
1、可以将一个Event添加到watch_table或者timer_list中;
2、如果Event是添加到watch_table中,需要把当前Event的fd(事件设备句柄)添加到readFDS中;
3、如果Event是添加到timer_list中,不需要把当前Event的fd(事件设备句柄)添加到readFDS中,而且当前Event的fd值是无效的;
4、在循环检测过程中,如果发现watch_table中有Event就会把当前Event添加到pending_list中,如果当前Event的persist属性为false,说明不需要保留当前节点,就把当前的Event从watch_table中删除;如果persist为true,说明需要保留,就不需要从watch_table中删除当前节点。
5、在循环检测过程中,如果发现timer_list中的Event超时时,把当前Event移动到pending_list中,同时删除timer_list中的节点。
6、在循环检测的过程中,等watch_table和timer_list处理完毕后,就去pending_list中执行里面的Event所指向的func。
三)、RIL_Init初始化
通过加载链接库加载reference文件
/hardware/ril/reference-ril/reference-ril.c
const RIL_RadioFunctions *RIL_Init(const struct RIL_Env *env, int argc, char **argv)
{
pthread_attr_init (&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
//开启线程处理mainLoop
ret = pthread_create(&s_tid_mainloop, &attr, mainLoop, NULL);
//把ril的回调函数返回出来
return &s_callbacks;
}
看到开启线程调用mainLoop处理
mainLoop(void *param __unused)
{
//初始化AT通道的关闭方法和超时方法
at_set_on_reader_closed(onATReaderClosed);
at_set_on_timeout(onATTimeout);
for (;;) {
//控制关闭
s_closed = 0;
//注意传入的参数
ret = at_open(fd, onUnsolicited);
RIL_requestTimedCallback(initializeCallback, NULL, &TIMEVAL_0);
waitForClose();
RLOGI("Re-opening after close");
}
}
上面可以看到,不仅打开了AT通道,而且还设置了超时方法。
跟进waitForClose发现当 s_closed=0是会继续等待,搜索s_closed值的更改,发现在两个地方会更改该值为1,即onATTimeout和onATReaderClosed处。
当前线程在打开AT通道后,在waitForClose中阻塞等待,如果AT通道在检测超时后,将会主动的关闭当前的AT通道,此时将会激活waitForClose中的阻塞线程,然后waitForClose将会返回。
而一旦waitForClose函数返回,将会再次进入for循环,重新打开AT通道。
继续跟进AT通道的打开
/hardware/ril/reference-ril/atchannel.c
/**
* Starts AT handler on stream "fd'
* returns 0 on success, -1 on error
*/
int at_open(int fd, ATUnsolHandler h)
{
s_unsolHandler = h;
pthread_attr_init (&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
ret = pthread_create(&s_tid_reader, &attr, readerLoop, &attr);
}
看到开启线程调用readLoop处理
static void *readerLoop(void *arg __unused)
{
for (;;) {
if(isSMSUnsolicited(line)) {
//读取数据
line1 = strdup(line);
line2 = readline();
if (s_unsolHandler != NULL) {
//unsolHandler处理-->处理主动上报的消息,URC消息可以直接发送给RILJ
s_unsolHandler (line1, line2);
}
free(line1);
} else {
//处理主动请求的消息
processLine(line);
}
}
//关闭读
onReaderClosed();
}
可以看到这里主要调用了s_unsolHandler或 processLine 方法处理消息。
四)、继续分析 s_unsolHandler (line1, line2);
查找s_unsolHandler的初始化,在 at_open中对其进行了初始化,也就是reference-ril.c中的 onUnsolicited 。
/hardware/ril/reference-ril/reference-ril.c
static void onUnsolicited (const char *s, const char *sms_pdu)
{
...
if (strStartsWith(s, "%CTZV:")) {
/* TI specific -- NITZ time */
char *response;
line = p = strdup(s);
at_tok_start(&p);
err = at_tok_nextstr(&p, &response);
if (err != 0) {
RLOGE("invalid NITZ line %s\n", s);
} else {
RIL_onUnsolicitedResponse (
RIL_UNSOL_NITZ_TIME_RECEIVED,
response, strlen(response));
}
free(line);
}
...省略多个else if
}
可以看到这里是根据开头的不同进行分别处理,有多种情况,这里仅列出第一种情况
可以看出,URC消息的处理流程基本上就是根据命令头的不同将其转化为不同的命令索引,然后调用 RIL_onUnsolicitedResponse 函数
所以我们继续追溯RIL_onUnsolicitedResponse方法
而RIL_onUnsolicitedResponse的实现:
#define RIL_onUnsolicitedResponse(a,b,c) s_rilenv->OnUnsolicitedResponse(a,b,c)
说明这个函数调用的是s_rilenv变量的OnUnsolicitedResponse方法。那么s_rilenv是哪里初始化的呢?
搜索s_rilenv,可以发现其是在调用RIL_Init方法的时候初始化的
我们在rild.c中的main函数中对reference库初始化时是这样的形式:
funcs = rilInit(&s_rilEnv, argc, rilArgv);
上面的初始化过程将s_rilEnv全局变量传递给了reference,然后在reference-ril.c内部将这个值传给了s_rilenv,而s_rilEnv的各个处理函数是在ril.cpp中实现的。
上面绕了一圈,还是把对消息的处理从动态库(也就是reference-ril.c文件)饶回到了ril.c文件中。
这也正是整个RIL架构的设计理念:框架和处理方式由ril.c管理,差异化的AT命令由reference实现。
所以继续查看ril.c中的具体实现
#if defined(ANDROID_MULTI_SIM)
extern "C"
void RIL_onUnsolicitedResponse(int unsolResponse, const void *data,
size_t datalen)
{
//确保已经注册
if (s_registerCalled == 0) {
// Ignore RIL_onUnsolicitedResponse before RIL_register
RLOGW("RIL_onUnsolicitedResponse called before RIL_register");
return;
}
appendPrintBuf("[UNSL]< %s", requestToString(unsolResponse));
//使用读写锁
pthread_rwlock_t *radioServiceRwlockPtr = radio::getRadioServiceRwlock((int) soc_id);
int rwlockRet = pthread_rwlock_rdlock(radioServiceRwlockPtr);
assert(rwlockRet == 0);
//调用responseFunction,注意soc_id
ret = s_unsolResponses[unsolResponseIndex].responseFunction(
(int) soc_id, responseType, 0, RIL_E_SUCCESS, const_cast<void*>(data),
datalen);
rwlockRet = pthread_rwlock_unlock(radioServiceRwlockPtr);
assert(rwlockRet == 0);
//android7.0 上此函数主要操作有两步,1是对返回数据进行打包到p中,2调用send发送
//ret = sendResponse(p,id);-->使用socket将打包的p数据发送
}
点关注s_unsolResponses的跟进
static UnsolResponseInfo s_unsolResponses[] = {
#include "ril_unsol_commands.h"
};
/hardware/ril/libril/ril_unsol_commands.h
{RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED, radio::radioStateChangedInd, WAKE_PARTIAL},
{RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED, radio::callStateChangedInd, WAKE_PARTIAL},
{RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED, radio::networkStateChangedInd, WAKE_PARTIAL},
{RIL_UNSOL_RESPONSE_NEW_SMS, radio::newSmsInd, WAKE_PARTIAL},
{RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT, radio::newSmsStatusReportInd, WAKE_PARTIAL},
{RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM, radio::newSmsOnSimInd, WAKE_PARTIAL},
{RIL_UNSOL_ON_USSD, radio::onUssdInd, WAKE_PARTIAL},
{RIL_UNSOL_ON_USSD_REQUEST, radio::onUssdInd, DONT_WAKE},
可以看到s_unsolResponses[unsolResponseIndex].responseFunction其实调用的就是radio::callStateChangedInd方法。
如果对比android N的ril_unsol_commands定义,发现其处理的方法发生了变化。
在原有N的代码上,ril_unsol_commands中的response方法实际上是由ril.cpp中进行了重新实现,而ril_unsol_commands.h仅定义处理方法而已。
那么我们继续在O的代码上进行跟踪radio::callStateChangedInd,可以发现其在ril_service.cpp中进行了实现
xref: /hardware/ril/libril/ril_service.cpp
int radio::callStateChangedInd(int slotId,
int indicationType, int token, RIL_Errno e, void *response,
size_t responseLen) {
if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
#if VDBG
RLOGD("callStateChangedInd");
#endif
Return<void> retStatus = radioService[slotId]->mRadioIndication->callStateChanged(
convertIntToRadioIndicationType(indicationType));
radioService[slotId]->checkReturnStatus(retStatus);
} else {
RLOGE("callStateChangedInd: radioService[%d]->mRadioIndication == NULL", slotId);
}
return 0;
}
继续跟进radioService[slotId]->mRadioIndication->callStateChanged方法
发现这里其实调用的就是mRadioIndication的方法,这里就和之前的Android8.0 MT流程一中的一样了。
跟踪 RadioIndication 类
public class RadioIndication extends IRadioIndication.Stub
我们继续看看其继承的 IRadioIndication.Stub,全局搜索 RadioIndication 可以发现其在 IRadioIndication.hal中定义了此接口。
注意RadioIndication类,发现其定义了大量类似callStateChanged的方法,再对比7.0上的processUnsolicited方法,发现本是通过一个方法统一管理的底层回复现在交由RadioIndication类处理,其callStateChanged对应与之前processUnsolicited方法中的switch-case的callStateChanged一项,其他的以此类推。
RIL通信的7.0和8.0差别变化比较大的一个地方。之后RIL层在接收到底层的消息后,会发起notify通知。
相比N的结构,其是先调用一个方法对回复的数据进行打包,之后使用socket进行发送,而O上则是直接调用一个方法对回复数据进行处理,通过RadioIndication进行HIDL调用,就直接到了RIL处。
五)、继续分析processLine方法的处理
static void processLine(const char *line)
{
pthread_mutex_lock(&s_commandmutex);
if (sp_response == NULL) {
/* no command pending */
handleUnsolicited(line);
//判断是否已经把所有有效数据传输完毕
} else if (isFinalResponseSuccess(line)) {
sp_response->success = 1;
//回复消息给上层
handleFinalResponse(line);
} else if (isFinalResponseError(line)) {
sp_response->success = 0;
handleFinalResponse(line);
} else if (s_smsPDU != NULL && 0 == strcmp(line, "> ")) {
// See eg. TS 27.005 4.3
// Commands like AT+CMGS have a "> " prompt
writeCtrlZ(s_smsPDU);
s_smsPDU = NULL;
} else switch (s_type) {
case NO_RESULT:
handleUnsolicited(line);
break;
case NUMERIC:
if (sp_response->p_intermediates == NULL
&& isdigit(line[0])
) {
addIntermediate(line);
} else {
/* either we already have an intermediate response or
the line doesn't begin with a digit */
handleUnsolicited(line);
}
break;
case SINGLELINE:
if (sp_response->p_intermediates == NULL
&& strStartsWith (line, s_responsePrefix)
) {
//将数据放到反馈数据中
addIntermediate(line);
} else {
/* we already have an intermediate response */
handleUnsolicited(line);
}
break;
case MULTILINE:
if (strStartsWith (line, s_responsePrefix)) {
addIntermediate(line);
} else {
handleUnsolicited(line);
}
break;
default: /* this should never be reached */
RLOGE("Unsupported AT command type %d\n", s_type);
handleUnsolicited(line);
break;
}
pthread_mutex_unlock(&s_commandmutex);
}
非URC消息通常有多行,处理到最后结束的时候会调用到handleFinalResponse 继续跟进
/** assumes s_commandmutex is held */
static void handleFinalResponse(const char *line)
{
//把回应消息返回给eventLoop
sp_response->finalResponse = strdup(line);
//发信号给s_commandcond线程,使其脱离阻塞状态
pthread_cond_signal(&s_commandcond);
}
注册得到的reference的回调函数
继续跟进RIL_register(funcs);追踪RIL.C中的注册方法,发现8.0已经做了变动,是通过注册服务来进行通信,之前是通过socket进行通信
extern "C" void
RIL_register (const RIL_RadioFunctions *callbacks) {
...
memcpy(&s_callbacks, callbacks, sizeof (RIL_RadioFunctions));
s_registerCalled = 1;
RLOGI("s_registerCalled flag set, %d", s_started);
// Little self-check
for (int i = 0; i < (int)NUM_ELEMS(s_commands); i++) {
assert(i == s_commands[i].requestNumber);
}
for (int i = 0; i < (int)NUM_ELEMS(s_unsolResponses); i++) {
assert(i + RIL_UNSOL_RESPONSE_BASE
== s_unsolResponses[i].requestNumber);
}
//通过注册服务获取
radio::registerService(&s_callbacks, s_commands);
RLOGI("RILHIDL called registerService");
}
继续跟进
//注册ril_service服务
xref: /hardware/ril/libril/ril_service.cpp
void radio::registerService(RIL_RadioFunctions *callbacks, CommandInfo *commands) {
using namespace android::hardware;
int simCount = 1;
const char *serviceNames[] = {
android::RIL_getServiceName()
#if (SIM_COUNT >= 2)
, RIL2_SERVICE_NAME
#if (SIM_COUNT >= 3)
, RIL3_SERVICE_NAME
#if (SIM_COUNT >= 4)
, RIL4_SERVICE_NAME
#endif
#endif
#endif
};
#if (SIM_COUNT >= 2)
simCount = SIM_COUNT;
#endif
configureRpcThreadpool(1, true /* callerWillJoin */);
for (int i = 0; i < simCount; i++) {
pthread_rwlock_t *radioServiceRwlockPtr = getRadioServiceRwlock(i);
int ret = pthread_rwlock_wrlock(radioServiceRwlockPtr);
assert(ret == 0);
radioService[i] = new RadioImpl;
radioService[i]->mSlotId = i;
oemHookService[i] = new OemHookImpl;
oemHookService[i]->mSlotId = i;
RLOGD("registerService: starting IRadio %s", serviceNames[i]);
android::status_t status = radioService[i]->registerAsService(serviceNames[i]);
status = oemHookService[i]->registerAsService(serviceNames[i]);
ret = pthread_rwlock_unlock(radioServiceRwlockPtr);
assert(ret == 0);
}
s_vendorFunctions = callbacks;
s_commands = commands;
}
注册服务的时候传入 callbacks,
#if defined(ANDROID_MULTI_SIM)
#define CALL_ONREQUEST(a, b, c, d, e) \
s_vendorFunctions->onRequest((a), (b), (c), (d), ((RIL_SOCKET_ID)(e)))
#define CALL_ONSTATEREQUEST(a) s_vendorFunctions->onStateRequest((RIL_SOCKET_ID)(a))
#else
#define CALL_ONREQUEST(a, b, c, d, e) s_vendorFunctions->onRequest((a), (b), (c), (d))
#define CALL_ONSTATEREQUEST(a) s_vendorFunctions->onStateRequest()
#endif
int radio::radioStateChangedInd(int slotId,
int indicationType, int token, RIL_Errno e, void *response,
size_t responseLen) {
if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
//这里其实调用的是callbacks的方法
RadioState radioState =
(RadioState) CALL_ONSTATEREQUEST(slotId);
RLOGD("radioStateChangedInd: radioState %d", radioState);
Return<void> retStatus = radioService[slotId]->mRadioIndication->radioStateChanged(
convertIntToRadioIndicationType(indicationType), radioState);
radioService[slotId]->checkReturnStatus(retStatus);
} else {
RLOGE("radioStateChangedInd: radioService[%d]->mRadioIndication == NULL", slotId);
}
return 0;
}
这里和之前分析的一样,使得ril_service.cpp实际调用也归ril.c管理
这里大致分析了RIL中两个比较关键的地方,更为完整的RIL处理流程见下篇分析。
1.eventLoop循环的构建,readLoop循环的构建。如何确保框架和处理方式由ril.c及command.h管理。
2.在O上由于通信方式的更改,对ril.java和ril.cpp进行了拆分,增加了ril_service.cpp和RadioIndication相关类及HIDL。
六、上面介绍了rild的流程,接下来我们一起分析 ril-java和modem关系
一)、去电流程三中跟踪到最后的时候可以看到其调用了RIL的dail方法
这里继续以此分析其从RIL到Modem的流程
RIL.java frameworks\opt\telephony\src\java\com\android\internal\telephony
@Override
public void dial(String address, int clirMode, UUSInfo uusInfo, Message result) {
//获取radio对象
IRadio radioProxy = getRadioProxy(result);
if (radioProxy != null) {
//构建RIL请求消息
RILRequest rr = obtainRequest(RIL_REQUEST_DIAL, result,
mRILDefaultWorkSource);
Dial dialInfo = new Dial();
dialInfo.address = convertNullToEmptyString(address);
dialInfo.clir = clirMode;
if (uusInfo != null) {
UusInfo info = new UusInfo();
info.uusType = uusInfo.getType();
info.uusDcs = uusInfo.getDcs();
info.uusData = new String(uusInfo.getUserData());
dialInfo.uusInfo.add(info);
}
if (RILJ_LOGD) {
// Do not log function arg for privacy
riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
}
try {
//调用dial方法
radioProxy.dial(rr.mSerial, dialInfo);
} catch (RemoteException | RuntimeException e) {
handleRadioProxyExceptionForRR(rr, "dial", e);
}
}
}
1、使用单例模式通过获取Radio对象,可以看到其获取的是HIDL的对象,并且设置的回复方法mRadioResponse,可以参见RIL架构分析。
RIL.java frameworks\opt\telephony\src\java\com\android\internal\telephony
protected IRadio getRadioProxy(Message result) {
...
try {
//获取HIDL的服务并设置setResponseFunctions
mRadioProxy = IRadio.getService(HIDL_SERVICE_NAME[mPhoneId == null ? 0 : mPhoneId]);
if (mRadioProxy != null) {
mRadioProxy.linkToDeath(mRadioProxyDeathRecipient,
mRadioProxyCookie.incrementAndGet());
//设置mRadioResponse和mRadioIndication
mRadioProxy.setResponseFunctions(mRadioResponse, mRadioIndication);
} else {
riljLoge("getRadioProxy: mRadioProxy == null");
}
} catch (RemoteException | RuntimeException e) {
mRadioProxy = null;
riljLoge("RadioProxy getService/setResponseFunctions: " + e);
}
...
}
可以看到其通过HIDL方式获取到Radio对象后,进一步调用此对象的dial方法
继续查找远端的Radio类
发现RadioImpl继承了IRadio
ril_service.cpp hardware\ril\libril
struct RadioImpl : public V1_1::IRadio
2、在 ril_service 中实现了dial方法,继续跟进此方法
Return<void> RadioImpl::dial(int32_t serial, const Dial& dialInfo) {
#if VDBG
RLOGD("dial: serial %d", serial);
#endif
//构建请求对象,Event侧和reference测协定的统一格式,当从event测发送到reference测时需要标准化为此对象
RequestInfo *pRI = android::addRequestToList(serial, mSlotId, RIL_REQUEST_DIAL);
if (pRI == NULL) {
return Void();
}
RIL_Dial dial = {};
RIL_UUS_Info uusInfo = {};
int32_t sizeOfDial = sizeof(dial);
if (!copyHidlStringToRil(&dial.address, dialInfo.address, pRI)) {
return Void();
}
dial.clir = (int) dialInfo.clir;
if (dialInfo.uusInfo.size() != 0) {
uusInfo.uusType = (RIL_UUS_Type) dialInfo.uusInfo[0].uusType;
uusInfo.uusDcs = (RIL_UUS_DCS) dialInfo.uusInfo[0].uusDcs;
if (dialInfo.uusInfo[0].uusData.size() == 0) {
uusInfo.uusData = NULL;
uusInfo.uusLength = 0;
} else {
if (!copyHidlStringToRil(&uusInfo.uusData, dialInfo.uusInfo[0].uusData, pRI)) {
memsetAndFreeStrings(1, dial.address);
return Void();
}
uusInfo.uusLength = dialInfo.uusInfo[0].uusData.size();
}
dial.uusInfo = &uusInfo;
}
//
CALL_ONREQUEST(RIL_REQUEST_DIAL, &dial, sizeOfDial, pRI, mSlotId);
memsetAndFreeStrings(2, dial.address, uusInfo.uusData);
return Void();
}
疑问点:为何没有进入EventLoop循环????
在Android7.0上是通过Select获取Socke发送过来的消息,然后通过EventLoop进行处理,最后调用到processCommandsCallback之后进行处理。和同事沟通后HIDL发送消息也会被Select获取到,之后一路调用到ev->func(ev->fd, 0, ev->param); ,但在8.0上没有processCommandsCallback处理,这里笔者也未追溯到其如何进一步处理,后续会进一步进行分析。但从现有源码来看其是调用到了RadioImpl的dial方法进行处理。
3.继续跟踪CALL_ONREQUEST
搜索CALL_ONREQUEST,可以看到其实际调用的是s_vendorFunctions->onRequest
#define CALL_ONREQUEST(a, b, c, d, e) s_vendorFunctions->onRequest((a), (b), ©, (d))
在registerService方法中看到s_vendorFunctions其实是传进来的callbacks实例,即RIL_RadioFunctions对象,这里具体分析可以见Android 8.0RIL框架分析。
在ril.c中继续跟踪OnRequest方法,回到之前rild.c的main中,我们看到其先调用rilInit进行初始化,之后返回了funcs,在传如RIL_register进行注册
跟进到reference-ril.c的 onRequest 方法
reference-ril.c hardware\ril\reference-ril
static void
onRequest (int request, void *data, size_t datalen, RIL_Token t)
{
ATResponse *p_response;
int err;
RLOGD("onRequest: %s", requestToString(request));
/* Ignore all requests except RIL_REQUEST_GET_SIM_STATUS
* when RADIO_STATE_UNAVAILABLE.
*/
if (sState == RADIO_STATE_UNAVAILABLE
&& request != RIL_REQUEST_GET_SIM_STATUS
) {
RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
return;
}
/* Ignore all non-power requests when RADIO_STATE_OFF
* (except RIL_REQUEST_GET_SIM_STATUS)
*/
if (sState == RADIO_STATE_OFF
&& !(request == RIL_REQUEST_RADIO_POWER
|| request == RIL_REQUEST_GET_SIM_STATUS)
) {
RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
return;
}
//可以看到只有两种情况是单独处理的,其他的在switch中处理
switch (request) {
...
case RIL_REQUEST_DIAL:
requestDial(data, datalen, t);
break;
...
}
}
4.继续跟进requestDial方法
reference-ril.c hardware\ril\reference-ril
static void requestDial(void *data, size_t datalen __unused, RIL_Token t)
{
RIL_Dial *p_dial;
char *cmd;
const char *clir;
int ret;
p_dial = (RIL_Dial *)data;
switch (p_dial->clir) {
case 1: clir = "I"; break; /*invocation*/
case 2: clir = "i"; break; /*suppression*/
default:
case 0: clir = ""; break; /*subscription default*/
}
asprintf(&cmd, "ATD%s%s;", p_dial->address, clir);
//发送AT命令
ret = at_send_command(cmd, NULL);
free(cmd);
/* success or failure is ignored by the upper layer here.
it will call GET_CURRENT_CALLS and determine success that way */
//结束时调用
RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
}
5.继续跟踪at_send_command
atchannel.c hardware\ril\reference-ril
int at_send_command (const char *command, ATResponse **pp_outResponse)
{
int err;
err = at_send_command_full (command, NO_RESULT, NULL,
NULL, 0, pp_outResponse);
return err;
}
6.继续跟进at_send_command_full
atchannel.c hardware\ril\reference-ril
/**
* Internal send_command implementation
*
* timeoutMsec == 0 means infinite timeout
*/
static int at_send_command_full (const char *command, ATCommandType type,
const char *responsePrefix, const char *smspdu,
long long timeoutMsec, ATResponse **pp_outResponse)
{
int err;
bool inEmulator;
if (0 != pthread_equal(s_tid_reader, pthread_self())) {
/* cannot be called from reader thread */
return AT_ERROR_INVALID_THREAD;
}
inEmulator = isInEmulator();
if (inEmulator) {
pthread_mutex_lock(&s_writeMutex);
}
pthread_mutex_lock(&s_commandmutex);
//继续发送
err = at_send_command_full_nolock(command, type,
responsePrefix, smspdu,
timeoutMsec, pp_outResponse);
pthread_mutex_unlock(&s_commandmutex);
if (inEmulator) {
pthread_mutex_unlock(&s_writeMutex);
}
if (err == AT_ERROR_TIMEOUT && s_onTimeout != NULL) {
s_onTimeout();
}
return err;
}
7.继续跟进at_send_command_full_nolock
static int at_send_command_full_nolock (const char *command, ATCommandType type,
const char *responsePrefix, const char *smspdu,
long long timeoutMsec, ATResponse **pp_outResponse)
{
int err = 0;
struct timespec ts;
if(sp_response != NULL) {
err = AT_ERROR_COMMAND_PENDING;
goto error;
}
//给modem发送AT消息
err = writeline (command);
if (err < 0) {
goto error;
}
s_type = type;
s_responsePrefix = responsePrefix;
s_smsPDU = smspdu;
//创建sp_respose作为回应
sp_response = at_response_new();
if (timeoutMsec != 0) {
setTimespecRelative(&ts, timeoutMsec);
}
//发送完后阻塞线程
while (sp_response->finalResponse == NULL && s_readerClosed == 0) {
if (timeoutMsec != 0) {
//进入阻塞状态,待另一个线程满足s_commandcond后解除
err = pthread_cond_timedwait(&s_commandcond, &s_commandmutex, &ts);
} else {
err = pthread_cond_wait(&s_commandcond, &s_commandmutex);
}
//超时结束
if (err == ETIMEDOUT) {
err = AT_ERROR_TIMEOUT;
goto error;
}
}
if (pp_outResponse == NULL) {
at_response_free(sp_response);
} else {
/* line reader stores intermediate responses in reverse order */
reverseIntermediates(sp_response);
//将回应发给请求的线程
*pp_outResponse = sp_response;
}
sp_response = NULL;
if(s_readerClosed > 0) {
err = AT_ERROR_CHANNEL_CLOSED;
goto error;
}
err = 0;
error:
clearPendingCommand();
return err;
}
可以看到这里做了两个重要的操作:
1.通过writeLine发送数据给modem
2.阻塞当前线程等待modem回应
8.这样数据就发送到了modem了
static int writeline (const char *s)
{
size_t cur = 0;
size_t len = strlen(s);
ssize_t written;
if (s_fd < 0 || s_readerClosed > 0) {
return AT_ERROR_CHANNEL_CLOSED;
}
//AT命令的打印
RLOGD("AT> %s\n", s);
AT_DUMP( ">> ", s, strlen(s) );
/* the main string */
while (cur < len) {
do {
s_fd是modem和rilc的串口
written = write (s_fd, s + cur, len - cur);
} while (written < 0 && errno == EINTR);
if (written < 0) {
return AT_ERROR_GENERIC;
}
cur += written;
}
/* the \r */
//以r结尾
do {
written = write (s_fd, "\r" , 1);
} while ((written < 0 && errno == EINTR) || (written == 0));
if (written < 0) {
return AT_ERROR_GENERIC;
}
return 0;
}
二)、从modem往上层返回消息
非URC消息处理
之前分析到在at_send_command_full_nolock调用后会先发送消息给modem,然后阻塞当前线程等待modem返回消息。
因此也是在readerLoop的消息处理中去唤醒阻塞的线程,而且应该把数据直接返回给阻塞的线程,如之前ndroid 8.0 RIL框架分析,非URC消息会调用processLine方法。
1.这里跟进到processLine方法
atchannel.c hardware\ril\reference-ril
static void processLine(const char *line)
{
pthread_mutex_lock(&s_commandmutex);
if (sp_response == NULL) {
/* no command pending */
handleUnsolicited(line);
} else if (isFinalResponseSuccess(line)) {
sp_response->success = 1;
//将消息发回给eventLoop
handleFinalResponse(line);
} else if (isFinalResponseError(line)) {
sp_response->success = 0;
handleFinalResponse(line);
} else if (s_smsPDU != NULL && 0 == strcmp(line, "> ")) {
// See eg. TS 27.005 4.3
// Commands like AT+CMGS have a "> " prompt
writeCtrlZ(s_smsPDU);
s_smsPDU = NULL;
} else switch (s_type) {
case NO_RESULT:
handleUnsolicited(line);
break;
case NUMERIC:
if (sp_response->p_intermediates == NULL
&& isdigit(line[0])
) {
addIntermediate(line);
} else {
/* either we already have an intermediate response or
the line doesn't begin with a digit */
handleUnsolicited(line);
}
break;
case SINGLELINE:
if (sp_response->p_intermediates == NULL
&& strStartsWith (line, s_responsePrefix)
) {
addIntermediate(line);
} else {
/* we already have an intermediate response */
handleUnsolicited(line);
}
break;
case MULTILINE:
if (strStartsWith (line, s_responsePrefix)) {
addIntermediate(line);
} else {
handleUnsolicited(line);
}
break;
default: /* this should never be reached */
RLOGE("Unsupported AT command type %d\n", s_type);
handleUnsolicited(line);
break;
}
pthread_mutex_unlock(&s_commandmutex);
}
2.继续跟进handleFinalResponse
/** assumes s_commandmutex is held */
static void handleFinalResponse(const char *line)
{
//把回应消息返回给RIL
sp_response->finalResponse = strdup(line);
//唤醒阻塞线程
pthread_cond_signal(&s_commandcond);
}
3.回到at_send_command_full_nolock
if (pp_outResponse == NULL) {
at_response_free(sp_response);
} else {
/* line reader stores intermediate responses in reverse order */
reverseIntermediates(sp_response);
//返回的数据
*pp_outResponse = sp_response;
}
4.回到最开始的 requestDial,在获取到返回数据后会调用RIL_onRequestComplete
reference-ril.c hardware\ril\reference-ril
static void requestDial(void *data, size_t datalen __unused, RIL_Token t)
{
RIL_Dial *p_dial;
char *cmd;
const char *clir;
int ret;
p_dial = (RIL_Dial *)data;
switch (p_dial->clir) {
case 1: clir = "I"; break; /*invocation*/
case 2: clir = "i"; break; /*suppression*/
default:
case 0: clir = ""; break; /*subscription default*/
}
asprintf(&cmd, "ATD%s%s;", p_dial->address, clir);
ret = at_send_command(cmd, NULL);
free(cmd);
/* success or failure is ignored by the upper layer here.
it will call GET_CURRENT_CALLS and determine success that way */
RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
}
5.这就回到ril.c的onRequestComplete中
extern "C" void
RIL_onRequestComplete(RIL_Token t, RIL_Errno e, void *response, size_t responselen) {
RequestInfo *pRI;
int ret;
RIL_SOCKET_ID socket_id = RIL_SOCKET_1;
pRI = (RequestInfo *)t;
if (!checkAndDequeueRequestInfoIfAck(pRI, false)) {
RLOGE ("RIL_onRequestComplete: invalid RIL_Token");
return;
}
socket_id = pRI->socket_id;
#if VDBG
RLOGD("RequestComplete, %s", rilSocketIdToString(socket_id));
#endif
if (pRI->local > 0) {
// Locally issued command...void only!
// response does not go back up the command socket
RLOGD("C[locl]< %s", requestToString(pRI->pCI->requestNumber));
free(pRI);
return;
}
appendPrintBuf("[%04d]< %s",
pRI->token, requestToString(pRI->pCI->requestNumber));
if (pRI->cancelled == 0) {
int responseType;
if (s_callbacks.version >= 13 && pRI->wasAckSent == 1) {
// If ack was already sent, then this call is an asynchronous response. So we need to
// send id indicating that we expect an ack from RIL.java as we acquire wakelock here.
responseType = RESPONSE_SOLICITED_ACK_EXP;
grabPartialWakeLock();
} else {
responseType = RESPONSE_SOLICITED;
}
// there is a response payload, no matter success or not.
#if VDBG
RLOGE ("Calling responseFunction() for token %d", pRI->token);
#endif
pthread_rwlock_t *radioServiceRwlockPtr = radio::getRadioServiceRwlock((int) socket_id);
int rwlockRet = pthread_rwlock_rdlock(radioServiceRwlockPtr);
assert(rwlockRet == 0);
//调用返回的响应方法
ret = pRI->pCI->responseFunction((int) socket_id,
responseType, pRI->token, e, response, responselen);
rwlockRet = pthread_rwlock_unlock(radioServiceRwlockPtr);
assert(rwlockRet == 0);
}
free(pRI);
}
5.跟进到RadioResponse
RadioResponse.java frameworks\opt\telephony\src\java\com\android\internal\telephony
public class RadioResponse extends IRadioResponse.Stub {
/**
* @param responseInfo Response info struct containing response type, serial no. and error
*/
public void dialResponse(RadioResponseInfo responseInfo) {
responseVoid(responseInfo);
}
6.继续跟进responseVoid
public void responseVoid(RadioResponseInfo responseInfo) {
//创建rilRequest反馈对象
RILRequest rr = mRil.processResponse(responseInfo);
if (rr != null) {
Object ret = null;
if (responseInfo.error == RadioError.NONE) {
//modem处理成功
sendMessageResponse(rr.mResult, ret);
}
mRil.processResponseDone(rr, responseInfo, ret);
}
}
7.将消息发送回请求的地方
public static void sendMessageResponse(Message msg, Object ret) {
if (msg != null) {
AsyncResult.forMessage(msg, ret, null);
msg.sendToTarget();
}
}
三)、URC消息处理
1.之前分析过如果是底层主动上报的URC消息则是使用handleUnsolicited进行处理
static void handleUnsolicited(const char *line)
{
if (s_unsolHandler != NULL) {
s_unsolHandler(line, NULL);
}
}
可以看到s_unsolHandler是个静态变量
static ATUnsolHandler s_unsolHandler;
查找s_unsolHandler的初始化
int at_open(int fd, ATUnsolHandler h)
{
...
s_unsolHandler = h;
...
}
可以看到是在at_open的时候传入的handler,继续往上追溯mainLoop
static void *
mainLoop(void *param __unused)
{
...
ret = at_open(fd, onUnsolicited);
...
}
2.可以看到其实调用的是reference-ril.c中的onUnsolicited方法
/**
* Called by atchannel when an unsolicited line appears
* This is called on atchannel's reader thread. AT commands may
* not be issued here
*/
static void onUnsolicited (const char *s, const char *sms_pdu)
{
...
if (strStartsWith(s, "%CTZV:")) {
/* TI specific -- NITZ time */
char *response;
line = p = strdup(s);
at_tok_start(&p);
err = at_tok_nextstr(&p, &response);
if (err != 0) {
RLOGE("invalid NITZ line %s\n", s);
} else {
RIL_onUnsolicitedResponse (
RIL_UNSOL_NITZ_TIME_RECEIVED,
response, strlen(response));
}
free(line);
}
// ...省略多个else if
}
可以看到其最后调用RIL_onUnsolicitedResponse进行处理
#define RIL_onRequestComplete(t, e, response, responselen) s_rilenv->OnRequestComplete(t,e, response, responselen)
#define RIL_onUnsolicitedResponse(a,b,c) s_rilenv->OnUnsolicitedResponse(a,b,c)
3.继续跟进RIL_onUnsolicitedResponse
extern "C"
void RIL_onUnsolicitedResponse(int unsolResponse, const void *data,
size_t datalen)
{
...
ret = s_unsolResponses[unsolResponseIndex].responseFunction(
(int) soc_id, responseType, 0, RIL_E_SUCCESS, const_cast<void*>(data),
datalen);
...
}
查看UnsolResponseInfo结构
typedef struct {
int requestNumber;
int (*responseFunction) (int slotId, int responseType, int token,
RIL_Errno e, void *response, size_t responselen);
WakeType wakeType;
} UnsolResponseInfo;
查找UnsolResponseInfo 的初始化
static UnsolResponseInfo s_unsolResponses[] = {
#include "ril_unsol_commands.h"
};
可以看到这个头文件的定义和N上已经发生了改变
{RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED, radio::callStateChangedInd, WAKE_PARTIAL},
4.跟进对应的callStateChangedInd响应方法
ril-service.cpp
int radio::callStateChangedInd(int slotId,
int indicationType, int token, RIL_Errno e, void *response,
size_t responseLen) {
if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
#if VDBG
RLOGD("callStateChangedInd");
#endif
Return<void> retStatus = radioService[slotId]->mRadioIndication->callStateChanged(
convertIntToRadioIndicationType(indicationType));
radioService[slotId]->checkReturnStatus(retStatus);
} else {
RLOGE("callStateChangedInd: radioService[%d]->mRadioIndication == NULL", slotId);
}
return 0;
}
5.可以看到其又通过HIDL调用到RILJ处的方法
frameworks\opt\telephony\src\java\com\android\internal\telephony\RadioIndication.java
public void callStateChanged(int indicationType) {
mRil.processIndication(indicationType);
if (RIL.RILJ_LOGD) mRil.unsljLog(RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED);
//继续通知消息
mRil.mCallStateRegistrants.notifyRegistrants();
}