Android 电话系统框架介绍
在Android系统中rild运行在AP上,AP上的应用通过rild发送AT指令给BP,BP接收到信息后又通过rild传送给AP。AP与BP之间有两种通信方式:
1.Solicited Response:Ap向Bp发送请求,Bp给Ap发送回复,该类型的AT指令及其回调函数以数组的形式存放在Ril_commands.h文件中:
{数组中的索引号,请求回调函数,响应回调函数}
- {0, NULL, NULL}, //none
- {RIL_REQUEST_GET_SIM_STATUS, dispatchVoid, responseSimStatus},
- {RIL_REQUEST_ENTER_SIM_PIN, dispatchStrings, responseInts},
- {RIL_REQUEST_ENTER_SIM_PUK, dispatchStrings, responseInts},
- {RIL_REQUEST_ENTER_SIM_PIN2, dispatchStrings, responseInts},
- {RIL_REQUEST_ENTER_SIM_PUK2, dispatchStrings, responseInts},
- {RIL_REQUEST_CHANGE_SIM_PIN, dispatchStrings, responseInts},
- {RIL_REQUEST_CHANGE_SIM_PIN2, dispatchStrings, responseInts},
- {RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION, dispatchStrings, responseInts},
- {RIL_REQUEST_GET_CURRENT_CALLS, dispatchVoid, responseCallList},
- {RIL_REQUEST_DIAL, dispatchDial, responseVoid},
- {RIL_REQUEST_GET_IMSI, dispatchStrings, responseString},
- {RIL_REQUEST_HANGUP, dispatchInts, responseVoid},
- {RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND, dispatchVoid, responseVoid},
- ...
{0, NULL, NULL}, //none
{RIL_REQUEST_GET_SIM_STATUS, dispatchVoid, responseSimStatus},
{RIL_REQUEST_ENTER_SIM_PIN, dispatchStrings, responseInts},
{RIL_REQUEST_ENTER_SIM_PUK, dispatchStrings, responseInts},
{RIL_REQUEST_ENTER_SIM_PIN2, dispatchStrings, responseInts},
{RIL_REQUEST_ENTER_SIM_PUK2, dispatchStrings, responseInts},
{RIL_REQUEST_CHANGE_SIM_PIN, dispatchStrings, responseInts},
{RIL_REQUEST_CHANGE_SIM_PIN2, dispatchStrings, responseInts},
{RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION, dispatchStrings, responseInts},
{RIL_REQUEST_GET_CURRENT_CALLS, dispatchVoid, responseCallList},
{RIL_REQUEST_DIAL, dispatchDial, responseVoid},
{RIL_REQUEST_GET_IMSI, dispatchStrings, responseString},
{RIL_REQUEST_HANGUP, dispatchInts, responseVoid},
{RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND, dispatchVoid, responseVoid},
...
不同手机厂商使用的AT命令不完全相同,为了保密,AP与BP之间通过各厂商自己的相关动态库来通信。
RIL模块由rild守护进程、libril.so、librefrence.so三部分组成:
1.rild模块被编译为一个可执行文件,实现一个main函数作为整个ril模块的入口点。在初始化时使用dlopen打开librefrence_ril.so,从中取出并执行RIL_Init函数,得到RIL_RadioFunctions指针,通过RIL_register()函数注册到libril.so库中,其源码结构如下:
2.libril.so是共享库,主要负责同上层的通信工作,接收ril的请求,并传递给librefrence_ril.so,同时将librefrence_ril.so返回的消息送给调用进程,源码结构如下所示:
3.librefrence_ril.so是由各手机厂商自己实现,在rild进程运行中通过dlopen方式加载,主要负责跟modem硬件通信,转换来自libril.so的请求为AT命令,同时监听Modem的反馈信息给libril.so
Android的电话系统主要分为三个部分,Java层的各种电话相关应用,java层的Phone Service,主要为上层提供API,同时与native进行通信,可以看做为电话系统的客户端,native层的电话服务进程RILD,负责为上层提供各种电话功能服务,直接与modem进行交互:
Android电话系统设计框架图:
由于Android 开发者使用的Modem 是不一样的,各种指令格式,初始化序列都可能不一样,所以为了消除这些差别,Android 设计者将ril 做了一个抽象,使用一个虚拟电话的概念,不同modem相关的AT指令或者通信协议编译成相应的动态链接库.so文件,Rild 是具体的AT 指令合成者和应答解析者。
Android电话系统代码结构图:
RILD框架设计
在android的电话系统中,在native层实现了电话服务的服务端,由RILD服务与modem的交互,在java层实现电话的客户端,本文主要介绍电话系统的服务端RILD进程,以下是RILD的设计框架图:
RILD源码分析
接下来通过源码对RILD的整个框架进行详细介绍。
在kernel启动完成后,将启动第一个应用进程Init进程,在android之Init进程启动过程源码分析一文中对init进程的启动流程进行了详细的介绍。init进程在启动过程中将读取init.rc文件来启动一些重量级的native服务,rild进程就是通过配置在init.rc中来启动的。
- service ril-daemon /system/bin/rild
- class main
- socket rild stream 660 root radio
- socket rild-debug stream 660 radio system
- user root
- group radio cache inet misc audio sdcard_rw log
service ril-daemon /system/bin/rild
class main
socket rild stream 660 root radio
socket rild-debug stream 660 radio system
user root
group radio cache inet misc audio sdcard_rw log
RILD进程入口函数分析
接下来给出的是RILD进程启动的时序图:
hardware\ril\rild\rild.c
- int main(int argc, charchar **argv)
- {
- const charchar * rilLibPath = NULL;
- charchar **rilArgv;
- voidvoid *dlHandle;
- const RIL_RadioFunctions *(*rilInit)(const struct RIL_Env *, int, charchar **);
- const RIL_RadioFunctions *funcs;
- char libPath[PROPERTY_VALUE_MAX];
- unsigned char hasLibArgs = 0;
- int i;
- umask(S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH);
- //rild启动无参数
- for (i = 1; i < argc ;) {
- if (0 == strcmp(argv[i], "-l") && (argc - i > 1)) {
- rilLibPath = argv[i + 1];
- i += 2;
- } else if (0 == strcmp(argv[i], "--")) {
- i++;
- hasLibArgs = 1;
- break;
- } else {
- usage(argv[0]);
- }
- }
- if (rilLibPath == NULL) {
- //通过Android属性系统读取属性"rild.libpath"的值,即lib库的存放路径
- if ( 0 == property_get(LIB_PATH_PROPERTY, libPath, NULL)) {
- goto done;
- } else {
- rilLibPath = libPath;
- }
- }
- ##################################################################################
- 判断是否为模拟器
- ##################################################################################
- #if 1
- {
- static char* arg_overrides[3];
- static char arg_device[32];
- int done = 0;
- #define REFERENCE_RIL_PATH "/system/lib/libreference-ril.so"
- /* first, read /proc/cmdline into memory */
- char buffer[1024], *p, *q;
- int len;
- int fd = open("/proc/cmdline",O_RDONLY);
- if (fd < 0) {
- LOGD("could not open /proc/cmdline:%s", strerror(errno));
- goto OpenLib;
- }
- //读取/proc/cmdline文件中的内容
- do {
- len = read(fd,buffer,sizeof(buffer)); }
- while (len == -1 && errno == EINTR);
- if (len < 0) {
- LOGD("could not read /proc/cmdline:%s", strerror(errno));
- close(fd);
- goto OpenLib;
- }
- close(fd);
- //判断是否为模拟器,对于真机,此处条件为false
- if (strstr(buffer, "android.qemud=") != NULL)
- {
- int tries = 5;
- #define QEMUD_SOCKET_NAME "qemud"
- while (1) {
- int fd;
- sleep(1);
- fd = socket_local_client(QEMUD_SOCKET_NAME,
- ANDROID_SOCKET_NAMESPACE_RESERVED,
- SOCK_STREAM );
- if (fd >= 0) {
- close(fd);
- snprintf( arg_device, sizeof(arg_device), "%s/%s",
- ANDROID_SOCKET_DIR, QEMUD_SOCKET_NAME );
- arg_overrides[1] = "-s";
- arg_overrides[2] = arg_device;
- done = 1;
- break;
- }
- LOGD("could not connect to %s socket: %s",QEMUD_SOCKET_NAME, strerror(errno));
- if (--tries == 0)
- break;
- }
- if (!done) {
- LOGE("could not connect to %s socket (giving up): %s",
- QEMUD_SOCKET_NAME, strerror(errno));
- while(1)
- sleep(0x00ffffff);
- }
- }
- /* otherwise, try to see if we passed a device name from the kernel */
- if (!done) do { //true
- #define KERNEL_OPTION "android.ril="
- #define DEV_PREFIX "/dev/"
- //判断/proc/cmdline中的内容是否包含"android.ril="
- p = strstr( buffer, KERNEL_OPTION );
- if (p == NULL)
- break;
- p += sizeof(KERNEL_OPTION)-1;
- q = strpbrk( p, " \t\n\r" );
- if (q != NULL)
- *q = 0;
- snprintf( arg_device, sizeof(arg_device), DEV_PREFIX "%s", p );
- arg_device[sizeof(arg_device)-1] = 0;
- arg_overrides[1] = "-d";
- arg_overrides[2] = arg_device;
- done = 1;
- } while (0);
- if (done) { //false
- argv = arg_overrides;
- argc = 3;
- i = 1;
- hasLibArgs = 1;
- rilLibPath = REFERENCE_RIL_PATH;
- LOGD("overriding with %s %s", arg_overrides[1], arg_overrides[2]);
- }
- }
- OpenLib:
- #endif
- ##################################################################################
- 动态库装载
- ##################################################################################
- switchUser();//设置Rild进程的组用户为radio
- //加载厂商自定义的库
- ①dlHandle = dlopen(rilLibPath, RTLD_NOW);
- if (dlHandle == NULL) {
- fprintf(stderr, "dlopen failed: %s\n", dlerror());
- exit(-1);
- }
- //<span style="font-family:'Courier New';color:#080000;line-height: 1.5; white-space: pre-wrap;">创建客户端事件监听线程</span>
- ②RIL_startEventLoop();
- //<span style="font-family:'Courier New';color:#080000;line-height: 1.5; white-space: pre-wrap;">通过dlsym定位到RIL_Init函数的地址,并且强制转换为RIL_RadioFunctions的函数指针</span>
- ③rilInit = (const RIL_RadioFunctions *(*)(const struct RIL_Env *, int, charchar **))dlsym(dlHandle, "RIL_Init");
- if (rilInit == NULL) {
- fprintf(stderr, "RIL_Init not defined or exported in %s\n", rilLibPath);
- exit(-1);
- }
- if (hasLibArgs) { //false
- rilArgv = argv + i - 1;
- argc = argc -i + 1;
- } else {
- static charchar * newArgv[MAX_LIB_ARGS];
- static char args[PROPERTY_VALUE_MAX];
- rilArgv = newArgv;
- property_get(LIB_ARGS_PROPERTY, args, "");//通过属性系统读取"rild.libargs"属性值
- argc = make_argv(args, rilArgv);
- }
- // Make sure there's a reasonable argv[0]
- rilArgv[0] = argv[0];
- //调用RIL_Init函数来初始化rild,传入参数s_rilEnv,返回RIL_RadioFunctions地址
- ④funcs = rilInit(&s_rilEnv, argc, rilArgv);
- //<span style="font-family:'Courier New';color:#080000;line-height: 1.5; white-space: pre-wrap;">注册客户端事件处理接口</span><span style="font-family:'Courier New';color:#080000;line-height: 1.5; white-space: pre-wrap;">RIL_RadioFunctions</span><span style="font-family:'Courier New';color:#080000;line-height: 1.5; white-space: pre-wrap;">,并创建socket监听事件</span>
- ⑤RIL_register(funcs);
- done:
- while(1) {
- // sleep(UINT32_MAX) seems to return immediately on bionic
- sleep(0x00ffffff);
- }
- }
int main(int argc, char **argv)
{
const char * rilLibPath = NULL;
char **rilArgv;
void *dlHandle;
const RIL_RadioFunctions *(*rilInit)(const struct RIL_Env *, int, char **);
const RIL_RadioFunctions *funcs;
char libPath[PROPERTY_VALUE_MAX];
unsigned char hasLibArgs = 0;
int i;
umask(S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH);
//rild启动无参数
for (i = 1; i < argc ;) {
if (0 == strcmp(argv[i], "-l") && (argc - i > 1)) {
rilLibPath = argv[i + 1];
i += 2;
} else if (0 == strcmp(argv[i], "--")) {
i++;
hasLibArgs = 1;
break;
} else {
usage(argv[0]);
}
}
if (rilLibPath == NULL) {
//通过Android属性系统读取属性"rild.libpath"的值,即lib库的存放路径
if ( 0 == property_get(LIB_PATH_PROPERTY, libPath, NULL)) {
goto done;
} else {
rilLibPath = libPath;
}
}
##################################################################################
判断是否为模拟器
##################################################################################
#if 1
{
static char* arg_overrides[3];
static char arg_device[32];
int done = 0;
#define REFERENCE_RIL_PATH "/system/lib/libreference-ril.so"
/* first, read /proc/cmdline into memory */
char buffer[1024], *p, *q;
int len;
int fd = open("/proc/cmdline",O_RDONLY);
if (fd < 0) {
LOGD("could not open /proc/cmdline:%s", strerror(errno));
goto OpenLib;
}
//读取/proc/cmdline文件中的内容
do {
len = read(fd,buffer,sizeof(buffer)); }
while (len == -1 && errno == EINTR);
if (len < 0) {
LOGD("could not read /proc/cmdline:%s", strerror(errno));
close(fd);
goto OpenLib;
}
close(fd);
//判断是否为模拟器,对于真机,此处条件为false
if (strstr(buffer, "android.qemud=") != NULL)
{
int tries = 5;
#define QEMUD_SOCKET_NAME "qemud"
while (1) {
int fd;
sleep(1);
fd = socket_local_client(QEMUD_SOCKET_NAME,
ANDROID_SOCKET_NAMESPACE_RESERVED,
SOCK_STREAM );
if (fd >= 0) {
close(fd);
snprintf( arg_device, sizeof(arg_device), "%s/%s",
ANDROID_SOCKET_DIR, QEMUD_SOCKET_NAME );
arg_overrides[1] = "-s";
arg_overrides[2] = arg_device;
done = 1;
break;
}
LOGD("could not connect to %s socket: %s",QEMUD_SOCKET_NAME, strerror(errno));
if (--tries == 0)
break;
}
if (!done) {
LOGE("could not connect to %s socket (giving up): %s",
QEMUD_SOCKET_NAME, strerror(errno));
while(1)
sleep(0x00ffffff);
}
}
/* otherwise, try to see if we passed a device name from the kernel */
if (!done) do { //true
#define KERNEL_OPTION "android.ril="
#define DEV_PREFIX "/dev/"
//判断/proc/cmdline中的内容是否包含"android.ril="
p = strstr( buffer, KERNEL_OPTION );
if (p == NULL)
break;
p += sizeof(KERNEL_OPTION)-1;
q = strpbrk( p, " \t\n\r" );
if (q != NULL)
*q = 0;
snprintf( arg_device, sizeof(arg_device), DEV_PREFIX "%s", p );
arg_device[sizeof(arg_device)-1] = 0;
arg_overrides[1] = "-d";
arg_overrides[2] = arg_device;
done = 1;
} while (0);
if (done) { //false
argv = arg_overrides;
argc = 3;
i = 1;
hasLibArgs = 1;
rilLibPath = REFERENCE_RIL_PATH;
LOGD("overriding with %s %s", arg_overrides[1], arg_overrides[2]);
}
}
OpenLib:
#endif
##################################################################################
动态库装载
##################################################################################
switchUser();//设置Rild进程的组用户为radio
//加载厂商自定义的库
①dlHandle = dlopen(rilLibPath, RTLD_NOW);
if (dlHandle == NULL) {
fprintf(stderr, "dlopen failed: %s\n", dlerror());
exit(-1);
}
//<span style="font-family:'Courier New';color:#080000;line-height: 1.5; white-space: pre-wrap;">创建客户端事件监听线程</span>
②RIL_startEventLoop();
//<span style="font-family:'Courier New';color:#080000;line-height: 1.5; white-space: pre-wrap;">通过dlsym定位到RIL_Init函数的地址,并且强制转换为RIL_RadioFunctions的函数指针</span>
③rilInit = (const RIL_RadioFunctions *(*)(const struct RIL_Env *, int, char **))dlsym(dlHandle, "RIL_Init");
if (rilInit == NULL) {
fprintf(stderr, "RIL_Init not defined or exported in %s\n", rilLibPath);
exit(-1);
}
if (hasLibArgs) { //false
rilArgv = argv + i - 1;
argc = argc -i + 1;
} else {
static char * newArgv[MAX_LIB_ARGS];
static char args[PROPERTY_VALUE_MAX];
rilArgv = newArgv;
property_get(LIB_ARGS_PROPERTY, args, "");//通过属性系统读取"rild.libargs"属性值
argc = make_argv(args, rilArgv);
}
// Make sure there's a reasonable argv[0]
rilArgv[0] = argv[0];
//调用RIL_Init函数来初始化rild,传入参数s_rilEnv,返回RIL_RadioFunctions地址
④funcs = rilInit(&s_rilEnv, argc, rilArgv);
//<span style="font-family:'Courier New';color:#080000;line-height: 1.5; white-space: pre-wrap;">注册客户端事件处理接口</span><span style="font-family:'Courier New';color:#080000;line-height: 1.5; white-space: pre-wrap;">RIL_RadioFunctions</span><span style="font-family:'Courier New';color:#080000;line-height: 1.5; white-space: pre-wrap;">,并创建socket监听事件</span>
⑤RIL_register(funcs);
done:
while(1) {
// sleep(UINT32_MAX) seems to return immediately on bionic
sleep(0x00ffffff);
}
}
1.解析命令行参数,通过判断是否为模拟器采取不同的方式来读取libreference-ril.so库的存放路径;
2.使用dlopen手动装载libreference-ril.so库;
3.启动事件循环处理;
4.从libreference-ril.so库中取得RIL_Init函数地址,并使用该函数将libril.so库中的RIL_Env接口注册到libreference-ril.so库,同时将libreference-ril.so库中的RIL_RadioFunctions接口注册到到libril.so库中,建立起libril.so库与libreference-ril.so库通信桥梁;
启动事件循环处理eventLoop工作线程
建立多路I/O驱动机制的消息队列,用来接收上层发出的命令以及往Modem发送AT指令的工作,时整个RIL系统的核心部分。创建一个事件分发线程s_tid_dispatch,线程执行体为eventLoop。
hardware\ril\libril\Ril.cpp
- extern "C" void RIL_startEventLoop(void) {
- int ret;
- pthread_attr_t attr;
- /* spin up eventLoop thread and wait for it to get started */
- s_started = 0;
- pthread_mutex_lock(&s_startupMutex);
- pthread_attr_init (&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- //创建一个工作线程eventLoop
- ret = pthread_create(&s_tid_dispatch, &attr, eventLoop, NULL);
- //确保函数返回前eventLoop线程启动运行
- while (s_started == 0) {
- pthread_cond_wait(&s_startupCond, &s_startupMutex);
- }
- pthread_mutex_unlock(&s_startupMutex);
- if (ret < 0) {
- LOGE("Failed to create dispatch thread errno:%d", errno);
- return;
- }
- }
extern "C" void RIL_startEventLoop(void) {
int ret;
pthread_attr_t attr;
/* spin up eventLoop thread and wait for it to get started */
s_started = 0;
pthread_mutex_lock(&s_startupMutex);
pthread_attr_init (&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
//创建一个工作线程eventLoop
ret = pthread_create(&s_tid_dispatch, &attr, eventLoop, NULL);
//确保函数返回前eventLoop线程启动运行
while (s_started == 0) {
pthread_cond_wait(&s_startupCond, &s_startupMutex);
}
pthread_mutex_unlock(&s_startupMutex);
if (ret < 0) {
LOGE("Failed to create dispatch thread errno:%d", errno);
return;
}
}
2. Wakeup事件:这些事件的句柄fd将加入的select IO多路复用的句柄池readFDs中,当对应的fd可读时将触发这些事件。对于处于listen端的socket,fd可读表示有个客户端连接,此时需要调用accept接受连接。
事件定义如下:- struct ril_event {
- struct ril_event *next;
- struct ril_event *prev;
- int fd; //文件句柄
- int index; //该事件在监控表中的索引
- bool persist; //如果是保持的,则不从watch_list 中删除
- struct timeval timeout; //任务执行时间
- ril_event_cb func; //回调事件处理函数
- void *param; //回调时参数
- };
struct ril_event {
struct ril_event *next;
struct ril_event *prev;
int fd; //文件句柄
int index; //该事件在监控表中的索引
bool persist; //如果是保持的,则不从watch_list 中删除
struct timeval timeout; //任务执行时间
ril_event_cb func; //回调事件处理函数
void *param; //回调时参数
};
在Rild进程中的几个重要事件有
- static struct ril_event s_commands_event;
- ril_event_set (&s_commands_event, s_fdCommand, 1,processCommandsCallback, p_rs)
- static struct ril_event s_wakeupfd_event;
- ril_event_set (&s_wakeupfd_event, s_fdWakeupRead, true,processWakeupCallback, NULL)
- static struct ril_event s_listen_event;
- ril_event_set (&s_listen_event, s_fdListen, false,listenCallback, NULL)
- static struct ril_event s_wake_timeout_event;
- ril_timer_add(&(p_info->event), &myRelativeTime);
- static struct ril_event s_debug_event;
- ril_event_set (&s_debug_event, s_fdDebug, true,debugCallback, NULL)
static struct ril_event s_commands_event;
ril_event_set (&s_commands_event, s_fdCommand, 1,processCommandsCallback, p_rs)
static struct ril_event s_wakeupfd_event;
ril_event_set (&s_wakeupfd_event, s_fdWakeupRead, true,processWakeupCallback, NULL)
static struct ril_event s_listen_event;
ril_event_set (&s_listen_event, s_fdListen, false,listenCallback, NULL)
static struct ril_event s_wake_timeout_event;
ril_timer_add(&(p_info->event), &myRelativeTime);
static struct ril_event s_debug_event;
ril_event_set (&s_debug_event, s_fdDebug, true,debugCallback, NULL)
/事件监控队列
static struct ril_event * watch_table[MAX_FD_EVENTS];
//定时事件队列
static struct ril_event timer_list;
//处理事件队列
static struct ril_event pending_list; //待处理事件队列,事件已经触发,需要所回调处理的事件
添加事件
- static void rilEventAddWakeup(struct ril_event *ev) {
- ril_event_add(ev); //向监控表watch_table添加一个s_wakeupfd_event事件
- triggerEvLoop(); //向管道s_fdWakeupWrite中写入之来触发事件循环
- }
static void rilEventAddWakeup(struct ril_event *ev) {
ril_event_add(ev); //向监控表watch_table添加一个s_wakeupfd_event事件
triggerEvLoop(); //向管道s_fdWakeupWrite中写入之来触发事件循环
}
- void ril_event_add(struct ril_event * ev)
- {
- dlog("~~~~ +ril_event_add ~~~~");
- MUTEX_ACQUIRE();
- for (int i = 0; i < MAX_FD_EVENTS; i++) { //遍历监控表watch_table
- if (watch_table[i] == NULL) { //从监控表中查找空闲的索引,然后把该任务加入到监控表中
- watch_table[i] = ev; //向监控表中添加事件
- ev->index = i; //事件的索引设置为在监控表中的索引
- dlog("~~~~ added at %d ~~~~", i);
- dump_event(ev);
- FD_SET(ev->fd, &readFds); //将添加的事件对应的句柄添加到句柄池readFds中
- if (ev->fd >= nfds) nfds = ev->fd+1; //修改句柄最大值
- dlog("~~~~ nfds = %d ~~~~", nfds);
- break;
- }
- }
- MUTEX_RELEASE();
- dlog("~~~~ -ril_event_add ~~~~");
- }
void ril_event_add(struct ril_event * ev)
{
dlog("~~~~ +ril_event_add ~~~~");
MUTEX_ACQUIRE();
for (int i = 0; i < MAX_FD_EVENTS; i++) { //遍历监控表watch_table
if (watch_table[i] == NULL) { //从监控表中查找空闲的索引,然后把该任务加入到监控表中
watch_table[i] = ev; //向监控表中添加事件
ev->index = i; //事件的索引设置为在监控表中的索引
dlog("~~~~ added at %d ~~~~", i);
dump_event(ev);
FD_SET(ev->fd, &readFds); //将添加的事件对应的句柄添加到句柄池readFds中
if (ev->fd >= nfds) nfds = ev->fd+1; //修改句柄最大值
dlog("~~~~ nfds = %d ~~~~", nfds);
break;
}
}
MUTEX_RELEASE();
dlog("~~~~ -ril_event_add ~~~~");
}
2.添加定时事件
- static void triggerEvLoop() {
- int ret;
- if (!pthread_equal(pthread_self(), s_tid_dispatch)) { //如果当前线程ID不等于事件分发线程eventLoop的线程ID
- do {
- ret = write (s_fdWakeupWrite, " ", 1); //向管道写端写入值1来触发eventLoop事件循环
- } while (ret < 0 && errno == EINTR);
- }
- }
- void ril_event_loop()
- {
- int n;
- fd_set rfds;
- struct timeval tv;
- struct timeval * ptv;
- for (;;) {
- memcpy(&rfds, &readFds, sizeof(fd_set));
- if (-1 == calcNextTimeout(&tv)) {
- dlog("~~~~ no timers; blocking indefinitely ~~~~");
- ptv = NULL;
- } else {
- dlog("~~~~ blocking for %ds + %dus ~~~~", (int)tv.tv_sec, (int)tv.tv_usec);
- ptv = &tv;
- }
- //使用select 函数等待在FDS 上,只要FDS 中记录的设备有数据到来,select 就会设置相应的标志位并返回。readFDS 记录了所有的事件相关设备句柄。readFDS 中句柄是在在AddEvent 加入的。
- printReadies(&rfds);
- n = select(nfds, &rfds, NULL, NULL, ptv);
- printReadies(&rfds);
- dlog("~~~~ %d events fired ~~~~", n);
- if (n < 0) {
- if (errno == EINTR) continue;
- LOGE("ril_event: select error (%d)", errno);
- return;
- }
- processTimeouts(); //从timer_list中查询执行时间已到的事件,并添加到pending_list中
- processReadReadies(&rfds, n); //从watch_table中查询数据可读的事件,并添加到pending_list中去处理,如果该事件不是持久事件,则同时从watch_table中删除
- //遍历pending_list,调用事件处理回调函数处理所有事件
- firePending();
- }
- }
void ril_event_loop()
{
int n;
fd_set rfds;
struct timeval tv;
struct timeval * ptv;
for (;;) {
memcpy(&rfds, &readFds, sizeof(fd_set));
if (-1 == calcNextTimeout(&tv)) {
dlog("~~~~ no timers; blocking indefinitely ~~~~");
ptv = NULL;
} else {
dlog("~~~~ blocking for %ds + %dus ~~~~", (int)tv.tv_sec, (int)tv.tv_usec);
ptv = &tv;
}
//使用select 函数等待在FDS 上,只要FDS 中记录的设备有数据到来,select 就会设置相应的标志位并返回。readFDS 记录了所有的事件相关设备句柄。readFDS 中句柄是在在AddEvent 加入的。
printReadies(&rfds);
n = select(nfds, &rfds, NULL, NULL, ptv);
printReadies(&rfds);
dlog("~~~~ %d events fired ~~~~", n);
if (n < 0) {
if (errno == EINTR) continue;
LOGE("ril_event: select error (%d)", errno);
return;
}
processTimeouts(); //从timer_list中查询执行时间已到的事件,并添加到pending_list中
processReadReadies(&rfds, n); //从watch_table中查询数据可读的事件,并添加到pending_list中去处理,如果该事件不是持久事件,则同时从watch_table中删除
//遍历pending_list,调用事件处理回调函数处理所有事件
firePending();
}
}
1.超时事件查询
- static void processTimeouts()
- {
- dlog("~~~~ +processTimeouts ~~~~");
- MUTEX_ACQUIRE();
- struct timeval now;
- struct ril_event * tev = timer_list.next;
- struct ril_event * next;
- getNow(&now); //获取当前时间
- dlog("~~~~ Looking for timers <= %ds + %dus ~~~~", (int)now.tv_sec, (int)now.tv_usec);
- //如果当前时间大于事件的超时时间,则将该事件从timer_list中移除,添加到pending_list
- while ((tev != &timer_list) && (timercmp(&now, &tev->timeout, >))) {
- dlog("~~~~ firing timer ~~~~");
- next = tev->next;
- removeFromList(tev); //从timer_list中移除事件
- addToList(tev, &pending_list); //将事件添加到pending_list
- tev = next;
- }
- MUTEX_RELEASE();
- dlog("~~~~ -processTimeouts ~~~~");
- }
static void processTimeouts()
{
dlog("~~~~ +processTimeouts ~~~~");
MUTEX_ACQUIRE();
struct timeval now;
struct ril_event * tev = timer_list.next;
struct ril_event * next;
getNow(&now); //获取当前时间
dlog("~~~~ Looking for timers <= %ds + %dus ~~~~", (int)now.tv_sec, (int)now.tv_usec);
//如果当前时间大于事件的超时时间,则将该事件从timer_list中移除,添加到pending_list
while ((tev != &timer_list) && (timercmp(&now, &tev->timeout, >))) {
dlog("~~~~ firing timer ~~~~");
next = tev->next;
removeFromList(tev); //从timer_list中移除事件
addToList(tev, &pending_list); //将事件添加到pending_list
tev = next;
}
MUTEX_RELEASE();
dlog("~~~~ -processTimeouts ~~~~");
}
2.可读事件查询
- static void processReadReadies(fd_set * rfds, int n)
- {
- dlog("~~~~ +processReadReadies (%d) ~~~~", n);
- MUTEX_ACQUIRE();
- //遍历watch_table数组,根据select返回的句柄n查找对应的事件
- 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); //将该事件添加到pending_list中
- if (rev->persist == false) { //如果该事件不是持久事件还要从watch_table中移除
- removeWatch(rev, i);
- }
- n--;
- }
- }
- MUTEX_RELEASE();
- dlog("~~~~ -processReadReadies (%d) ~~~~", n);
- }
static void processReadReadies(fd_set * rfds, int n)
{
dlog("~~~~ +processReadReadies (%d) ~~~~", n);
MUTEX_ACQUIRE();
//遍历watch_table数组,根据select返回的句柄n查找对应的事件
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); //将该事件添加到pending_list中
if (rev->persist == false) { //如果该事件不是持久事件还要从watch_table中移除
removeWatch(rev, i);
}
n--;
}
}
MUTEX_RELEASE();
dlog("~~~~ -processReadReadies (%d) ~~~~", n);
}
3.事件处理
- static void firePending()
- {
- dlog("~~~~ +firePending ~~~~");
- struct ril_event * ev = pending_list.next;
- while (ev != &pending_list) { //遍历pending_list链表,处理链表中的所有事件
- struct ril_event * next = ev->next;
- removeFromList(ev); //将处理完的事件从pending_list中移除
- ev->func(ev->fd, 0, ev->param); //调用事件处理的回调函数
- ev = next;
- }
- dlog("~~~~ -firePending ~~~~");
- }
static void firePending()
{
dlog("~~~~ +firePending ~~~~");
struct ril_event * ev = pending_list.next;
while (ev != &pending_list) { //遍历pending_list链表,处理链表中的所有事件
struct ril_event * next = ev->next;
removeFromList(ev); //将处理完的事件从pending_list中移除
ev->func(ev->fd, 0, ev->param); //调用事件处理的回调函数
ev = next;
}
dlog("~~~~ -firePending ~~~~");
}
RIL_Env定义
hardware\ril\include\telephony\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);
- };
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);
};
hardware\ril\rild\rild.c
s_rilEnv变量定义:
- static struct RIL_Env s_rilEnv = {
- RIL_onRequestComplete,
- RIL_onUnsolicitedResponse,
- RIL_requestTimedCallback
- };
static struct RIL_Env s_rilEnv = {
RIL_onRequestComplete,
RIL_onUnsolicitedResponse,
RIL_requestTimedCallback
};
在hardware\ril\libril\ril.cpp中实现了RIL_Env的各个接口函数
1.RIL_onRequestComplete
- extern "C" void RIL_onRequestComplete(RIL_Token t, RIL_Errno e, void *response, size_t responselen) {
- RequestInfo *pRI;
- int ret;
- size_t errorOffset;
- pRI = (RequestInfo *)t;
- if (!checkAndDequeueRequestInfo(pRI)) {
- LOGE ("RIL_onRequestComplete: invalid RIL_Token");
- return;
- }
- if (pRI->local > 0) {
- // Locally issued command...void only!
- // response does not go back up the command socket
- LOGD("C[locl]< %s", requestToString(pRI->pCI->requestNumber));
- goto done;
- }
- appendPrintBuf("[%04d]< %s",pRI->token, requestToString(pRI->pCI->requestNumber));
- if (pRI->cancelled == 0) {
- Parcel p;
- p.writeInt32 (RESPONSE_SOLICITED);
- p.writeInt32 (pRI->token);
- errorOffset = p.dataPosition();
- p.writeInt32 (e);
- if (response != NULL) {
- // there is a response payload, no matter success or not.
- ret = pRI->pCI->responseFunction(p, response, responselen);
- /* if an error occurred, rewind and mark it */
- if (ret != 0) {
- p.setDataPosition(errorOffset);
- p.writeInt32 (ret);
- }
- }
- if (e != RIL_E_SUCCESS) {
- appendPrintBuf("%s fails by %s", printBuf, failCauseToString(e));
- }
- if (s_fdCommand < 0) {
- LOGD ("RIL onRequestComplete: Command channel closed");
- }
- sendResponse(p);
- }
- done:
- free(pRI);
- }
extern "C" void RIL_onRequestComplete(RIL_Token t, RIL_Errno e, void *response, size_t responselen) {
RequestInfo *pRI;
int ret;
size_t errorOffset;
pRI = (RequestInfo *)t;
if (!checkAndDequeueRequestInfo(pRI)) {
LOGE ("RIL_onRequestComplete: invalid RIL_Token");
return;
}
if (pRI->local > 0) {
// Locally issued command...void only!
// response does not go back up the command socket
LOGD("C[locl]< %s", requestToString(pRI->pCI->requestNumber));
goto done;
}
appendPrintBuf("[%04d]< %s",pRI->token, requestToString(pRI->pCI->requestNumber));
if (pRI->cancelled == 0) {
Parcel p;
p.writeInt32 (RESPONSE_SOLICITED);
p.writeInt32 (pRI->token);
errorOffset = p.dataPosition();
p.writeInt32 (e);
if (response != NULL) {
// there is a response payload, no matter success or not.
ret = pRI->pCI->responseFunction(p, response, responselen);
/* if an error occurred, rewind and mark it */
if (ret != 0) {
p.setDataPosition(errorOffset);
p.writeInt32 (ret);
}
}
if (e != RIL_E_SUCCESS) {
appendPrintBuf("%s fails by %s", printBuf, failCauseToString(e));
}
if (s_fdCommand < 0) {
LOGD ("RIL onRequestComplete: Command channel closed");
}
sendResponse(p);
}
done:
free(pRI);
}
通过调用responseXXX将底层响应传给客户进程
2.RIL_onUnsolicitedResponse
- extern "C" void RIL_onUnsolicitedResponse(int unsolResponse, void *data,
- size_t datalen)
- {
- int unsolResponseIndex;
- int ret;
- int64_t timeReceived = 0;
- bool shouldScheduleTimeout = false;
- if (s_registerCalled == 0) {
- // Ignore RIL_onUnsolicitedResponse before RIL_register
- LOGW("RIL_onUnsolicitedResponse called before RIL_register");
- return;
- }
- unsolResponseIndex = unsolResponse - RIL_UNSOL_RESPONSE_BASE;
- if ((unsolResponseIndex < 0)
- || (unsolResponseIndex >= (int32_t)NUM_ELEMS(s_unsolResponses))) {
- LOGE("unsupported unsolicited response code %d", unsolResponse);
- return;
- }
- // Grab a wake lock if needed for this reponse,
- // as we exit we'll either release it immediately
- // or set a timer to release it later.
- switch (s_unsolResponses[unsolResponseIndex].wakeType) {
- case WAKE_PARTIAL:
- grabPartialWakeLock();
- shouldScheduleTimeout = true;
- break;
- case DONT_WAKE:
- default:
- // No wake lock is grabed so don't set timeout
- shouldScheduleTimeout = false;
- break;
- }
- // Mark the time this was received, doing this
- // after grabing the wakelock incase getting
- // the elapsedRealTime might cause us to goto
- // sleep.
- if (unsolResponse == RIL_UNSOL_NITZ_TIME_RECEIVED) {
- timeReceived = elapsedRealtime();
- }
- appendPrintBuf("[UNSL]< %s", requestToString(unsolResponse));
- Parcel p;
- p.writeInt32 (RESPONSE_UNSOLICITED);
- p.writeInt32 (unsolResponse);
- ret = s_unsolResponses[unsolResponseIndex].responseFunction(p, data, datalen);
- if (ret != 0) {
- // Problem with the response. Don't continue;
- goto error_exit;
- }
- // some things get more payload
- switch(unsolResponse) {
- case RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED:
- p.writeInt32(s_callbacks.onStateRequest());
- appendPrintBuf("%s {%s}", printBuf,
- radioStateToString(s_callbacks.onStateRequest()));
- break;
- case RIL_UNSOL_NITZ_TIME_RECEIVED:
- // Store the time that this was received so the
- // handler of this message can account for
- // the time it takes to arrive and process. In
- // particular the system has been known to sleep
- // before this message can be processed.
- p.writeInt64(timeReceived);
- break;
- }
- ret = sendResponse(p);
- if (ret != 0 && unsolResponse == RIL_UNSOL_NITZ_TIME_RECEIVED) {
- // Unfortunately, NITZ time is not poll/update like everything
- // else in the system. So, if the upstream client isn't connected,
- // keep a copy of the last NITZ response (with receive time noted
- // above) around so we can deliver it when it is connected
- if (s_lastNITZTimeData != NULL) {
- free (s_lastNITZTimeData);
- s_lastNITZTimeData = NULL;
- }
- s_lastNITZTimeData = malloc(p.dataSize());
- s_lastNITZTimeDataSize = p.dataSize();
- memcpy(s_lastNITZTimeData, p.data(), p.dataSize());
- }
- // For now, we automatically go back to sleep after TIMEVAL_WAKE_TIMEOUT
- // FIXME The java code should handshake here to release wake lock
- if (shouldScheduleTimeout) {
- // Cancel the previous request
- if (s_last_wake_timeout_info != NULL) {
- s_last_wake_timeout_info->userParam = (void *)1;
- }
- s_last_wake_timeout_info= internalRequestTimedCallback(wakeTimeoutCallback, NULL,
- &TIMEVAL_WAKE_TIMEOUT);
- }
- return;
- error_exit:
- if (shouldScheduleTimeout) {
- releaseWakeLock();
- }
- }
extern "C" void RIL_onUnsolicitedResponse(int unsolResponse, void *data,
size_t datalen)
{
int unsolResponseIndex;
int ret;
int64_t timeReceived = 0;
bool shouldScheduleTimeout = false;
if (s_registerCalled == 0) {
// Ignore RIL_onUnsolicitedResponse before RIL_register
LOGW("RIL_onUnsolicitedResponse called before RIL_register");
return;
}
unsolResponseIndex = unsolResponse - RIL_UNSOL_RESPONSE_BASE;
if ((unsolResponseIndex < 0)
|| (unsolResponseIndex >= (int32_t)NUM_ELEMS(s_unsolResponses))) {
LOGE("unsupported unsolicited response code %d", unsolResponse);
return;
}
// Grab a wake lock if needed for this reponse,
// as we exit we'll either release it immediately
// or set a timer to release it later.
switch (s_unsolResponses[unsolResponseIndex].wakeType) {
case WAKE_PARTIAL:
grabPartialWakeLock();
shouldScheduleTimeout = true;
break;
case DONT_WAKE:
default:
// No wake lock is grabed so don't set timeout
shouldScheduleTimeout = false;
break;
}
// Mark the time this was received, doing this
// after grabing the wakelock incase getting
// the elapsedRealTime might cause us to goto
// sleep.
if (unsolResponse == RIL_UNSOL_NITZ_TIME_RECEIVED) {
timeReceived = elapsedRealtime();
}
appendPrintBuf("[UNSL]< %s", requestToString(unsolResponse));
Parcel p;
p.writeInt32 (RESPONSE_UNSOLICITED);
p.writeInt32 (unsolResponse);
ret = s_unsolResponses[unsolResponseIndex].responseFunction(p, data, datalen);
if (ret != 0) {
// Problem with the response. Don't continue;
goto error_exit;
}
// some things get more payload
switch(unsolResponse) {
case RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED:
p.writeInt32(s_callbacks.onStateRequest());
appendPrintBuf("%s {%s}", printBuf,
radioStateToString(s_callbacks.onStateRequest()));
break;
case RIL_UNSOL_NITZ_TIME_RECEIVED:
// Store the time that this was received so the
// handler of this message can account for
// the time it takes to arrive and process. In
// particular the system has been known to sleep
// before this message can be processed.
p.writeInt64(timeReceived);
break;
}
ret = sendResponse(p);
if (ret != 0 && unsolResponse == RIL_UNSOL_NITZ_TIME_RECEIVED) {
// Unfortunately, NITZ time is not poll/update like everything
// else in the system. So, if the upstream client isn't connected,
// keep a copy of the last NITZ response (with receive time noted
// above) around so we can deliver it when it is connected
if (s_lastNITZTimeData != NULL) {
free (s_lastNITZTimeData);
s_lastNITZTimeData = NULL;
}
s_lastNITZTimeData = malloc(p.dataSize());
s_lastNITZTimeDataSize = p.dataSize();
memcpy(s_lastNITZTimeData, p.data(), p.dataSize());
}
// For now, we automatically go back to sleep after TIMEVAL_WAKE_TIMEOUT
// FIXME The java code should handshake here to release wake lock
if (shouldScheduleTimeout) {
// Cancel the previous request
if (s_last_wake_timeout_info != NULL) {
s_last_wake_timeout_info->userParam = (void *)1;
}
s_last_wake_timeout_info= internalRequestTimedCallback(wakeTimeoutCallback, NULL,
&TIMEVAL_WAKE_TIMEOUT);
}
return;
error_exit:
if (shouldScheduleTimeout) {
releaseWakeLock();
}
}
这个函数处理modem
从网络端接收到的各种事件,如网络信号变化,拨入的电话,收到短信等。然后传给客户进程。
3.RIL_requestTimedCallback
- extern "C" void RIL_requestTimedCallback (RIL_TimedCallback callback, void *param,
- const struct timeval *relativeTime) {
- internalRequestTimedCallback (callback, param, relativeTime);
- }
extern "C" void RIL_requestTimedCallback (RIL_TimedCallback callback, void *param,
const struct timeval *relativeTime) {
internalRequestTimedCallback (callback, param, relativeTime);
}
[cpp]
view plain
copy
- static UserCallbackInfo *internalRequestTimedCallback (RIL_TimedCallback callback, void *param,
- const struct timeval *relativeTime)
- {
- struct timeval myRelativeTime;
- UserCallbackInfo *p_info;
- p_info = (UserCallbackInfo *) malloc (sizeof(UserCallbackInfo));
- p_info->p_callback = callback;
- p_info->userParam = param;
- if (relativeTime == NULL) {
- /* treat null parameter as a 0 relative time */
- memset (&myRelativeTime, 0, sizeof(myRelativeTime));
- } else {
- /* FIXME I think event_add's tv param is really const anyway */
- memcpy (&myRelativeTime, relativeTime, sizeof(myRelativeTime));
- }
- ril_event_set(&(p_info->event), -1, false, userTimerCallback, p_info);
- ril_timer_add(&(p_info->event), &myRelativeTime);
- triggerEvLoop();
- return p_info;
- }
static UserCallbackInfo *internalRequestTimedCallback (RIL_TimedCallback callback, void *param,
const struct timeval *relativeTime)
{
struct timeval myRelativeTime;
UserCallbackInfo *p_info;
p_info = (UserCallbackInfo *) malloc (sizeof(UserCallbackInfo));
p_info->p_callback = callback;
p_info->userParam = param;
if (relativeTime == NULL) {
/* treat null parameter as a 0 relative time */
memset (&myRelativeTime, 0, sizeof(myRelativeTime));
} else {
/* FIXME I think event_add's tv param is really const anyway */
memcpy (&myRelativeTime, relativeTime, sizeof(myRelativeTime));
}
ril_event_set(&(p_info->event), -1, false, userTimerCallback, p_info);
ril_timer_add(&(p_info->event), &myRelativeTime);
triggerEvLoop();
return p_info;
}
RIL_RadioFunctions定义
客户端向Rild发送请求的接口,由各手机厂商实现。
hardware\ril\include\telephony\Ril.h
- typedef struct {
- int version; //Rild版本
- RIL_RequestFunc onRequest; //AP请求接口
- RIL_RadioStateRequest onStateRequest;//BP状态查询
- RIL_Supports supports;
- RIL_Cancel onCancel;
- RIL_GetVersion getVersion;//动态库版本
- } RIL_RadioFunctions;
typedef struct {
int version; //Rild版本
RIL_RequestFunc onRequest; //AP请求接口
RIL_RadioStateRequest onStateRequest;//BP状态查询
RIL_Supports supports;
RIL_Cancel onCancel;
RIL_GetVersion getVersion;//动态库版本
} RIL_RadioFunctions;
[cpp]
view plain
copy
- static const RIL_RadioFunctions s_callbacks = {
- RIL_VERSION,
- onRequest,
- currentState,
- onSupports,
- onCancel,
- getVersion
- };
static const RIL_RadioFunctions s_callbacks = {
RIL_VERSION,
onRequest,
currentState,
onSupports,
onCancel,
getVersion
};
在hardware\ril\reference-ril\reference-ril.c中实现了RIL_RadioFunctions的各个接口函数
1.onRequest
- static void onRequest (int request, voidvoid *data, size_t datalen, RIL_Token t)
- {
- ATResponse *p_response;
- int err;
- LOGD("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 (request) {
- case RIL_REQUEST_GET_SIM_STATUS: {
- RIL_CardStatus *p_card_status;
- charchar *p_buffer;
- int buffer_size;
- int result = getCardStatus(&p_card_status);
- if (result == RIL_E_SUCCESS) {
- p_buffer = (charchar *)p_card_status;
- buffer_size = sizeof(*p_card_status);
- } else {
- p_buffer = NULL;
- buffer_size = 0;
- }
- RIL_onRequestComplete(t, result, p_buffer, buffer_size);
- freeCardStatus(p_card_status);
- break;
- }
- case RIL_REQUEST_GET_CURRENT_CALLS:
- requestGetCurrentCalls(data, datalen, t);
- break;
- case RIL_REQUEST_DIAL:
- requestDial(data, datalen, t);
- break;
- case RIL_REQUEST_HANGUP:
- requestHangup(data, datalen, t);
- break;
- case RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND:
- // 3GPP 22.030 6.5.5
- // "Releases all held calls or sets User Determined User Busy
- // (UDUB) for a waiting call."
- at_send_command("AT+CHLD=0", NULL);
- /* 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);
- break;
- case RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND:
- // 3GPP 22.030 6.5.5
- // "Releases all active calls (if any exist) and accepts
- // the other (held or waiting) call."
- at_send_command("AT+CHLD=1", NULL);
- /* 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);
- break;
- case RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE:
- // 3GPP 22.030 6.5.5
- // "Places all active calls (if any exist) on hold and accepts
- // the other (held or waiting) call."
- at_send_command("AT+CHLD=2", NULL);
- #ifdef WORKAROUND_ERRONEOUS_ANSWER
- s_expectAnswer = 1;
- #endif /* WORKAROUND_ERRONEOUS_ANSWER */
- /* 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);
- break;
- case RIL_REQUEST_ANSWER:
- at_send_command("ATA", NULL);
- #ifdef WORKAROUND_ERRONEOUS_ANSWER
- s_expectAnswer = 1;
- #endif /* WORKAROUND_ERRONEOUS_ANSWER */
- /* 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);
- break;
- case RIL_REQUEST_CONFERENCE:
- // 3GPP 22.030 6.5.5
- // "Adds a held call to the conversation"
- at_send_command("AT+CHLD=3", NULL);
- /* 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);
- break;
- case RIL_REQUEST_UDUB:
- /* user determined user busy */
- /* sometimes used: ATH */
- at_send_command("ATH", NULL);
- /* 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);
- break;
- case RIL_REQUEST_SEPARATE_CONNECTION:
- {
- char cmd[12];
- int party = ((int*)data)[0];
- // Make sure that party is in a valid range.
- // (Note: The Telephony middle layer imposes a range of 1 to 7.
- // It's sufficient for us to just make sure it's single digit.)
- if (party > 0 && party < 10) {
- sprintf(cmd, "AT+CHLD=2%d", party);
- at_send_command(cmd, NULL);
- RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
- } else {
- RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
- }
- }
- break;
- case RIL_REQUEST_SIGNAL_STRENGTH:
- requestSignalStrength(data, datalen, t);
- break;
- case RIL_REQUEST_REGISTRATION_STATE:
- case RIL_REQUEST_GPRS_REGISTRATION_STATE:
- requestRegistrationState(request, data, datalen, t);
- break;
- case RIL_REQUEST_OPERATOR:
- requestOperator(data, datalen, t);
- break;
- case RIL_REQUEST_RADIO_POWER:
- requestRadioPower(data, datalen, t);
- break;
- case RIL_REQUEST_DTMF: {
- char c = ((charchar *)data)[0];
- charchar *cmd;
- asprintf(&cmd, "AT+VTS=%c", (int)c);
- at_send_command(cmd, NULL);
- free(cmd);
- RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
- break;
- }
- case RIL_REQUEST_SEND_SMS:
- requestSendSMS(data, datalen, t);
- break;
- case RIL_REQUEST_SETUP_DATA_CALL:
- requestSetupDataCall(data, datalen, t);
- break;
- case RIL_REQUEST_SMS_ACKNOWLEDGE:
- requestSMSAcknowledge(data, datalen, t);
- break;
- case RIL_REQUEST_GET_IMSI:
- p_response = NULL;
- err = at_send_command_numeric("AT+CIMI", &p_response);
- if (err < 0 || p_response->success == 0) {
- RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
- } else {
- RIL_onRequestComplete(t, RIL_E_SUCCESS,
- p_response->p_intermediates->line, sizeof(charchar *));
- }
- at_response_free(p_response);
- break;
- case RIL_REQUEST_GET_IMEI:
- p_response = NULL;
- err = at_send_command_numeric("AT+CGSN", &p_response);
- if (err < 0 || p_response->success == 0) {
- RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
- } else {
- RIL_onRequestComplete(t, RIL_E_SUCCESS,
- p_response->p_intermediates->line, sizeof(charchar *));
- }
- at_response_free(p_response);
- break;
- case RIL_REQUEST_SIM_IO:
- requestSIM_IO(data,datalen,t);
- break;
- case RIL_REQUEST_SEND_USSD:
- requestSendUSSD(data, datalen, t);
- break;
- case RIL_REQUEST_CANCEL_USSD:
- p_response = NULL;
- err = at_send_command_numeric("AT+CUSD=2", &p_response);
- if (err < 0 || p_response->success == 0) {
- RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
- } else {
- RIL_onRequestComplete(t, RIL_E_SUCCESS,
- p_response->p_intermediates->line, sizeof(charchar *));
- }
- at_response_free(p_response);
- break;
- case RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC:
- at_send_command("AT+COPS=0", NULL);
- break;
- case RIL_REQUEST_DATA_CALL_LIST:
- requestDataCallList(data, datalen, t);
- break;
- case RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE:
- requestQueryNetworkSelectionMode(data, datalen, t);
- break;
- case RIL_REQUEST_OEM_HOOK_RAW:
- // echo back data
- RIL_onRequestComplete(t, RIL_E_SUCCESS, data, datalen);
- break;
- case RIL_REQUEST_OEM_HOOK_STRINGS: {
- int i;
- const charchar ** cur;
- LOGD("got OEM_HOOK_STRINGS: 0x%8p %lu", data, (long)datalen);
- for (i = (datalen / sizeof (charchar *)), cur = (const charchar **)data ;
- i > 0 ; cur++, i --) {
- LOGD("> '%s'", *cur);
- }
- // echo back strings
- RIL_onRequestComplete(t, RIL_E_SUCCESS, data, datalen);
- break;
- }
- case RIL_REQUEST_WRITE_SMS_TO_SIM:
- requestWriteSmsToSim(data, datalen, t);
- break;
- case RIL_REQUEST_DELETE_SMS_ON_SIM: {
- charchar * cmd;
- p_response = NULL;
- asprintf(&cmd, "AT+CMGD=%d", ((intint *)data)[0]);
- err = at_send_command(cmd, &p_response);
- free(cmd);
- if (err < 0 || p_response->success == 0) {
- RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
- } else {
- RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
- }
- at_response_free(p_response);
- break;
- }
- case RIL_REQUEST_ENTER_SIM_PIN:
- case RIL_REQUEST_ENTER_SIM_PUK:
- case RIL_REQUEST_ENTER_SIM_PIN2:
- case RIL_REQUEST_ENTER_SIM_PUK2:
- case RIL_REQUEST_CHANGE_SIM_PIN:
- case RIL_REQUEST_CHANGE_SIM_PIN2:
- requestEnterSimPin(data, datalen, t);
- break;
- case RIL_REQUEST_GSM_SMS_BROADCAST_ACTIVATION:
- requestSmsBroadcastActivation(0,data, datalen, t);
- break;
- case RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG:
- LOGD("onRequest RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG");
- requestSetSmsBroadcastConfig(0,data, datalen, t);
- break;
- case RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG:
- requestGetSmsBroadcastConfig(0,data, datalen, t);
- break;
- default:
- RIL_onRequestComplete(t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0);
- break;
- }
- }
static void onRequest (int request, void *data, size_t datalen, RIL_Token t)
{
ATResponse *p_response;
int err;
LOGD("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 (request) {
case RIL_REQUEST_GET_SIM_STATUS: {
RIL_CardStatus *p_card_status;
char *p_buffer;
int buffer_size;
int result = getCardStatus(&p_card_status);
if (result == RIL_E_SUCCESS) {
p_buffer = (char *)p_card_status;
buffer_size = sizeof(*p_card_status);
} else {
p_buffer = NULL;
buffer_size = 0;
}
RIL_onRequestComplete(t, result, p_buffer, buffer_size);
freeCardStatus(p_card_status);
break;
}
case RIL_REQUEST_GET_CURRENT_CALLS:
requestGetCurrentCalls(data, datalen, t);
break;
case RIL_REQUEST_DIAL:
requestDial(data, datalen, t);
break;
case RIL_REQUEST_HANGUP:
requestHangup(data, datalen, t);
break;
case RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND:
// 3GPP 22.030 6.5.5
// "Releases all held calls or sets User Determined User Busy
// (UDUB) for a waiting call."
at_send_command("AT+CHLD=0", NULL);
/* 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);
break;
case RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND:
// 3GPP 22.030 6.5.5
// "Releases all active calls (if any exist) and accepts
// the other (held or waiting) call."
at_send_command("AT+CHLD=1", NULL);
/* 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);
break;
case RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE:
// 3GPP 22.030 6.5.5
// "Places all active calls (if any exist) on hold and accepts
// the other (held or waiting) call."
at_send_command("AT+CHLD=2", NULL);
#ifdef WORKAROUND_ERRONEOUS_ANSWER
s_expectAnswer = 1;
#endif /* WORKAROUND_ERRONEOUS_ANSWER */
/* 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);
break;
case RIL_REQUEST_ANSWER:
at_send_command("ATA", NULL);
#ifdef WORKAROUND_ERRONEOUS_ANSWER
s_expectAnswer = 1;
#endif /* WORKAROUND_ERRONEOUS_ANSWER */
/* 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);
break;
case RIL_REQUEST_CONFERENCE:
// 3GPP 22.030 6.5.5
// "Adds a held call to the conversation"
at_send_command("AT+CHLD=3", NULL);
/* 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);
break;
case RIL_REQUEST_UDUB:
/* user determined user busy */
/* sometimes used: ATH */
at_send_command("ATH", NULL);
/* 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);
break;
case RIL_REQUEST_SEPARATE_CONNECTION:
{
char cmd[12];
int party = ((int*)data)[0];
// Make sure that party is in a valid range.
// (Note: The Telephony middle layer imposes a range of 1 to 7.
// It's sufficient for us to just make sure it's single digit.)
if (party > 0 && party < 10) {
sprintf(cmd, "AT+CHLD=2%d", party);
at_send_command(cmd, NULL);
RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
} else {
RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
}
}
break;
case RIL_REQUEST_SIGNAL_STRENGTH:
requestSignalStrength(data, datalen, t);
break;
case RIL_REQUEST_REGISTRATION_STATE:
case RIL_REQUEST_GPRS_REGISTRATION_STATE:
requestRegistrationState(request, data, datalen, t);
break;
case RIL_REQUEST_OPERATOR:
requestOperator(data, datalen, t);
break;
case RIL_REQUEST_RADIO_POWER:
requestRadioPower(data, datalen, t);
break;
case RIL_REQUEST_DTMF: {
char c = ((char *)data)[0];
char *cmd;
asprintf(&cmd, "AT+VTS=%c", (int)c);
at_send_command(cmd, NULL);
free(cmd);
RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
break;
}
case RIL_REQUEST_SEND_SMS:
requestSendSMS(data, datalen, t);
break;
case RIL_REQUEST_SETUP_DATA_CALL:
requestSetupDataCall(data, datalen, t);
break;
case RIL_REQUEST_SMS_ACKNOWLEDGE:
requestSMSAcknowledge(data, datalen, t);
break;
case RIL_REQUEST_GET_IMSI:
p_response = NULL;
err = at_send_command_numeric("AT+CIMI", &p_response);
if (err < 0 || p_response->success == 0) {
RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
} else {
RIL_onRequestComplete(t, RIL_E_SUCCESS,
p_response->p_intermediates->line, sizeof(char *));
}
at_response_free(p_response);
break;
case RIL_REQUEST_GET_IMEI:
p_response = NULL;
err = at_send_command_numeric("AT+CGSN", &p_response);
if (err < 0 || p_response->success == 0) {
RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
} else {
RIL_onRequestComplete(t, RIL_E_SUCCESS,
p_response->p_intermediates->line, sizeof(char *));
}
at_response_free(p_response);
break;
case RIL_REQUEST_SIM_IO:
requestSIM_IO(data,datalen,t);
break;
case RIL_REQUEST_SEND_USSD:
requestSendUSSD(data, datalen, t);
break;
case RIL_REQUEST_CANCEL_USSD:
p_response = NULL;
err = at_send_command_numeric("AT+CUSD=2", &p_response);
if (err < 0 || p_response->success == 0) {
RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
} else {
RIL_onRequestComplete(t, RIL_E_SUCCESS,
p_response->p_intermediates->line, sizeof(char *));
}
at_response_free(p_response);
break;
case RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC:
at_send_command("AT+COPS=0", NULL);
break;
case RIL_REQUEST_DATA_CALL_LIST:
requestDataCallList(data, datalen, t);
break;
case RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE:
requestQueryNetworkSelectionMode(data, datalen, t);
break;
case RIL_REQUEST_OEM_HOOK_RAW:
// echo back data
RIL_onRequestComplete(t, RIL_E_SUCCESS, data, datalen);
break;
case RIL_REQUEST_OEM_HOOK_STRINGS: {
int i;
const char ** cur;
LOGD("got OEM_HOOK_STRINGS: 0x%8p %lu", data, (long)datalen);
for (i = (datalen / sizeof (char *)), cur = (const char **)data ;
i > 0 ; cur++, i --) {
LOGD("> '%s'", *cur);
}
// echo back strings
RIL_onRequestComplete(t, RIL_E_SUCCESS, data, datalen);
break;
}
case RIL_REQUEST_WRITE_SMS_TO_SIM:
requestWriteSmsToSim(data, datalen, t);
break;
case RIL_REQUEST_DELETE_SMS_ON_SIM: {
char * cmd;
p_response = NULL;
asprintf(&cmd, "AT+CMGD=%d", ((int *)data)[0]);
err = at_send_command(cmd, &p_response);
free(cmd);
if (err < 0 || p_response->success == 0) {
RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
} else {
RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
}
at_response_free(p_response);
break;
}
case RIL_REQUEST_ENTER_SIM_PIN:
case RIL_REQUEST_ENTER_SIM_PUK:
case RIL_REQUEST_ENTER_SIM_PIN2:
case RIL_REQUEST_ENTER_SIM_PUK2:
case RIL_REQUEST_CHANGE_SIM_PIN:
case RIL_REQUEST_CHANGE_SIM_PIN2:
requestEnterSimPin(data, datalen, t);
break;
case RIL_REQUEST_GSM_SMS_BROADCAST_ACTIVATION:
requestSmsBroadcastActivation(0,data, datalen, t);
break;
case RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG:
LOGD("onRequest RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG");
requestSetSmsBroadcastConfig(0,data, datalen, t);
break;
case RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG:
requestGetSmsBroadcastConfig(0,data, datalen, t);
break;
default:
RIL_onRequestComplete(t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0);
break;
}
}
每一个RIL_REQUEST_XXX
请求转化成相应的
ATcommand
,发送给
modem
,然后睡眠等待,当收到
ATcommand
的最终响应后,线程被唤醒,将响应传给客户端进程。
- static int onSupports (int requestCode)
- {
- //@@@ todo
- return 1;
- }
由于各手机厂商的AT指令差异,因此与modem交互层需要各手机厂商实现,以动态库的形式提供。作为介于modem与上层的中间层,即要与底层交互也要与上层通信,因此就需要定义一个接口来衔接RILD与动态库,RIL_Env和RIL_RadioFunctions接口就是libril.so与librefrence.so通信的桥梁。是Rild架构中用于隔离通用代码和厂商代码的接口,RIL_Env由通用代码实现,而RIL_RadioFunctions则是由厂商代码实现。
RIL_Init的主要任务:
1. 向librefrence.so注册libril.so提供的接口RIL_Env;
2. 创建一个mainLoop工作线程,用于初始化AT模块,并监控AT模块的状态,一旦AT被关闭,则重新打开并初始化AT;
3. 当AT被打开后,mainLoop工作线程将向Rild提交一个定时事件,并触发eventLoop来完成对modem的初始化;
4. 创建一个readLoop工作线程,用于从AT串口中读取数据;
5.返回librefrence.so提供的接口RIL_RadioFunctions;
hardware\ril\reference-ril\reference-ril.c
- const RIL_RadioFunctions *RIL_Init(const struct RIL_Env *env, int argc, charchar **argv)
- {
- int ret;
- int fd = -1;
- int opt;
- pthread_attr_t attr;
- s_rilenv = env; //将ril.cpp中定义的RIL_Env注册到reference-ril.c中的s_rilenv
- while ( -1 != (opt = getopt(argc, argv, "p:d:s:"))) {
- switch (opt) {
- case 'p':
- s_port = atoi(optarg);
- if (s_port == 0) {
- usage(argv[0]);
- return NULL;
- }
- LOGI("Opening loopback port %d\n", s_port);
- break;
- case 'd':
- s_device_path = optarg;
- LOGI("Opening tty device %s\n", s_device_path);
- break;
- case 's':
- s_device_path = optarg;
- s_device_socket = 1;
- LOGI("Opening socket %s\n", s_device_path);
- break;
- default:
- usage(argv[0]);
- return NULL;
- }
- }
- if (s_port < 0 && s_device_path == NULL) {
- usage(argv[0]);
- return NULL;
- }
- pthread_attr_init (&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- //创建一个mainLoop线程
- ret = pthread_create(&s_tid_mainloop, &attr, mainLoop, NULL);
- //将reference-ril.c中定义的RIL_RadioFunctions返回并注册到ril.cpp中的s_callbacks
- return &s_callbacks;
- }
const RIL_RadioFunctions *RIL_Init(const struct RIL_Env *env, int argc, char **argv)
{
int ret;
int fd = -1;
int opt;
pthread_attr_t attr;
s_rilenv = env; //将ril.cpp中定义的RIL_Env注册到reference-ril.c中的s_rilenv
while ( -1 != (opt = getopt(argc, argv, "p:d:s:"))) {
switch (opt) {
case 'p':
s_port = atoi(optarg);
if (s_port == 0) {
usage(argv[0]);
return NULL;
}
LOGI("Opening loopback port %d\n", s_port);
break;
case 'd':
s_device_path = optarg;
LOGI("Opening tty device %s\n", s_device_path);
break;
case 's':
s_device_path = optarg;
s_device_socket = 1;
LOGI("Opening socket %s\n", s_device_path);
break;
default:
usage(argv[0]);
return NULL;
}
}
if (s_port < 0 && s_device_path == NULL) {
usage(argv[0]);
return NULL;
}
pthread_attr_init (&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
//创建一个mainLoop线程
ret = pthread_create(&s_tid_mainloop, &attr, mainLoop, NULL);
//将reference-ril.c中定义的RIL_RadioFunctions返回并注册到ril.cpp中的s_callbacks
return &s_callbacks;
}
mainLoop
工作线程是用来初始化并监控
AT
模块的,一旦
AT
模块被关闭,就自动打开。
- static voidvoid * mainLoop(voidvoid *param)
- {
- int fd;
- int ret;
- AT_DUMP("== ", "entering mainLoop()", -1 );
- //为AT模块设置回调函数
- at_set_on_reader_closed(onATReaderClosed);
- at_set_on_timeout(onATTimeout);
- for (;;) {
- fd = -1;
- while (fd < 0) { //获得串口AT模块的设备文件描述符
- 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")) {
- /* Qemu-specific control socket */
- fd = socket_local_client( "qemud",
- ANDROID_SOCKET_NAMESPACE_RESERVED,SOCK_STREAM );
- if (fd >= 0 ) {
- char answer[2];
- if ( write(fd, "gsm", 3) != 3 ||read(fd, answer, 2) != 2 ||
- memcmp(answer, "OK", 2) != 0)
- {
- close(fd);
- fd = -1;
- }
- }
- }
- else
- fd = socket_local_client( s_device_path, ANDROID_SOCKET_NAMESPACE_FILESYSTEM,SOCK_STREAM );
- } else if (s_device_path != NULL) {
- fd = open (s_device_path, O_RDWR);
- if ( fd >= 0 && !memcmp( s_device_path, "/dev/ttyS", 9 ) ) {
- /* disable echo on serial ports */
- struct termios ios;
- tcgetattr( fd, &ios );
- ios.c_lflag = 0; /* disable ECHO, ICANON, etc... */
- tcsetattr( fd, TCSANOW, &ios );
- }
- }
- if (fd < 0) {
- perror ("opening AT interface. retrying...");
- sleep(10);
- }
- }
- s_closed = 0;
- //打开AT模块,创建AT读取线程s_tid_reader,fd为modem设备文件句柄
- ret = at_open(fd, onUnsolicited);
- if (ret < 0) {
- LOGE ("AT error %d on at_open\n", ret);
- return 0;
- }
- //向Rild提交超时任务
- RIL_requestTimedCallback(initializeCallback, NULL, &TIMEVAL_0);
- sleep(1);
- //如果AT模块被关闭,则waitForClose返回,重新打开AT,如果AT已打开,则阻塞
- waitForClose();
- LOGI("Re-opening after close");
- }
- }
static void * mainLoop(void *param)
{
int fd;
int ret;
AT_DUMP("== ", "entering mainLoop()", -1 );
//为AT模块设置回调函数
at_set_on_reader_closed(onATReaderClosed);
at_set_on_timeout(onATTimeout);
for (;;) {
fd = -1;
while (fd < 0) { //获得串口AT模块的设备文件描述符
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")) {
/* Qemu-specific control socket */
fd = socket_local_client( "qemud",
ANDROID_SOCKET_NAMESPACE_RESERVED,SOCK_STREAM );
if (fd >= 0 ) {
char answer[2];
if ( write(fd, "gsm", 3) != 3 ||read(fd, answer, 2) != 2 ||
memcmp(answer, "OK", 2) != 0)
{
close(fd);
fd = -1;
}
}
}
else
fd = socket_local_client( s_device_path, ANDROID_SOCKET_NAMESPACE_FILESYSTEM,SOCK_STREAM );
} else if (s_device_path != NULL) {
fd = open (s_device_path, O_RDWR);
if ( fd >= 0 && !memcmp( s_device_path, "/dev/ttyS", 9 ) ) {
/* disable echo on serial ports */
struct termios ios;
tcgetattr( fd, &ios );
ios.c_lflag = 0; /* disable ECHO, ICANON, etc... */
tcsetattr( fd, TCSANOW, &ios );
}
}
if (fd < 0) {
perror ("opening AT interface. retrying...");
sleep(10);
}
}
s_closed = 0;
//打开AT模块,创建AT读取线程s_tid_reader,fd为modem设备文件句柄
ret = at_open(fd, onUnsolicited);
if (ret < 0) {
LOGE ("AT error %d on at_open\n", ret);
return 0;
}
//向Rild提交超时任务
RIL_requestTimedCallback(initializeCallback, NULL, &TIMEVAL_0);
sleep(1);
//如果AT模块被关闭,则waitForClose返回,重新打开AT,如果AT已打开,则阻塞
waitForClose();
LOGI("Re-opening after close");
}
}
1.打开AT模块
通过at_open打开文件描述符为fd的AT串口设备,并注册回调函数ATUnsolHandler
- int at_open(int fd, ATUnsolHandler h)
- {
- int ret;
- 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;
- /* Android power control ioctl */
- #ifdef HAVE_ANDROID_OS
- #ifdef OMAP_CSMI_POWER_CONTROL
- ret = ioctl(fd, OMAP_CSMI_TTY_ENABLE_ACK);
- if(ret == 0) {
- int ack_count;
- int read_count;
- int old_flags;
- char sync_buf[256];
- old_flags = fcntl(fd, F_GETFL, 0);
- fcntl(fd, F_SETFL, old_flags | O_NONBLOCK);
- do {
- ioctl(fd, OMAP_CSMI_TTY_READ_UNACKED, &ack_count);
- read_count = 0;
- do {
- ret = read(fd, sync_buf, sizeof(sync_buf));
- if(ret > 0)
- read_count += ret;
- } while(ret > 0 || (ret < 0 && errno == EINTR));
- ioctl(fd, OMAP_CSMI_TTY_ACK, &ack_count);
- } while(ack_count > 0 || read_count > 0);
- fcntl(fd, F_SETFL, old_flags);
- s_readCount = 0;
- s_ackPowerIoctl = 1;
- }
- else
- s_ackPowerIoctl = 0;
- #else // OMAP_CSMI_POWER_CONTROL
- s_ackPowerIoctl = 0;
- #endif // OMAP_CSMI_POWER_CONTROL
- #endif /*HAVE_ANDROID_OS*/
- pthread_attr_init (&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- //创建readerLoop工作线程,该线程用于从串口读取数据
- ret = pthread_create(&s_tid_reader, &attr, readerLoop, &attr);
- if (ret < 0) {
- perror ("pthread_create");
- return -1;
- }
- return 0;
- }
int at_open(int fd, ATUnsolHandler h)
{
int ret;
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;
/* Android power control ioctl */
#ifdef HAVE_ANDROID_OS
#ifdef OMAP_CSMI_POWER_CONTROL
ret = ioctl(fd, OMAP_CSMI_TTY_ENABLE_ACK);
if(ret == 0) {
int ack_count;
int read_count;
int old_flags;
char sync_buf[256];
old_flags = fcntl(fd, F_GETFL, 0);
fcntl(fd, F_SETFL, old_flags | O_NONBLOCK);
do {
ioctl(fd, OMAP_CSMI_TTY_READ_UNACKED, &ack_count);
read_count = 0;
do {
ret = read(fd, sync_buf, sizeof(sync_buf));
if(ret > 0)
read_count += ret;
} while(ret > 0 || (ret < 0 && errno == EINTR));
ioctl(fd, OMAP_CSMI_TTY_ACK, &ack_count);
} while(ack_count > 0 || read_count > 0);
fcntl(fd, F_SETFL, old_flags);
s_readCount = 0;
s_ackPowerIoctl = 1;
}
else
s_ackPowerIoctl = 0;
#else // OMAP_CSMI_POWER_CONTROL
s_ackPowerIoctl = 0;
#endif // OMAP_CSMI_POWER_CONTROL
#endif /*HAVE_ANDROID_OS*/
pthread_attr_init (&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
//创建readerLoop工作线程,该线程用于从串口读取数据
ret = pthread_create(&s_tid_reader, &attr, readerLoop, &attr);
if (ret < 0) {
perror ("pthread_create");
return -1;
}
return 0;
}
2.
添加定时事件RIL_requestTimedCallback
- RIL_requestTimedCallback(initializeCallback, NULL, &TIMEVAL_0);
- #define RIL_requestTimedCallback(a,b,c) s_rilenv->RequestTimedCallback(a,b,c)
RIL_requestTimedCallback(initializeCallback, NULL, &TIMEVAL_0);
#define RIL_requestTimedCallback(a,b,c) s_rilenv->RequestTimedCallback(a,b,c)
向定时事件队列中添加一个定时事件,该事件的处理函数为initializeCallback,用于发送一些AT
指令来初始化
BP
的
modem
。
3.readLoop工作线程
Read loop 解析从Modem 发过来的回应。如果遇到URC 则通过handleUnsolicited 上报的RIL_JAVA。如果是命令的应答,则通过handleFinalResponse 通知send_at_command 有应答结果。
注册RIL_RadioFunctions接口
hardware\ril\libril\ril.cpp
- extern "C" void RIL_register (const RIL_RadioFunctions *callbacks) {
- int ret;
- int flags;
- //版本验证
- if (callbacks == NULL || ((callbacks->version != RIL_VERSION)&& (callbacks->version < 2))) {
- return;
- }
- if (callbacks->version < RIL_VERSION) {
- LOGE ("RIL_register: upgrade RIL to version %d current version=%d",
- RIL_VERSION, callbacks->version);
- }
- if (s_registerCalled > 0) {
- LOGE("RIL_register has been called more than once. "Subsequent call ignored");
- return;
- }
- //将reference-ril.c中定义的RIL_RadioFunctions注册到ril.cpp中
- memcpy(&s_callbacks, callbacks, sizeof (RIL_RadioFunctions));
- s_registerCalled = 1;
- 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);
- }
- // old standalone impl wants it here.
- if (s_started == 0) {
- RIL_startEventLoop();
- }
- // 得到名为rild的socket句柄
- s_fdListen = android_get_control_socket(SOCKET_NAME_RIL);
- if (s_fdListen < 0) {
- LOGE("Failed to get socket '" SOCKET_NAME_RIL "'");
- exit(-1);
- }
- // 监听该socket
- ret = listen(s_fdListen, 4);
- if (ret < 0) {
- LOGE("Failed to listen on control socket '%d': %s",s_fdListen, strerror(errno));
- exit(-1);
- }
- /* 设置s_listen_event事件,一旦有客户端连接,即s_fdListen可读就会导致eventLoop工作线程中的select返回,因为该事件不是持久的,因此调用为listenCallback处理完后,将从watch_table移除该事件,所以Rild只支持一个客户端连接*/
- ril_event_set (&s_listen_event, s_fdListen, false,listenCallback, NULL);
- /* 添加s_listen_event事件,并触发eventLoop工作线程 */
- rilEventAddWakeup (&s_listen_event);
- #if 1
- // 得到调试socket的句柄rild-debug
- s_fdDebug = android_get_control_socket(SOCKET_NAME_RIL_DEBUG);
- if (s_fdDebug < 0) {
- LOGE("Failed to get socket '" SOCKET_NAME_RIL_DEBUG "' errno:%d", errno);
- exit(-1);
- }
- //监听该socket
- ret = listen(s_fdDebug, 4);
- if (ret < 0) {
- LOGE("Failed to listen on ril debug socket '%d': %s",s_fdDebug, strerror(errno));
- exit(-1);
- }
- /* 设置s_debug_event事件 */
- ril_event_set (&s_debug_event, s_fdDebug, true,debugCallback, NULL);
- /* 添加s_debug_event事件,并触发eventLoop工作线程 */
- rilEventAddWakeup (&s_debug_event);
- #endif
- }
extern "C" void RIL_register (const RIL_RadioFunctions *callbacks) {
int ret;
int flags;
//版本验证
if (callbacks == NULL || ((callbacks->version != RIL_VERSION)&& (callbacks->version < 2))) {
return;
}
if (callbacks->version < RIL_VERSION) {
LOGE ("RIL_register: upgrade RIL to version %d current version=%d",
RIL_VERSION, callbacks->version);
}
if (s_registerCalled > 0) {
LOGE("RIL_register has been called more than once. "Subsequent call ignored");
return;
}
//将reference-ril.c中定义的RIL_RadioFunctions注册到ril.cpp中
memcpy(&s_callbacks, callbacks, sizeof (RIL_RadioFunctions));
s_registerCalled = 1;
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);
}
// old standalone impl wants it here.
if (s_started == 0) {
RIL_startEventLoop();
}
// 得到名为rild的socket句柄
s_fdListen = android_get_control_socket(SOCKET_NAME_RIL);
if (s_fdListen < 0) {
LOGE("Failed to get socket '" SOCKET_NAME_RIL "'");
exit(-1);
}
// 监听该socket
ret = listen(s_fdListen, 4);
if (ret < 0) {
LOGE("Failed to listen on control socket '%d': %s",s_fdListen, strerror(errno));
exit(-1);
}
/* 设置s_listen_event事件,一旦有客户端连接,即s_fdListen可读就会导致eventLoop工作线程中的select返回,因为该事件不是持久的,因此调用为listenCallback处理完后,将从watch_table移除该事件,所以Rild只支持一个客户端连接*/
ril_event_set (&s_listen_event, s_fdListen, false,listenCallback, NULL);
/* 添加s_listen_event事件,并触发eventLoop工作线程 */
rilEventAddWakeup (&s_listen_event);
#if 1
// 得到调试socket的句柄rild-debug
s_fdDebug = android_get_control_socket(SOCKET_NAME_RIL_DEBUG);
if (s_fdDebug < 0) {
LOGE("Failed to get socket '" SOCKET_NAME_RIL_DEBUG "' errno:%d", errno);
exit(-1);
}
//监听该socket
ret = listen(s_fdDebug, 4);
if (ret < 0) {
LOGE("Failed to listen on ril debug socket '%d': %s",s_fdDebug, strerror(errno));
exit(-1);
}
/* 设置s_debug_event事件 */
ril_event_set (&s_debug_event, s_fdDebug, true,debugCallback, NULL);
/* 添加s_debug_event事件,并触发eventLoop工作线程 */
rilEventAddWakeup (&s_debug_event);
#endif
}
打开监听端口,接收来自客户端进程的命令请求,当与客户进程连接建立时调用listenCallback
函数,创建单独线程监视并处理所有事件源。
1.客户端连接处理
s_listen_event事件用于处理上层客户端的socket连接,当得到socket连接请求时,eventLoop工作线程里的select返回并自动调用listenCallback回调函数进行处理:
- tatic void listenCallback (int fd, short flags, void *param) {
- int ret;
- int err;
- int is_phone_socket;
- RecordStream *p_rs;
- commthread_data_t *user_data = NULL;
- user_data =(commthread_data_t *)malloc(sizeof(commthread_data_t));
- struct sockaddr_un peeraddr;
- socklen_t socklen = sizeof (peeraddr);
- struct ucred creds;
- socklen_t szCreds = sizeof(creds);
- struct passwd *pwd = NULL;
- assert (s_fdCommand < 0);
- assert (fd == s_fdListen);
- //接收一个客户端的连接,并将该socket连接保存在变量s_fdCommand中
- s_fdCommand = accept(s_fdListen, (sockaddr *) &peeraddr, &socklen);
- if (s_fdCommand < 0 ) {
- LOGE("Error on accept() errno:%d", errno);
- /* start listening for new connections again */
- rilEventAddWakeup(&s_listen_event);
- return;
- }
- /* 对客户端权限判断,判断是否是进程组ID为radio的进程发起的连接*/
- errno = 0;
- is_phone_socket = 0;
- err = getsockopt(s_fdCommand, SOL_SOCKET, SO_PEERCRED, &creds, &szCreds);
- if (err == 0 && szCreds > 0) {
- errno = 0;
- pwd = getpwuid(creds.uid);
- if (pwd != NULL) {
- if (strcmp(pwd->pw_name, PHONE_PROCESS) == 0) {
- is_phone_socket = 1;
- } else {
- LOGE("RILD can't accept socket from process %s", pwd->pw_name);
- }
- } else {
- LOGE("Error on getpwuid() errno: %d", errno);
- }
- } else {
- LOGD("Error on getsockopt() errno: %d", errno);
- }
- if ( !is_phone_socket ) {
- LOGE("RILD must accept socket from %s", PHONE_PROCESS);
- close(s_fdCommand);
- s_fdCommand = -1;
- onCommandsSocketClosed();
- /* start listening for new connections again */
- rilEventAddWakeup(&s_listen_event);
- return;
- }
- #if 0
- if(s_dualSimMode) {
- if(s_sim_num == 0) {
- property_get(SIM_POWER_PROPERTY, prop, "0");
- if(!strcmp(prop, "0")) {
- property_set(SIM_POWER_PROPERTY, "1");
- s_callbacks.powerSIM(NULL);
- }
- } else if(s_sim_num == 1) {
- property_get(SIM_POWER_PROPERTY1, prop, "0");
- if(!strcmp(prop, "0")) {
- property_set(SIM_POWER_PROPERTY1, "1");
- s_callbacks.powerSIM(NULL);
- }
- }
- } else {
- property_get(SIM_POWER_PROPERTY, prop, "0");
- if(!strcmp(prop, "0")) {
- property_set(SIM_POWER_PROPERTY, "1");
- s_callbacks.powerSIM(NULL);
- }
- }
- #endif
- //p_rs为RecordStream类型,它内部会分配一个缓冲区来存储客户端发送过来的数据
- p_rs = record_stream_new(s_fdCommand, MAX_COMMAND_BYTES);
- //添加一个针对接收到的客户端连接的处理事件,从而在eventLoop工作线程中处理该客户端的各种请求
- ril_event_set (&s_commands_event, s_fdCommand, 1,processCommandsCallback, p_rs);
- rilEventAddWakeup (&s_commands_event);
- onNewCommandConnect();
- }
tatic void listenCallback (int fd, short flags, void *param) {
int ret;
int err;
int is_phone_socket;
RecordStream *p_rs;
commthread_data_t *user_data = NULL;
user_data =(commthread_data_t *)malloc(sizeof(commthread_data_t));
struct sockaddr_un peeraddr;
socklen_t socklen = sizeof (peeraddr);
struct ucred creds;
socklen_t szCreds = sizeof(creds);
struct passwd *pwd = NULL;
assert (s_fdCommand < 0);
assert (fd == s_fdListen);
//接收一个客户端的连接,并将该socket连接保存在变量s_fdCommand中
s_fdCommand = accept(s_fdListen, (sockaddr *) &peeraddr, &socklen);
if (s_fdCommand < 0 ) {
LOGE("Error on accept() errno:%d", errno);
/* start listening for new connections again */
rilEventAddWakeup(&s_listen_event);
return;
}
/* 对客户端权限判断,判断是否是进程组ID为radio的进程发起的连接*/
errno = 0;
is_phone_socket = 0;
err = getsockopt(s_fdCommand, SOL_SOCKET, SO_PEERCRED, &creds, &szCreds);
if (err == 0 && szCreds > 0) {
errno = 0;
pwd = getpwuid(creds.uid);
if (pwd != NULL) {
if (strcmp(pwd->pw_name, PHONE_PROCESS) == 0) {
is_phone_socket = 1;
} else {
LOGE("RILD can't accept socket from process %s", pwd->pw_name);
}
} else {
LOGE("Error on getpwuid() errno: %d", errno);
}
} else {
LOGD("Error on getsockopt() errno: %d", errno);
}
if ( !is_phone_socket ) {
LOGE("RILD must accept socket from %s", PHONE_PROCESS);
close(s_fdCommand);
s_fdCommand = -1;
onCommandsSocketClosed();
/* start listening for new connections again */
rilEventAddWakeup(&s_listen_event);
return;
}
#if 0
if(s_dualSimMode) {
if(s_sim_num == 0) {
property_get(SIM_POWER_PROPERTY, prop, "0");
if(!strcmp(prop, "0")) {
property_set(SIM_POWER_PROPERTY, "1");
s_callbacks.powerSIM(NULL);
}
} else if(s_sim_num == 1) {
property_get(SIM_POWER_PROPERTY1, prop, "0");
if(!strcmp(prop, "0")) {
property_set(SIM_POWER_PROPERTY1, "1");
s_callbacks.powerSIM(NULL);
}
}
} else {
property_get(SIM_POWER_PROPERTY, prop, "0");
if(!strcmp(prop, "0")) {
property_set(SIM_POWER_PROPERTY, "1");
s_callbacks.powerSIM(NULL);
}
}
#endif
//p_rs为RecordStream类型,它内部会分配一个缓冲区来存储客户端发送过来的数据
p_rs = record_stream_new(s_fdCommand, MAX_COMMAND_BYTES);
//添加一个针对接收到的客户端连接的处理事件,从而在eventLoop工作线程中处理该客户端的各种请求
ril_event_set (&s_commands_event, s_fdCommand, 1,processCommandsCallback, p_rs);
rilEventAddWakeup (&s_commands_event);
onNewCommandConnect();
}
2.客户端通信处理
在listenCallback中首先接收客户端的连接请求,并验证客户端的权限,同时将该客户端以事件的形式添加到eventLoop工作线程中进行监控,当该客户端有数据请求时,eventLoop工作线程从select中返回,并自动调用processCommandsCallback回调函数:
- static void processCommandsCallback(int fd, short flags, void *param) {
- RecordStream *p_rs;
- void *p_record;
- size_t recordlen;
- int ret;
- assert(fd == s_fdCommand);
- p_rs = (RecordStream *)param;
- for (;;) { //循环处理客户端发送过来的AT命令
- //读取一条AT命令
- ret = record_stream_get_next(p_rs, &p_record, &recordlen);
- if (ret == 0 && p_record == NULL) {
- break;
- } else if (ret < 0) {
- break;
- } else if (ret == 0) { /* && p_record != NULL */
- //处理客户端发送过来的AT命令
- processCommandBuffer(p_record, recordlen);
- }
- }
- if (ret == 0 || !(errno == EAGAIN || errno == EINTR)) {
- if (ret != 0) {
- LOGE("error on reading command socket errno:%d\n", errno);
- } else {
- LOGW("EOS. Closing command socket.");
- }
- close(s_fdCommand);
- s_fdCommand = -1;
- ril_event_del(&s_commands_event);
- record_stream_free(p_rs);
- rilEventAddWakeup(&s_listen_event);
- onCommandsSocketClosed();
- }
- }
static void processCommandsCallback(int fd, short flags, void *param) {
RecordStream *p_rs;
void *p_record;
size_t recordlen;
int ret;
assert(fd == s_fdCommand);
p_rs = (RecordStream *)param;
for (;;) { //循环处理客户端发送过来的AT命令
//读取一条AT命令
ret = record_stream_get_next(p_rs, &p_record, &recordlen);
if (ret == 0 && p_record == NULL) {
break;
} else if (ret < 0) {
break;
} else if (ret == 0) { /* && p_record != NULL */
//处理客户端发送过来的AT命令
processCommandBuffer(p_record, recordlen);
}
}
if (ret == 0 || !(errno == EAGAIN || errno == EINTR)) {
if (ret != 0) {
LOGE("error on reading command socket errno:%d\n", errno);
} else {
LOGW("EOS. Closing command socket.");
}
close(s_fdCommand);
s_fdCommand = -1;
ril_event_del(&s_commands_event);
record_stream_free(p_rs);
rilEventAddWakeup(&s_listen_event);
onCommandsSocketClosed();
}
}
通过processCommandBuffer函数来处理每一条AT
命令:
- static int processCommandBuffer(void *buffer, size_t buflen) {
- Parcel p;
- status_t status;
- int32_t request;
- int32_t token;
- RequestInfo *pRI;
- int ret;
- p.setData((uint8_t *) buffer, buflen);
- // status checked at end
- status = p.readInt32(&request);
- status = p.readInt32 (&token);
- if (status != NO_ERROR) {
- LOGE("invalid request block");
- return 0;
- }
- if (request < 1 || request >= (int32_t)NUM_ELEMS(s_commands)) {
- LOGE("unsupported request code %d token %d", request, token);
- return 0;
- }
- pRI = (RequestInfo *)calloc(1, sizeof(RequestInfo));
- pRI->token = token; //AT命令标号
- pRI->pCI = &(s_commands[request]); //根据request找到s_commands命令数组中的指定AT命令
- ret = pthread_mutex_lock(&s_pendingRequestsMutex);
- assert (ret == 0);
- pRI->p_next = s_pendingRequests;
- s_pendingRequests = pRI;
- ret = pthread_mutex_unlock(&s_pendingRequestsMutex);
- assert (ret == 0);
- //调用指定AT命令的dispatch函数,根据接收来自客户进程的命令和参数,调用onRequest进行处理。
- pRI->pCI->dispatchFunction(p, pRI);
- return 0;
- }
static int processCommandBuffer(void *buffer, size_t buflen) {
Parcel p;
status_t status;
int32_t request;
int32_t token;
RequestInfo *pRI;
int ret;
p.setData((uint8_t *) buffer, buflen);
// status checked at end
status = p.readInt32(&request);
status = p.readInt32 (&token);
if (status != NO_ERROR) {
LOGE("invalid request block");
return 0;
}
if (request < 1 || request >= (int32_t)NUM_ELEMS(s_commands)) {
LOGE("unsupported request code %d token %d", request, token);
return 0;
}
pRI = (RequestInfo *)calloc(1, sizeof(RequestInfo));
pRI->token = token; //AT命令标号
pRI->pCI = &(s_commands[request]); //根据request找到s_commands命令数组中的指定AT命令
ret = pthread_mutex_lock(&s_pendingRequestsMutex);
assert (ret == 0);
pRI->p_next = s_pendingRequests;
s_pendingRequests = pRI;
ret = pthread_mutex_unlock(&s_pendingRequestsMutex);
assert (ret == 0);
//调用指定AT命令的dispatch函数,根据接收来自客户进程的命令和参数,调用onRequest进行处理。
pRI->pCI->dispatchFunction(p, pRI);
return 0;
}
打电话的AT
命令:{
RIL_REQUEST_DIAL,
dispatchDial,
responseVoid},
发短信的AT命令:{RIL_REQUEST_SEND_SMS, dispatchStrings, responseSMS},
3.电话拨打流程
- static void dispatchDial (Parcel &p, RequestInfo *pRI) {
- RIL_Dial dial; //RIL_Dial存储了打电话的所有信息
- RIL_UUS_Info uusInfo;
- int32_t sizeOfDial;
- int32_t t;
- .................. //初始化dial变量
- s_callbacks.onRequest(pRI->pCI->requestNumber, &dial, sizeOfDial, pRI);
- .................
- return;
- }
static void dispatchDial (Parcel &p, RequestInfo *pRI) {
RIL_Dial dial; //RIL_Dial存储了打电话的所有信息
RIL_UUS_Info uusInfo;
int32_t sizeOfDial;
int32_t t;
.................. //初始化dial变量
s_callbacks.onRequest(pRI->pCI->requestNumber, &dial, sizeOfDial, pRI);
.................
return;
}
s_callbacks.onRequest
其实就是调用
RIL_RadioFunctions中的
onRequest
函数,该函数在前面已介绍过了。
- static void onRequest (int request, void *data, size_t datalen, RIL_Token t)
- {
- switch (request) {
- case RIL_REQUEST_DIAL:
- requestDial(data, datalen, t);
- break;
- }
- }
static void onRequest (int request, void *data, size_t datalen, RIL_Token t)
{
switch (request) {
case RIL_REQUEST_DIAL:
requestDial(data, datalen, t);
break;
}
}
- static void requestDial(void *data, size_t datalen, 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*/
- }
- //向串口发送AT指令
- ret = at_send_command(cmd, NULL);
- free(cmd);
- //通知请求结果
- RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
- }
static void requestDial(void *data, size_t datalen, 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*/
}
//向串口发送AT指令
ret = at_send_command(cmd, NULL);
free(cmd);
//通知请求结果
RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
}
向
AT
发送完拨号指令后,通过RIL_onRequestComplete返回处理结果,RIL_onRequestComplete实际上是RIL_Env中的
OnRequestComplete函数,在前面我们也介绍过了
- extern "C" void RIL_onRequestComplete(RIL_Token t, RIL_Errno e, void *response, size_t responselen) {
- RequestInfo *pRI;
- int ret;
- size_t errorOffset;
- pRI = (RequestInfo *)t;
- //该请求已经处理,需要从请求队列中移除该请求
- if (!checkAndDequeueRequestInfo(pRI)) {
- LOGE ("RIL_onRequestComplete: invalid RIL_Token");
- return;
- }
- if (pRI->local > 0) {
- ...........
- sendResponse(p);
- }
- done:
- free(pRI);
- }
extern "C" void RIL_onRequestComplete(RIL_Token t, RIL_Errno e, void *response, size_t responselen) {
RequestInfo *pRI;
int ret;
size_t errorOffset;
pRI = (RequestInfo *)t;
//该请求已经处理,需要从请求队列中移除该请求
if (!checkAndDequeueRequestInfo(pRI)) {
LOGE ("RIL_onRequestComplete: invalid RIL_Token");
return;
}
if (pRI->local > 0) {
...........
sendResponse(p);
}
done:
free(pRI);
}
[cpp]
view plain
copy
- static int sendResponse (Parcel &p) {
- return sendResponseRaw(p.data(), p.dataSize()); //将结果发送给JAVA RIL客户端
- }
static int sendResponse (Parcel &p) {
return sendResponseRaw(p.data(), p.dataSize()); //将结果发送给JAVA RIL客户端
}
[cpp]
view plain
copy
- static int sendResponseRaw (const void *data, size_t dataSize) {
- int fd = s_fdCommand;
- int ret;
- uint32_t header;
- if (s_fdCommand < 0) {
- return -1;
- }
- if (dataSize > MAX_COMMAND_BYTES) {
- return -1;
- }
- pthread_mutex_lock(&s_writeMutex);
- header = htonl(dataSize);
- ret = blockingWrite(fd, (void *)&header, sizeof(header));
- if (ret < 0) {
- pthread_mutex_unlock(&s_writeMutex);
- return ret;
- }
- ret = blockingWrite(fd, data, dataSize);
- if (ret < 0) {
- pthread_mutex_unlock(&s_writeMutex);
- return ret;
- }
- pthread_mutex_unlock(&s_writeMutex);
- return 0;
- }
static int sendResponseRaw (const void *data, size_t dataSize) {
int fd = s_fdCommand;
int ret;
uint32_t header;
if (s_fdCommand < 0) {
return -1;
}
if (dataSize > MAX_COMMAND_BYTES) {
return -1;
}
pthread_mutex_lock(&s_writeMutex);
header = htonl(dataSize);
ret = blockingWrite(fd, (void *)&header, sizeof(header));
if (ret < 0) {
pthread_mutex_unlock(&s_writeMutex);
return ret;
}
ret = blockingWrite(fd, data, dataSize);
if (ret < 0) {
pthread_mutex_unlock(&s_writeMutex);
return ret;
}
pthread_mutex_unlock(&s_writeMutex);
return 0;
}
拨打电话的时序图如下:
Rild通过onRequest向动态库提交一个请求,然后返回,动态库处理完请求后,处理结果通过回调接口通知客户端