androoid framework学习之 - android RIL
1. RIL简单介绍:
RIL------RadioInterface Layer,RIL是Android 的无线接口层.负责提供电话服务.是上层应用和下层硬件modem之间的中间层。
2.在RIL.Java里如何和HAL层交换数据
交换数据都分为两种:发送和接收,下面先讲下自己今天学习的发送:
以RIL_REQUEST_UDUB(拒接电话)这个事件为例:
l 在RIL.Java中
@Override
public void
rejectCall (Message result) {
RILRequest rr
= RILRequest.obtain(RIL_REQUEST_UDUB, result);
if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
send(rr);
}
l 在HAL层接收消息:
Reference-ril.c中:
static void
onRequest (int request, void *data, size_t datalen, RIL_Token t)
{
.............................
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;
.............................
}
那以上就是一个拒绝接电话的建东RIL实现,那看完上面这个肯定会有很多疑问:
1. 一个是.java文件、一个是.c文件,他们是怎么连接消息的?----简单来说是用socket来进行通信的,具体会例外开一篇文章来说。
2. 为什么会调用onRequest函数呢,它是一直在跑还是回调函数呢?
对于这个问题,他是回调函数。那下面来看下整个过程:
1.从Rild.c开始:
int main(int argc, char **argv)
{
.............
RIL_startEventLoop();//创建客户端事件监听线程
..................
rilInit = (const RIL_RadioFunctions *(*)(const struct RIL_Env *, int, char **))dlsym(dlHandle, "RIL_Init");
//通过dlsym定位到RIL_Init函数的地址,并且强制转换为RIL_RadioFunctions的函数指针
...........................
/*这个地方s_rilEnv虽然名字与RIL_init的一样,但是二者只作用于当前文件,
//目前这个文件对s_rilEnv结构体进行赋值了,也就是对应了
static struct RIL_Env s_rilEnv = {底层-------->上层
RIL_onRequestComplete,
RIL_onUnsolicitedResponse,
RIL_requestTimedCallback
};
然后再将这个结构体指针赋给RIL_init里面的Env,相当于将底层的返回通知的接口注册好
*/
funcs = rilInit(&s_rilEnv, argc, rilArgv);//ril初始化,通过传过来的参数获取硬件接口设备文件,该函数在Reference_ril.c里面
//******调用RIL_Init函数来初始化rild,传入参数s_rilEnv,返回RIL_RadioFunctions地址
RLOGD("RIL_Init rilInit completed"?;
RIL_register(funcs);//将s_fdListen加入消息队列中,开始s_fdListen时间监听,librefrence.so接口就是
//客事件处理接口RIL_RadioFunctions,并创建socket监听事件
/*将上层需要查询、设置的接口注册到底层,上层--------->底层
static const RIL_RadioFunctions s_callbacks = {
RIL_VERSION,
onRequest,////AP请求接口
currentState,//BP状态查询
onSupports,
onCancel,
getVersion//动态库版本
};
*/
.......................
}
2.这边先讲下RIL_init函数,在 hardware\ril\reference-ril\reference-ril.c
这里有两个很重要的结构RIL_Env和RIL_RadioFunctions,
//RIL_Env和RIL_RadioFunctions接口就是libril.so与librefrence.so通信的桥梁
//是Rild架构中用于隔离通用代码和厂商代码的接口,RIL_Env由通用代码实现,而RIL_RadioFunctions则是由厂商代码实现
//RIL_Env是libril.so提供的接口包含(完成quest后通知结果,电话来了的接口、延时接口)?
//底层给客户进程的接口
//RIL_Env和RIL_RadioFunctions接口就是libril.so与librefrence.so通信的桥梁
//是Rild架构中用于隔离通用代码和厂商代码的接口,RIL_Env由通用代码实现,而RIL_RadioFunctions则是由厂商代码实现
const RIL_RadioFunctions *RIL_Init(const struct RIL_Env *env, int argc, char **argv)
{
........................
s_rilenv = env;//将ril.cpp中定义的RIL_Env注册到reference-ril.c中的s_rilenv
..........................
pthread_attr_init (&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
ret = pthread_create(&s_tid_mainloop, &attr, mainLoop, NULL);
return &s_callbacks;//返回RIL_RadioFunctions结构
}
这边再看下
RIL_Env(有三种,完成framework时的通知OnRequestComplete、来电通知操作OnUnsolicitedResponse、延时操作RequestTimedCallback,都是由modern往上发的)和
RIL_RadioFunctions(响应framework下下来的消息,比如set/get等,都通过Onrequest来响应)这两个结构体:
在hardware\ril\reference-ril\Rild.c和hardware\ril\reference-ril\Rild.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, RIL_SOCKET_ID socket_id);
//延时操作
void (*RequestTimedCallback) (RIL_TimedCallback callback,
void *param, const struct timeval *relativeTime);
};
static struct RIL_Env s_rilEnv = {
RIL_onRequestComplete,
RIL_onUnsolicitedResponse,
RIL_requestTimedCallback
};
在hardware\ril\reference-ril\Rild.h
typedef struct {
int version; //Rild版本 /* set to RIL_VERSION */
RIL_RequestFunc onRequest; //AP请求接口
RIL_RadioStateRequest onStateRequest;//BP状态查询
RIL_Supports supports;
RIL_Cancel onCancel;
RIL_GetVersion getVersion;//动态库版本
} RIL_RadioFunctions;
在hardware\ril\reference-ril\reference-ril.c
/*** Static Variables ***///变量定义
//客户端向Rild发送请求的接口,由各手机厂商实现。
static const RIL_RadioFunctions s_callbacks = {
RIL_VERSION,
onRequest,////AP请求接口
currentState,//BP状态查询
onSupports,
onCancel,
getVersion//动态库版本
};
3.上面RIL_init返回了RIL_RadioFunctions结构体的指针,这个指针会在main函数里的funcs = rilInit(&s_rilEnv, argc, rilArgv); RIL_register(funcs);注册
4.看下RIL_register函数:
RIL_register (const RIL_RadioFunctions *callbacks) {
.......................
//将reference-ril.c中定义的RIL_RadioFunctions注册到ril.cpp中
memcpy(&s_callbacks, callbacks, sizeof (RIL_RadioFunctions));//注册事件处理接口
............................
这里就将
RIL_RadioFunctions赋给了s_callbacks全局指针
s_ril_param_socket = {
RIL_SOCKET_1, /* socket_id */
-1, /* fdListen */
-1, /* fdCommand */
PHONE_PROCESS, /* processName */
&s_commands_event, /* commands_event */
&s_listen_event, /* listen_event */
processCommandsCallback, /* processCommandsCallback */
NULL /* p_rs */
};
startListen(RIL_SOCKET_1, &s_ril_param_socket);////将s_listen_event事件加入到watch_table队列中 唤醒事件处理线程
这里是制定RIL_SOCKET_1的callback函数是processCommandsCallback,并且将其加入watch_table队列中。
5.然后就是startListen函数了:
static void startListen(RIL_SOCKET_ID socket_id, SocketListenParam* socket_listen_p) {
......................
fdListen = android_get_control_socket(socket_name);//在init.rc里面找同名的socket
...........................
socket_listen_p->fdListen = fdListen;
/* note: non-persistent so we can accept only one connection at a time */
//创建事件s_listen_event 监听和处理客户端请求
ril_event_set (socket_listen_p->listen_event, fdListen, false,
listenCallback, socket_listen_p);
//将s_listen_event事件加入到watch_table队列中 唤醒事件处理线程
rilEventAddWakeup (socket_listen_p->listen_event);
}
ril_event_set和rilEventAddWakeup二者结合就是将事件加入到watch_table队列中 唤醒事件处理线程。
那这个地方就有个一个疑问了,listenCallback这个callback函数什么时候执行呢?
来我来解释下:
6.在Ril.cpp中:
/*建立多路I/O驱动机制的消息队列,用来接收上层发出的命令以及往Modem发送AT指令的工作,
时整个RIL系统的核心部分。创建一个事件分发线程s_tid_dispatch,线程执行体为eventLoop。
*
*/
RIL_startEventLoop(void) {
/* spin up eventLoop thread and wait for it to get started */
//建eventLoop线程,直到被启动并将s_started置为1返回
s_started = 0;
pthread_mutex_lock(&s_startupMutex);//上锁
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
//创建一个工作线程eventLoop
int result = pthread_create(&s_tid_dispatch, &attr, eventLoop, NULL);
//确保函数返回前eventLoop线程启动运行
if (result != 0) {
RLOGE("Failed to create dispatch thread: %s", strerror(result));
goto done;
}
//线程未启动 休眠等待……
while (s_started == 0) {
pthread_cond_wait(&s_startupCond, &s_startupMutex);
}
done:
pthread_mutex_unlock(&s_startupMutex);//解锁
}
static void *
eventLoop(void *param) {
int ret;
int filedes[2];
ril_event_init();//初始化请求队列
pthread_mutex_lock(&s_startupMutex);
s_started = 1; //eventLoop线程运行标志位
pthread_cond_broadcast(&s_startupCond);
pthread_mutex_unlock(&s_startupMutex);
//创建匿名管道
ret = pipe(filedes);
if (ret < 0) {
RLOGE("Error in pipe() errno:%d", errno);
return NULL;
}
s_fdWakeupRead = filedes[0];//s_fdWakeupRead为管道读端
s_fdWakeupWrite = filedes[1];//s_fdWakeupWrite为管道写端
fcntl(s_fdWakeupRead, F_SETFL, O_NONBLOCK);//设置管道读端为O_NONBLOCK非阻塞
//初始化s_wakeupfd_event结构体的内容,句柄为s_fdWakeupRead,回调函数为 processWakeupCallback
ril_event_set (&s_wakeupfd_event, s_fdWakeupRead, true,
processWakeupCallback, NULL);
rilEventAddWakeup (&s_wakeupfd_event);
// Only returns on error
ril_event_loop();///处理事件
RLOGE ("error in event_loop_base errno:%d", errno);
// kill self to restart on error
kill(0, SIGKILL);
return NULL;
}
void ril_event_loop()//开启ril_event_loop()循环,监听上层发来的request命令
{
int n;
fd_set rfds;
struct timeval tv;
struct timeval * ptv;
//这里一直在跑,所以当select有时间到来时select返回,否则阻塞
/*
当select返回时,表示有事件的到来,通过调用processTimeouts函数来处理超时事件,
处理方式是遍历time_list链表以查询超时事件,并将超时事件移入到pending_list链表中,
接着调用processReadReadies函数来处理触发的事件,处理方式为遍历watch_table列表以查询触发的事件,
并将触发的事件移入到pending_list链表中,如果该事件不是持久事件,还需要从watch_table列表中移除,
当查询完两种待处理的事件并放入到pending_list链表中后,调用firePending函数对待处理的事件进行集中处理,
处理方式为遍历链表,
调用每一个事件的回调函数。
*/
for (;;) {
// make local copy of read fd_set
memcpy(&rfds, &readFds, sizeof(fd_set));
if (-1 == calcNextTimeout(&tv)) {
// no pending timers; block indefinitely
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);//判断readfds是否有变化
printReadies(&rfds);
dlog("~~~~ %d events fired ~~~~", n);
if (n < 0) {
if (errno == EINTR) continue;
RLOGE("ril_event: select error (%d)", errno);
// bail?
return;
}
// Check for timeouts
processTimeouts();//从timer_list中查询执行时间已到的事件,并添加到pending_list中
// Check for read-ready
processReadReadies(&rfds, n);//从watch_table中查询数据可读的事件,并添加到pending_list中去处理,
//如果该事件不是持久事件,则同时从watch_table中删除
// Fire away
firePending();//遍历pending_list,调用事件处理回调函数处理所有事件
}
}
那在这里有个select函数,他是用于判断当前消息是否有变化,判断rfds,从该函数中可以看出,这个取决于readFds,那
void ril_event_init()
{
MUTEX_INIT();
FD_ZERO(&readFds);//初始化为0
init_list(&timer_list);
init_list(&pending_list);
memset(watch_table, 0, sizeof(watch_table));
}
// Add event to watch list
void ril_event_add(struct ril_event * ev)
{
dlog("~~~~ +ril_event_add ~~~~");
MUTEX_ACQUIRE();
for (int i = 0; i < MAX_FD_EVENTS; i++) {
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);
if (ev->fd >= nfds) nfds = ev->fd+1;
dlog("~~~~ nfds = %d ~~~~", nfds);
break;
}
}
MUTEX_RELEASE();
dlog("~~~~ -ril_event_add ~~~~");
}
你看这个就是在ril_event_add时和事件建立关系的。
所以processTimeouts();//从timer_list中查询执行时间已到的事件,并添加到pending_list中 ,processReadReadies(&rfds, n);//从watch_table中查询数据可读的事件,并添加到pending_list中去处理?,
firePending();//遍历pending_list,调用事件处理回调函数处理所有事件,所以这里就会调用startListen里绑定 ril_event_set (socket_listen_p->listen_event, fdListen, false,
listenCallback, socket_listen_p);中的listenCallback函数。
7.listenCallback函数:
s_listen_event事件用于处理上层客户端的socket连接,当得到socket连接请求时,eventLoop工作线程里的select返回并自动调用listenCallback回调函数进行处理:
//准备读取ril-Java发来的request
static void listenCallback (int fd, short flags, void *param) {
int ret;
int err;
int is_phone_socket;
int fdCommand = -1;
RecordStream *p_rs;
SocketListenParam *p_info = (SocketListenParam *)param;
struct sockaddr_un peeraddr;
socklen_t socklen = sizeof (peeraddr);
struct ucred creds;
socklen_t szCreds = sizeof(creds);
struct passwd *pwd = NULL;
assert (*p_info->fdCommand < 0);
assert (fd == *p_info->fdListen);
//监听socket连接
fdCommand = accept(fd, (sockaddr *) &peeraddr, &socklen);
if (fdCommand < 0 ) {
RLOGE("Error on accept() errno:%d", errno);
/* start listening for new connections again */
rilEventAddWakeup(p_info->listen_event);
return;
}
/* check the credential of the other side and only accept socket from
* phone process
*/
errno = 0;
is_phone_socket = 0;
//判断是否是PHONE_PROCESS 连接 否则返回
err = getsockopt(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, p_info->processName) == 0) {
is_phone_socket = 1;
} else {
RLOGE("RILD can't accept socket from process %s", pwd->pw_name);
}
} else {
RLOGE("Error on getpwuid() errno: %d", errno);
}
} else {
RLOGD("Error on getsockopt() errno: %d", errno);
}
if (!is_phone_socket) {
RLOGE("RILD must accept socket from %s", p_info->processName);
close(fdCommand);
fdCommand = -1;
onCommandsSocketClosed(p_info->socket_id);
/* start listening for new connections again */
rilEventAddWakeup(p_info->listen_event);
return;
}
ret = fcntl(fdCommand, F_SETFL, O_NONBLOCK);
if (ret < 0) {
RLOGE ("Error setting O_NONBLOCK errno:%d", errno);
}
RLOGI("libril: new connection to %s", rilSocketIdToString(p_info->socket_id));
p_info->fdCommand = fdCommand;
p_rs = record_stream_new(p_info->fdCommand, MAX_COMMAND_BYTES);
p_info->p_rs = p_rs;
ril_event_set (p_info->commands_event, p_info->fdCommand, 1,//创建事件commands_event 处理socket请求
p_info->processCommandsCallback, p_info);
//这里将之前与RIL_SOCKET_1绑定的processCommandsCallback 通过ril_event_add加入到watch_table中
//该列表会在ril_event_loop通过select函数判断是否有变化,如果有变化,则通过firePending
//调用该event的callback函数
rilEventAddWakeup (p_info->commands_event);
onNewCommandConnect(p_info->socket_id);//通知客户端已建立连接
//对命令进行解析和处理
static void processCommandsCallback(int fd, short flags, void *param) {
RecordStream *p_rs;
void *p_record;
size_t recordlen;
int ret;
SocketListenParam *p_info = (SocketListenParam *)param;
assert(fd == p_info->fdCommand);
p_rs = p_info->p_rs;
for (;;) {
/* loop until EAGAIN/EINTR, end of stream, or other error */
ret = record_stream_get_next(p_rs, &p_record, &recordlen);
if (ret == 0 && p_record == NULL) {
/* end-of-stream */
break;
} else if (ret < 0) {
break;
} else if (ret == 0) { /* && p_record != NULL */
processCommandBuffer(p_record, recordlen, p_info->socket_id);
}
}
if (ret == 0 || !(errno == EAGAIN || errno == EINTR)) {
/* fatal error or end-of-stream */
if (ret != 0) {
RLOGE("error on reading command socket errno:%d\n", errno);
} else {
RLOGW("EOS. Closing command socket.");
}
close(fd);
p_info->fdCommand = -1;
ril_event_del(p_info->commands_event);
record_stream_free(p_rs);
/* start listening for new connections again */
rilEventAddWakeup(&s_listen_event);
onCommandsSocketClosed(p_info->socket_id);
}
}
打开监听端口,接收来自客户端进程的命令请求,当与客户进程连接建立时调用listenCallback函数,创建单独线程监视并处理所有事件源。
1.客户端连接处理
s_listen_event事件用于处理上层客户端的socket连接,当得到socket连接请求时,eventLoop工作线程里的select返回并自动调用listenCallback回调函数进行处理: