androoid framework学习之 - RILd启动过程和如何接收framwork层的消息流程

本文详细探讨了Android RIL(Radio Interface Layer)的工作原理,包括RIL与HAL层的数据交换,RIL_request_UDUB事件的处理,以及RILd的启动过程。文章解释了RILd如何通过socket通信与Java层交互,着重分析了RIL_register函数、startListen函数以及listenCallback回调函数在接收和处理框架层消息的角色。此外,还介绍了客户端连接的处理机制,包括权限判断和socket连接的建立。

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回调函数进行处理:

[cpp]  view plain  copy
  1. tatic void listenCallback (int fd, short flags, void *param) {  
  2.     int ret;  
  3.     int err;  
  4.     int is_phone_socket;  
  5.     RecordStream *p_rs;  
  6.     commthread_data_t *user_data = NULL;  
  7.     user_data =(commthread_data_t *)malloc(sizeof(commthread_data_t));  
  8.     struct sockaddr_un peeraddr;  
  9.     socklen_t socklen = sizeof (peeraddr);  
  10.     struct ucred creds;  
  11.     socklen_t szCreds = sizeof(creds);  
  12.     struct passwd *pwd = NULL;  
  13.     assert (s_fdCommand < 0);  
  14.   assert (fd == s_fdListen);  
  15.   //接收一个客户端的连接,并将该socket连接保存在变量s_fdCommand中  
  16.     s_fdCommand = accept(s_fdListen, (sockaddr *) &peeraddr, &socklen);  
  17.     if (s_fdCommand < 0 ) {  
  18.         LOGE("Error on accept() errno:%d", errno);  
  19.         /* start listening for new connections again */  
  20.         rilEventAddWakeup(&s_listen_event);  
  21.           return;  
  22.     }  
  23.     /* 对客户端权限判断,判断是否是进程组ID为radio的进程发起的连接*/  
  24.     errno = 0;  
  25.     is_phone_socket = 0;  
  26.     err = getsockopt(s_fdCommand, SOL_SOCKET, SO_PEERCRED, &creds, &szCreds);  
  27.     if (err == 0 && szCreds > 0) {  
  28.         errno = 0;  
  29.         pwd = getpwuid(creds.uid);  
  30.         if (pwd != NULL) {  
  31.             if (strcmp(pwd->pw_name, PHONE_PROCESS) == 0) {  
  32.                 is_phone_socket = 1;  
  33.             } else {  
  34.                 LOGE("RILD can't accept socket from process %s", pwd->pw_name);  
  35.             }  
  36.         } else {  
  37.             LOGE("Error on getpwuid() errno: %d", errno);  
  38.         }  
  39.     } else {  
  40.         LOGD("Error on getsockopt() errno: %d", errno);  
  41.     }  
  42.       
  43.     if ( !is_phone_socket ) {  
  44.       LOGE("RILD must accept socket from %s", PHONE_PROCESS);  
  45.       close(s_fdCommand);  
  46.       s_fdCommand = -1;  
  47.       onCommandsSocketClosed();  
  48.       /* start listening for new connections again */  
  49.       rilEventAddWakeup(&s_listen_event);  
  50.       return;  
  51.     }  
  52. #if 0  
  53.     if(s_dualSimMode) {  
  54.         if(s_sim_num == 0) {  
  55.             property_get(SIM_POWER_PROPERTY, prop, "0");  
  56.             if(!strcmp(prop, "0")) {  
  57.                 property_set(SIM_POWER_PROPERTY, "1");  
  58.                 s_callbacks.powerSIM(NULL);  
  59.             }  
  60.         } else if(s_sim_num == 1) {  
  61.             property_get(SIM_POWER_PROPERTY1, prop, "0");  
  62.             if(!strcmp(prop, "0")) {  
  63.                 property_set(SIM_POWER_PROPERTY1, "1");  
  64.                 s_callbacks.powerSIM(NULL);  
  65.             }  
  66.         }  
  67.     } else {  
  68.         property_get(SIM_POWER_PROPERTY, prop, "0");  
  69.         if(!strcmp(prop, "0")) {  
  70.             property_set(SIM_POWER_PROPERTY, "1");  
  71.             
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值