下面看第二个关键函数RIL_Init。这个函数必须由动态库实现,对于下面这个例子来说,它将由RefRil库实现,这个函数定义在Reference_ril.c中:
**Reference_ril.c**
~~~
pthread_t s_tid_mainloop;//看来又会创建一个线程
//动态库必须实现的RIL_Init函数。
const RIL_RadioFunctions *RIL_Init(const structRIL_Env *env,
int argc, char **argv)
{
intret;
int fd= -1;
intopt;
pthread_attr_t attr;
s_rilenv = env; //将外部传入的env保存为s_rilenv。
......//一些参数处理,不必管它
pthread_attr_init (&attr);
pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
//创建一个工作线程mainLoop
ret =pthread_create(&s_tid_mainloop, &attr, mainLoop, NULL);
/*
s_callbacks也为一个结构体
staticconst RIL_RadioFunctions s_callbacks = {
RIL_VERSION, //RIL的版本
onRequest, //下面是一些函数指针
currentState,
onSupports,
onCancel,
getVersion
};
*/
return&s_callbacks;
}
~~~
RefRil的RIL_Init函数比较简单,主要有三项工作要做:
- 保存Rild传入的RIL_Env结构体。
- 创建一个叫mainLoop的工作线程。
- 返回一个RIL_RadioFunctions的结构体。
上面的RIL_Env和RIL_RadioFunctions结构体,就是Rild架构中用来隔离通用代码和厂商相关代码的接口。先来看RIL_RadioFunctions,这个结构体由厂商的动态库实现,它的代码如下:
~~~
//函数指针定义
typedef void (*RIL_RequestFunc) (int request,void *data,
size_tdatalen, RIL_Token t);
typedef RIL_RadioState(*RIL_RadioStateRequest)();
typedef int (*RIL_Supports)(int requestCode);
typedef void (*RIL_Cancel)(RIL_Token t);
typedef void (*RIL_TimedCallback) (void *param);
typedef const char * (*RIL_GetVersion) (void);
typedef struct {
intversion; //RIL的版本
//通过这个接口可向BP提交一个请求,注意这个函数的返回值为空,这是为什么?
RIL_RequestFunc onRequest;
RIL_RadioStateRequest onStateRequest;//查询BP的状态
RIL_Supports supports;
RIL_CancelonCancel;
//查询动态库的版本,RefRil库中该函数的实现将返回字符串”android reference-ril 1.0”
RIL_GetVersion getVersion;
} RIL_RadioFunctions;
~~~
对于上面的结构体,应重点关注函数onRequest,它被Rild用来向动态库提交一个请求,也就是说,AP向BP发送请求的接口就是它,但是这个函数却没有返回值,那么该请求的执行结果是怎么得到的呢?
这里不卖关子,直接告诉大家。Rild架构中最大的特点就是采用了异步请求/处理的方式。这种方式和异步I/O有异曲同工之妙。那么什么是异步请求/处理呢?它的执行流程如下:
- Rild通过onRequest向动态库提交一个请求,然后返回去做自己的事情。
- 动态库处理这个请求,请求的处理结果通过回调接口通知。
这种异步请求/处理的流程和酒店的MorningCall服务很类似,具体相似之处如下所示:
- 在前台预约了一个Morning Call,这好比向酒店提交了一个请求。预约完后,就可以放心地做自己的事情了。
- 酒店登记了这个请求,记录是哪个房间申请的服务,然后由酒店安排工作人员值班,这些都是酒店对这个请求的处理,作为房客则无须知道处理细节。
- 第二天早上,约好的时间一到,酒店给房客打电话,房客就知道这个请求被处理了。为了检查一下宾馆服务的效果,最好是拿表看看接到电话的时间是不是之前预约的时间。
这时,读者对异步请求/处理机制或许有了一些直观的感受。那么,动态库是如何通知请求的处理结果的呢?这里用到了另外一个接口RIL_Env结构,它的定义如下所示:
**Ril.h**
~~~
struct RIL_Env {
//动态库完成一个请求后,通过下面这个函数通知处理结果,其中第一个参数标明是哪个请求
//的处理结果
void(*OnRequestComplete)(RIL_Token t, RIL_Errno e,
void *response,size_t responselen);
//动态库用于进行unsolicited Response通知的函数
void(*OnUnsolicitedResponse)(int unsolResponse, const void *data,
size_t datalen);
//给Rild提交一个超时任务
void*(*RequestTimedCallback) (RIL_TimedCallback callback,
void *param,const struct timeval *relativeTime);
//从Rild的超时任务队列中移除一个任务
void(*RemoveTimedCallback) (void *callbackInfo);
};
~~~
结合图9-7和上面的分析可以发现,Rild在设计时将请求的应答接口和动态库的通知接口都放在了RIL_Env结构体中。
关于Rild和动态库的交互接口就分析到这里。相信读者已经明白其中的原理了。下面来看RefRil库创建的工作线程mainLoop。
1. 工作线程mainLoop的分析
RefRil库的RIL_Init函数会创建一个工作线程mainLoop,其代码如下所示:
**Reference_Ril.c**
~~~
static void *
mainLoop(void *param)
{
intfd;
intret;
......
/*
为AT模块设置一些回调函数,AT模块用来和BP交互,对于RefRil库来说,AT模块就是对
串口设备通信的封装,这里统称为AT模块。
*/
at_set_on_reader_closed(onATReaderClosed);
at_set_on_timeout(onATTimeout);
for(;;) {
fd= -1;
//下面这个while循环的目的是为了得到串口设备的文件描述符,我们省略其中的一些内容
while (fd < 0) {
if (s_port > 0) {
fd = socket_loopback_client(s_port, SOCK_STREAM);
} else if (s_device_socket) {
if (!strcmp(s_device_path, "/dev/socket/qemud")) {
......
} else if (s_device_path != NULL) {
fd = open (s_device_path, O_RDWR);
if ( fd >= 0 && !memcmp( s_device_path,"/dev/ttyS", 9 ) ) {
struct termios ios;
tcgetattr( fd, &ios );
ios.c_lflag = 0;
tcsetattr( fd, TCSANOW,&ios );
}
}
......
}
s_closed = 0;
//①打开AT模块,传入一个回调函数onUnsolicited
ret = at_open(fd, onUnsolicited);
......
//②下面这个函数向Rild提交一个超时任务,该任务的处理函数是initializeCallback
RIL_requestTimedCallback(initializeCallback,NULL, &TIMEVAL_0);
sleep(1);
/*
如果AT模块被关闭,则waitForClose返回,但是该线程并不会退出,而是从for循环那
开始重新执行一次。所以这个mainLoop工作线程是用来监控AT模块的,一旦它被关闭,就
需要重新打开。也就是说不允许AT模块被关闭。
*/
waitForClose();
......
}
}
~~~
可以看到,mainLoop的工作其实就是初始化AT模块,并监控AT模块,一旦AT模块被关闭,那么mainLoop就要重新打开并初始化它。这几项工作主要由at_open和超时任务的处理函数initializeCallback完成。
(1)at_open分析
来看at_open这个函数,其代码如下所示:
**Atchannle.c**
~~~
int at_open(int fd, ATUnsolHandler h)
{
//at_open的第一个参数是一个代表串口设备的文件描述符。
intret;
pthread_t tid;
pthread_attr_t attr;
s_fd =fd;
s_unsolHandler = h;
s_readerClosed = 0;
s_responsePrefix = NULL;
s_smsPDU = NULL;
sp_response = NULL;
......//和电源管理相关的操作
pthread_attr_init (&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
//创建一个工作线程readerLoop,这个线程的目的就是从串口设备读取数据
ret =pthread_create(&s_tid_reader, &attr, readerLoop, &attr);
......
return0;
}
~~~
at_open函数会另外创建一个工作线程readerLoop,从名字上看,它会读取串口设备。下面来看它的工作,代码如下所示:
**Atchannle.c**
~~~
static void *readerLoop(void *arg)
{
for(;;) {
const char * line;
line = readline(); //从串口设备读取数据
......
if(isSMSUnsolicited(line)) {
char *line1;
const char *line2;
line1 = strdup(line);
line2 = readline();
if (line2 == NULL) {
break;
}
if (s_unsolHandler != NULL) {
s_unsolHandler (line1, line2);//调用回调,处理SMS的通知
}
free(line1);
}else {
//处理接收到的数据,也就是根据line中的AT指令调用不同的回调
processLine(line);
}
......//电源管理相关
//这个线程退出前会调用通过at_set_on_reader_closed设置的回调函数,以通知
//AT模块关闭
onReaderClosed();
returnNULL;
}
~~~
readerLoop工作线程比较简单,就是从串口设备中读取数据,然后进行处理。这些数据有可能是solicited response,也有可能是unsolicited response,具体的处理函数我们在后续的实例分析中再来介绍,下面我们看第二个函数RIL_requestTimedCallback。
(2)initializeCallback的分析
在分析initializeCallback函数前,我们先看看RefRil向Rild提交超时任务的RIL_requestTimedCallback函数,它其实是一个宏,不过这个宏比较简单,就是封装了RIL_Env结构体中对RequestTimedCallback函数的调用,代码如下所示:
~~~
#define RIL_requestTimedCallback(a,b,c) \
s_rilenv->RequestTimedCallback(a,b,c)
//向Rild提交一个超时处理函数
~~~
下面我们看看Rild实现的这个RequestTimedCallback函数,代码如下所示。
**Ril.cpp**
~~~
extern "C" void *
RIL_requestTimedCallback (RIL_TimedCallbackcallback, void *param,
const structtimeval *relativeTime) {
returninternalRequestTimedCallback (callback, param, relativeTime);
}
/*
调用internalRequestTimedCallback,其实就是构造一个Ril_event事件然后加入到
timer_list,并触发event_loop工作线程执行
*/
static UserCallbackInfo * internalRequestTimedCallback(
RIL_TimedCallback callback, void *param,
const structtimeval *relativeTime)
{
structtimeval myRelativeTime;
UserCallbackInfo *p_info;
p_info= (UserCallbackInfo *) malloc (sizeof(UserCallbackInfo));
p_info->p_callback = callback;
p_info->userParam = param;
if(relativeTime == NULL) {
memset (&myRelativeTime, 0, sizeof(myRelativeTime));
} else{
memcpy (&myRelativeTime, relativeTime, sizeof(myRelativeTime));
}
ril_event_set(&(p_info->event), -1, false, userTimerCallback,p_info);
//将该任务添加到timer_list中去
ril_timer_add(&(p_info->event), &myRelativeTime);
triggerEvLoop(); //触发eventLoop线程
returnp_info;
}
~~~
从上面的代码可知,RIL_requestTimedCallback函数就是向eventLoop提交一个超时任务,这个任务的处理函数则为initialCallback,下面直接来看该函数的内容,如下所示。
**Reference_ril.c**
~~~
static void initializeCallback(void *param)
{
/*
这个函数就是通过发送一些AT指令来初始化BP中的无线通信Modem,不同的modem可能有
不同的AT指令。这里仅列出部分代码。
*/
ATResponse *p_response = NULL;
interr;
setRadioState (RADIO_STATE_OFF);
at_handshake();
......
err =at_send_command("AT+CREG=2", &p_response);
......
at_response_free(p_response);
at_send_command("AT+CGREG=1", NULL);
at_send_command("AT+CCWA=1", NULL);
......
if(isRadioOn() > 0) {
setRadioState (RADIO_STATE_SIM_NOT_READY);
}
......
}
~~~
2. RIL_Init的总结
RIL_Init函数由动态库提供,以上面RefRil库的代码为参考,这个函数执行完后,将完成RefRil库的几项重要工作,它们是:
- 创建一个mainLoop工作线程,mainLoop线程的任务是初始化AT模块,并监控AT模块,一旦AT模块被关闭,则会重新初始化AT模块。
- AT模块内部会创建一个工作线程readerLoop,该线程的作用是从串口设备中读取信息,也就是直接和BP打交道。
- mainLoop通过向Rild提交超时任务,完成了对Modem的初始化工作。
在Rild的main函数中还剩下最后一个关键函数RIL_register没有分析了,下面来看看它。
- 前言
- 第1章 阅读前的准备工作
- 1.1 系统架构
- 1.1.1 Android系统架构
- 1.1.2 本书的架构
- 1.2 搭建开发环境
- 1.2.1 下载源码
- 1.2.2 编译源码
- 1.3 工具介绍
- 1.3.1 Source Insight介绍
- 1.3.2 Busybox的使用
- 1.4 本章小结
- 第2章 深入理解JNI
- 2.1 JNI概述
- 2.2 学习JNI的实例:MediaScanner
- 2.3 Java层的MediaScanner分析
- 2.3.1 加载JNI库
- 2.3.2 Java的native函数和总结
- 2.4 JNI层MediaScanner的分析
- 2.4.1 注册JNI函数
- 2.4.2 数据类型转换
- 2.4.3 JNIEnv介绍
- 2.4.4 通过JNIEnv操作jobject
- 2.4.5 jstring介绍
- 2.4.6 JNI类型签名介绍
- 2.4.7 垃圾回收
- 2.4.8 JNI中的异常处理
- 2.5 本章小结
- 第3章 深入理解init
- 3.1 概述
- 3.2 init分析
- 3.2.1 解析配置文件
- 3.2.2 解析service
- 3.2.3 init控制service
- 3.2.4 属性服务
- 3.3 本章小结
- 第4章 深入理解zygote
- 4.1 概述
- 4.2 zygote分析
- 4.2.1 AppRuntime分析
- 4.2.2 Welcome to Java World
- 4.2.3 关于zygote的总结
- 4.3 SystemServer分析
- 4.3.1 SystemServer的诞生
- 4.3.2 SystemServer的重要使命
- 4.3.3 关于 SystemServer的总结
- 4.4 zygote的分裂
- 4.4.1 ActivityManagerService发送请求
- 4.4.2 有求必应之响应请求
- 4.4.3 关于zygote分裂的总结
- 4.5 拓展思考
- 4.5.1 虚拟机heapsize的限制
- 4.5.2 开机速度优化
- 4.5.3 Watchdog分析
- 4.6 本章小结
- 第5章 深入理解常见类
- 5.1 概述
- 5.2 以“三板斧”揭秘RefBase、sp和wp
- 5.2.1 第一板斧--初识影子对象
- 5.2.2 第二板斧--由弱生强
- 5.2.3 第三板斧--破解生死魔咒
- 5.2.4 轻量级的引用计数控制类LightRefBase
- 5.2.5 题外话-三板斧的来历
- 5.3 Thread类及常用同步类分析
- 5.3.1 一个变量引发的思考
- 5.3.2 常用同步类
- 5.4 Looper和Handler类分析
- 5.4.1 Looper类分析
- 5.4.2 Handler分析
- 5.4.3 Looper和Handler的同步关系
- 5.4.4 HandlerThread介绍
- 5.5 本章小结
- 第6章 深入理解Binder
- 6.1 概述
- 6.2 庖丁解MediaServer
- 6.2.1 MediaServer的入口函数
- 6.2.2 独一无二的ProcessState
- 6.2.3 时空穿越魔术-defaultServiceManager
- 6.2.4 注册MediaPlayerService
- 6.2.5 秋风扫落叶-StartThread Pool和join Thread Pool分析
- 6.2.6 你彻底明白了吗
- 6.3 服务总管ServiceManager
- 6.3.1 ServiceManager的原理
- 6.3.2 服务的注册
- 6.3.3 ServiceManager存在的意义
- 6.4 MediaPlayerService和它的Client
- 6.4.1 查询ServiceManager
- 6.4.2 子承父业
- 6.5 拓展思考
- 6.5.1 Binder和线程的关系
- 6.5.2 有人情味的讣告
- 6.5.3 匿名Service
- 6.6 学以致用
- 6.6.1 纯Native的Service
- 6.6.2 扶得起的“阿斗”(aidl)
- 6.7 本章小结
- 第7章 深入理解Audio系统
- 7.1 概述
- 7.2 AudioTrack的破解
- 7.2.1 用例介绍
- 7.2.2 AudioTrack(Java空间)分析
- 7.2.3 AudioTrack(Native空间)分析
- 7.2.4 关于AudioTrack的总结
- 7.3 AudioFlinger的破解
- 7.3.1 AudioFlinger的诞生
- 7.3.2 通过流程分析AudioFlinger
- 7.3.3 audio_track_cblk_t分析
- 7.3.4 关于AudioFlinger的总结
- 7.4 AudioPolicyService的破解
- 7.4.1 AudioPolicyService的创建
- 7.4.2 重回AudioTrack
- 7.4.3 声音路由切换实例分析
- 7.4.4 关于AudioPolicy的总结
- 7.5 拓展思考
- 7.5.1 DuplicatingThread破解
- 7.5.2 题外话
- 7.6 本章小结
- 第8章 深入理解Surface系统
- 8.1 概述
- 8.2 一个Activity的显示
- 8.2.1 Activity的创建
- 8.2.2 Activity的UI绘制
- 8.2.3 关于Activity的总结
- 8.3 初识Surface
- 8.3.1 和Surface有关的流程总结
- 8.3.2 Surface之乾坤大挪移
- 8.3.3 乾坤大挪移的JNI层分析
- 8.3.4 Surface和画图
- 8.3.5 初识Surface小结
- 8.4 深入分析Surface
- 8.4.1 与Surface相关的基础知识介绍
- 8.4.2 SurfaceComposerClient分析
- 8.4.3 SurfaceControl分析
- 8.4.4 writeToParcel和Surface对象的创建
- 8.4.5 lockCanvas和unlockCanvasAndPost分析
- 8.4.6 GraphicBuffer介绍
- 8.4.7 深入分析Surface的总结
- 8.5 SurfaceFlinger分析
- 8.5.1 SurfaceFlinger的诞生
- 8.5.2 SF工作线程分析
- 8.5.3 Transaction分析
- 8.5.4 关于SurfaceFlinger的总结
- 8.6 拓展思考
- 8.6.1 Surface系统的CB对象分析
- 8.6.2 ViewRoot的你问我答
- 8.6.3 LayerBuffer分析
- 8.7 本章小结
- 第9章 深入理解Vold和Rild
- 9.1 概述
- 9.2 Vold的原理与机制分析
- 9.2.1 Netlink和Uevent介绍
- 9.2.2 初识Vold
- 9.2.3 NetlinkManager模块分析
- 9.2.4 VolumeManager模块分析
- 9.2.5 CommandListener模块分析
- 9.2.6 Vold实例分析
- 9.2.7 关于Vold的总结
- 9.3 Rild的原理与机制分析
- 9.3.1 初识Rild
- 9.3.2 RIL_startEventLoop分析
- 9.3.3 RIL_Init分析
- 9.3.4 RIL_register分析
- 9.3.5 关于Rild main函数的总结
- 9.3.6 Rild实例分析
- 9.3.7 关于Rild的总结
- 9.4 拓展思考
- 9.4.1 嵌入式系统的存储知识介绍
- 9.4.2 Rild和Phone的改进探讨
- 9.5 本章小结
- 第10章 深入理解MediaScanner
- 10.1 概述
- 10.2 android.process.media分析
- 10.2.1 MSR模块分析
- 10.2.2 MSS模块分析
- 10.2.3 android.process.media媒体扫描工作的流程总结
- 10.3 MediaScanner分析
- 10.3.1 Java层分析
- 10.3.2 JNI层分析
- 10.3.3 PVMediaScanner分析
- 10.3.4 关于MediaScanner的总结
- 10.4 拓展思考
- 10.4.1 MediaScannerConnection介绍
- 10.4.2 我问你答
- 10.5 本章小结