Android7.0 Rild工作流程

一、基于Rild的通信架构

一般智能手机的硬件架构都是两个处理器:
一个处理器用来运行操作系统,上面运行应用程序,这个处理器称作Application Processor,简称AP;另一个处理负责和射频无线通信相关的工作,叫Baseband Processor,简称BP。

Android系统中,Rild运行在AP上,它是AP和BP在软件层上通信的中枢。

目前通过Rild,AP和BP的通信方式可以分为两种:
第一种是AP发送请求给BP,BP响应并回复AP。此时,BP通过Rild回复的请求被称为solicited Response。
第二种是BP主动发送信息给AP。在这种情况下,BP通过Rild发送的请求被称为unsolicited Response。

基于Rild进程的整个通信架构,基本上如上图所示。
从图中我们可以看出:
1、Android框架部分,是通过Phone进程与Rild进程通信的。它们之间的通信方式采用的是socket。
在前面介绍PhoneApp启动时,我们知道Phone进程中有两个Phone对象。每个Phone对象持有一个socket,与对应的Rild进程通信。因此,我们知道手机中实际上启动了两个Rild进程(双卡手机)。

<code class="hljs avrasm has-numbering"><span class="hljs-label">shell:</span>/ $ ps | grep rild
radio     <span class="hljs-number">572</span>   <span class="hljs-number">1</span>     <span class="hljs-number">113732</span> <span class="hljs-number">14792</span> hrtimer_na <span class="hljs-number">0000000000</span> S /system/bin/rild
radio     <span class="hljs-number">869</span>   <span class="hljs-number">1</span>     <span class="hljs-number">109604</span> <span class="hljs-number">13944</span> hrtimer_na <span class="hljs-number">0000000000</span> S /system/bin/rild

<span class="hljs-label">shell:</span>/ $ ps | grep phone
radio     <span class="hljs-number">2621</span>  <span class="hljs-number">605</span>   <span class="hljs-number">2019984</span> <span class="hljs-number">74424</span> SyS_epoll_ <span class="hljs-number">0000000000</span> S <span class="hljs-keyword">com</span><span class="hljs-preprocessor">.android</span><span class="hljs-preprocessor">.phone</span>

<span class="hljs-label">shell:</span>/ $ ps | grep init
root      <span class="hljs-number">1</span>     <span class="hljs-number">0</span>     <span class="hljs-number">9648</span>   <span class="hljs-number">1712</span>  SyS_epoll_ <span class="hljs-number">0000000000</span> S /init

<span class="hljs-label">shell:</span>/ $ ps | grep zygote
root      <span class="hljs-number">605</span>   <span class="hljs-number">1</span>     <span class="hljs-number">2195280</span> <span class="hljs-number">70956</span> poll_sched <span class="hljs-number">0000000000</span> S zygote64
root      <span class="hljs-number">606</span>   <span class="hljs-number">1</span>     <span class="hljs-number">1610708</span> <span class="hljs-number">59144</span> poll_sched <span class="hljs-number">0000000000</span> S zygote</code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li></ul>

我们通过usb连接手机后,通过adb shell进入终端,通过ps和grep命令,可以得到上述结果。
明显可以看到一个Phone进程对应者两个Rild进程;同时Rild进程由init进程加载,Phone进程由zygote进程加载。

2、Rild与BP之间并没有直接通信,而是引入了厂商的动态库。
这种设计应该是为了保证灵活性吧。
用面向对象的思想来看,我们可以认为Rild是一个接口,定义了AP、BP双向通信时需要使用的最基本的函数。不同的厂商都需要满足这个接口,以提供手机最基本的通信功能。
至于具体如何实现,是完全独立和自由的。

二、Rild的启动
在hardware/ril/rild/rild.rc中定义了Rild启动时对应的选项:

<code class="hljs livecodeserver has-numbering">service ril-daemon /<span class="hljs-keyword">system</span>/bin/rild
    class main
    <span class="hljs-built_in">socket</span> rild stream <span class="hljs-number">660</span> root radio
    <span class="hljs-built_in">socket</span> sap_uim_socket1 stream <span class="hljs-number">660</span> bluetooth bluetooth
    <span class="hljs-built_in">socket</span> rild-debug stream <span class="hljs-number">660</span> radio <span class="hljs-keyword">system</span>
    user root
    group radio cache inet misc audio <span class="hljs-built_in">log</span> readproc wakelock</code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li></ul>

在Android 7.0之前的版本中,该文件的内容是被定义在init.rc中的。
到了Android7.0 之后,init.rc文件中的许多内容均被移出,添加到各个进程中。如前面分析Vold进程时,对应的启动文件定义于vold.rc中。
个人猜测这些文件应该会在编译时,重新集成起来,毕竟在在rild对应的Android.mk中增加了下述字段:

<code class="hljs asciidoc has-numbering"><span class="hljs-code">.......
LOCAL_MODULE:= rild
LOCAL_MODULE_TAGS := optional
//新增字段
LOCAL_INIT_RC := rild.rc
.......</span></code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li></ul>

目前手边没有Android7.0的机器,还不好验证,以后有机会再做尝试。

init进程根据rild.rc文件启动一个Rild进程,还需要根据厂商定义的rc文件启动另一个Rild进程。
厂商定义的rc文件中,与Rild进程相关的主要内容与rild.rc相似,就是socket名称不同。对于第二个Rild进程,其socket名应该为rild2。

现在我们看看Rild进程的main函数,定义于rild.c中:

<code class="hljs objectivec has-numbering"><span class="hljs-keyword">int</span> main(<span class="hljs-keyword">int</span> argc, <span class="hljs-keyword">char</span> **argv) {
    <span class="hljs-comment">//rilLibPath用于指定动态库的位置</span>
    <span class="hljs-keyword">const</span> <span class="hljs-keyword">char</span> * rilLibPath = <span class="hljs-literal">NULL</span>;
    ........
    <span class="hljs-comment">//Rild规定动态库必须实现一个叫做Ril_init的函数,这个函数的第一个参数指向结构体RIL_Env</span>
    <span class="hljs-comment">//而它的返回值指向结构体RIL_RadioFunctions</span>
    <span class="hljs-keyword">const</span> RIL_RadioFunctions *(*rilInit)(<span class="hljs-keyword">const</span> <span class="hljs-keyword">struct</span> RIL_Env *, <span class="hljs-keyword">int</span>, <span class="hljs-keyword">char</span> **);
    ........
    <span class="hljs-keyword">const</span> RIL_RadioFunctions *funcs;
    <span class="hljs-keyword">char</span> libPath[PROPERTY_VALUE_MAX];
    <span class="hljs-comment">//解析参数</span>
    ........

    <span class="hljs-keyword">if</span> (strncmp(clientId, <span class="hljs-string">"0"</span>, MAX_CLIENT_ID_LENGTH)) {
        strlcat(rild, clientId, MAX_SOCKET_NAME_LENGTH);
        <span class="hljs-comment">//注意此处调用了ril.cpp中的函数,保存了Rild进程对应socket的名字,后文还会提到</span>
        RIL_setRilSocketName(rild);
    }

    <span class="hljs-keyword">if</span> (rilLibPath == <span class="hljs-literal">NULL</span>) {
        <span class="hljs-comment">//读取系统属性,LIB_PATH_PROPERTY的值为rild.libpath</span>
        <span class="hljs-comment">//原生的属性值定义于build/target/board/generic/system.prop文件中</span>
        <span class="hljs-comment">//实际的手机中将会使用厂商指定的system.prop文件</span>
        <span class="hljs-keyword">if</span> ( <span class="hljs-number">0</span> == property_get(LIB_PATH_PROPERTY, libPath, <span class="hljs-literal">NULL</span>)) {
            <span class="hljs-comment">// No lib sepcified on the command line, and nothing set in props.</span>
            <span class="hljs-comment">// Assume "no-ril" case.</span>
            <span class="hljs-keyword">goto</span> done;
        } <span class="hljs-keyword">else</span> {
            rilLibPath = libPath;
        }
    }
    ..........
    <span class="hljs-comment">//根据动态库位置,利用dlopen打开动态库</span>
    dlHandle = dlopen(rilLibPath, RTLD_NOW);
    ..........
    <span class="hljs-comment">//1、启动EventLoop,事件处理</span>
    RIL_startEventLoop()

    <span class="hljs-comment">//从动态库中的到RIL_Init函数的地址</span>
    rilInit =
        (<span class="hljs-keyword">const</span> RIL_RadioFunctions *(*)(<span class="hljs-keyword">const</span> <span class="hljs-keyword">struct</span> RIL_Env *, <span class="hljs-keyword">int</span>, <span class="hljs-keyword">char</span> **))
        dlsym(dlHandle, <span class="hljs-string">"RIL_Init"</span>);
    ......
    <span class="hljs-comment">//2、调用RIL_init函数</span>
    funcs = rilInit(&s_rilEnv, argc, rilArgv);
    RLOGD(<span class="hljs-string">"RIL_Init rilInit completed"</span>);

    <span class="hljs-comment">//3、注册funcs到Rild中</span>
    RIL_register(funcs);
    ........
done:

    RLOGD(<span class="hljs-string">"RIL_Init starting sleep loop"</span>);
    <span class="hljs-keyword">while</span> (<span class="hljs-literal">true</span>) {
        sleep(UINT32_MAX);
    }
}</code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li><li>42</li><li>43</li><li>44</li><li>45</li><li>46</li><li>47</li><li>48</li><li>49</li><li>50</li><li>51</li><li>52</li><li>53</li><li>54</li><li>55</li><li>56</li><li>57</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li><li>42</li><li>43</li><li>44</li><li>45</li><li>46</li><li>47</li><li>48</li><li>49</li><li>50</li><li>51</li><li>52</li><li>53</li><li>54</li><li>55</li><li>56</li><li>57</li></ul>

根据Rild的main函数,我们可以看出主要就进行了三件事:启动Event Loop、调用RIL_Init函数和注册库函数。
接下来我们分别分析一下主要事件对应的流程。

1、 RIL_startEventLoop
RIL_startEventLoop定义于hardware/ril/libril/ril.cpp中:

<code class="hljs lasso has-numbering">extern <span class="hljs-string">"C"</span> <span class="hljs-literal">void</span>
RIL_startEventLoop(<span class="hljs-literal">void</span>) {
    <span class="hljs-comment">/* spin up eventLoop thread and wait for it to get started */</span>
    s_started <span class="hljs-subst">=</span> <span class="hljs-number">0</span>;
    <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-attribute">...</span>
    <span class="hljs-comment">//创建工作线程,线程ID存入s_tid_dispatch,对应执行函数为eventLoop</span>
    int result <span class="hljs-subst">=</span> pthread_create(<span class="hljs-subst">&</span>s_tid_dispatch, <span class="hljs-subst">&</span>attr, eventLoop, <span class="hljs-built_in">NULL</span>);
    <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-attribute">...</span>
    <span class="hljs-comment">//工作线程eventLoop运行后,会设置s_started为1,并触发s_startupCond</span>
    <span class="hljs-comment">//这里的等待的目的是保证RIL_startEventLoop返回前,工作线程创建并运行成功</span>
    <span class="hljs-keyword">while</span> (s_started <span class="hljs-subst">==</span> <span class="hljs-number">0</span>) {
        pthread_cond_wait(<span class="hljs-subst">&</span>s_startupCond, <span class="hljs-subst">&</span>s_startupMutex);
    }
    <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-attribute">...</span>
}</code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li></ul>

我们需要跟进eventLoop函数:

<code class="hljs objectivec has-numbering"><span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> *
eventLoop(<span class="hljs-keyword">void</span> *param) {
    <span class="hljs-keyword">int</span> ret;
    <span class="hljs-keyword">int</span> filedes[<span class="hljs-number">2</span>];

    <span class="hljs-comment">//1、初始化内部数据结构</span>
    ril_event_init();

    pthread_mutex_lock(&s_startupMutex);

    <span class="hljs-comment">//通知RIL_startEventLoop本线程已经创建并成功运行了</span>
    s_started = <span class="hljs-number">1</span>;
    pthread_cond_broadcast(&s_startupCond);

    pthread_mutex_unlock(&s_startupMutex);

    <span class="hljs-comment">//创建匿名管道</span>
    ret = pipe(filedes);
    ........
    s_fdWakeupRead = filedes[<span class="hljs-number">0</span>];
    s_fdWakeupWrite = filedes[<span class="hljs-number">1</span>];
    <span class="hljs-comment">//设置读端口为非阻塞的</span>
    fcntl(s_fdWakeupRead, F_SETFL, O_NONBLOCK);

    <span class="hljs-comment">//2、创建一个ril_event</span>
    ril_event_set (&s_wakeupfd_event, s_fdWakeupRead, <span class="hljs-literal">true</span>,
                processWakeupCallback, <span class="hljs-literal">NULL</span>);

    <span class="hljs-comment">//3、将创建出的ril_event加入到event队列中</span>
    rilEventAddWakeup (&s_wakeupfd_event);

    <span class="hljs-comment">//4、进入事件等待循环中</span>
    ril_event_loop();
    .........    
}</code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li></ul>

1.1 初始化内部数据结构
我们先看看ril_event_init函数:

<code class="hljs cpp has-numbering"><span class="hljs-keyword">void</span> ril_event_init()
{
    MUTEX_INIT();

    FD_ZERO(&readFds);
    <span class="hljs-comment">//初始化timer_list,任务插入时按时间排序</span>
    init_list(&timer_list);
    <span class="hljs-comment">//初始化pending_list,保存每次需要执行的任务</span>
    init_list(&pending_list);
    <span class="hljs-comment">//初始化监控表</span>
    <span class="hljs-built_in">memset</span>(watch_table, <span class="hljs-number">0</span>, <span class="hljs-keyword">sizeof</span>(watch_table));
}

<span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> init_list(<span class="hljs-keyword">struct</span> ril_event * <span class="hljs-built_in">list</span>)
{
    <span class="hljs-built_in">memset</span>(<span class="hljs-built_in">list</span>, <span class="hljs-number">0</span>, <span class="hljs-keyword">sizeof</span>(<span class="hljs-keyword">struct</span> ril_event));
    <span class="hljs-built_in">list</span>->next = <span class="hljs-built_in">list</span>;
    <span class="hljs-built_in">list</span>->prev = <span class="hljs-built_in">list</span>;
    <span class="hljs-built_in">list</span>->fd = -<span class="hljs-number">1</span>;
}

<span class="hljs-comment">//MAX_FD_EVENTS为8</span>
<span class="hljs-comment">//watchtable将用于保存FD加入到readFDs中的ril_event</span>
<span class="hljs-keyword">static</span> <span class="hljs-keyword">struct</span> ril_event * watch_table[MAX_FD_EVENTS];</code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li></ul>

可以看出ril_event_init就是初始化readFds、timer_list、pending_list和watch_table,其中后三种数据结构均是用来存放ril_event的。

根据前文的代码,我们知道Rild的main函数中,通过调用RIL_startEventLoop单独启动了一个线程运行eventLoop,这是一个工作线程。
这个工作线程就是靠ril_event结构体来描述自己需要执行的任务,并且它将多个任务按时间顺序组织起来,保存在任务队列中。
ril_event的数据结构如下:

<code class="hljs cs has-numbering"><span class="hljs-keyword">struct</span> ril_event {
    <span class="hljs-keyword">struct</span> ril_event *next;
    <span class="hljs-keyword">struct</span> ril_event *prev;

    <span class="hljs-keyword">int</span> fd;
    <span class="hljs-keyword">int</span> index;
    <span class="hljs-keyword">bool</span> persist;
    <span class="hljs-keyword">struct</span> timeval timeout;
    ril_event_cb func;
    <span class="hljs-keyword">void</span> *param;
};</code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li></ul>

如果从设计模式的角度来理解Rild的工作线程,易于看出,这其实是比较典型的命令模式。
就如同之前博客分析vold进程一样,CommandListener收到数据后,调用对应Command的runCommand方法进行处理。
此处,工作线程收到ril_event后,加入队列中,当需要处理时,调用ril_event对应的处理函数func。

1.2 创建wakeupfd ril_event
工作线程完成数据结构的初始化后,创建了第一个ril_event:

<code class="hljs asciidoc has-numbering"><span class="hljs-code">........
ril_event_set (&s_wakeupfd_event, s_fdWakeupRead, true,
            processWakeupCallback, NULL);
........</span></code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li></ul>
<code class="hljs cpp has-numbering"><span class="hljs-comment">// Initialize an event</span>
<span class="hljs-keyword">void</span> ril_event_set(<span class="hljs-keyword">struct</span> ril_event * ev, <span class="hljs-keyword">int</span> fd, <span class="hljs-keyword">bool</span> persist, ril_event_cb func, <span class="hljs-keyword">void</span> * param)
{
    dlog(<span class="hljs-string">"~~~~ ril_event_set %x ~~~~"</span>, (<span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span>)ev);
    <span class="hljs-built_in">memset</span>(ev, <span class="hljs-number">0</span>, <span class="hljs-keyword">sizeof</span>(<span class="hljs-keyword">struct</span> ril_event));
    ev->fd = fd;
    ev->index = -<span class="hljs-number">1</span>;
    ev->persist = persist;
    ev->func = func;
    ev->param = param;
    fcntl(fd, F_SETFL, O_NONBLOCK);
}</code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li></ul>

从上面的代码可以看出,创建的第一个ril_event的fd为管道的读端、回调函数为processWakeupCallback,同时persist属性为true。

1.3 将创建出的ril_event加入到event队列中

<code class="hljs fsharp has-numbering"><span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> rilEventAddWakeup(<span class="hljs-keyword">struct</span> ril_event *ev) {
    ril_event_add(ev);
    triggerEvLoop();
}

<span class="hljs-comment">// Add event to watch list</span>
<span class="hljs-keyword">void</span> ril_event_add(<span class="hljs-keyword">struct</span> ril_event * ev)
{
    dlog(<span class="hljs-string">"~~~~ +ril_event_add ~~~~"</span>);
    MUTEX_ACQUIRE();
    <span class="hljs-keyword">for</span> (int i = <span class="hljs-number">0</span>; i < MAX_FD_EVENTS; i++) {
        <span class="hljs-comment">//找到第一个空闲索引加入</span>
        <span class="hljs-keyword">if</span> (watch_table[i] == NULL) {
            watch_table[i] = ev;
            <span class="hljs-comment">//ril</span>
            ev->index = i;
            dlog(<span class="hljs-string">"~~~~ added at %d ~~~~"</span>, i);
            dump_event(ev);
            <span class="hljs-comment">//将ril_event对应的fd加入到readFds</span>
            FD_SET(ev->fd, &readFds);
            <span class="hljs-comment">//select的限制,第一个参数为监听总数+1</span>
            <span class="hljs-keyword">if</span> (ev->fd >= nfds) nfds = ev->fd+<span class="hljs-number">1</span>;
            dlog(<span class="hljs-string">"~~~~ nfds = %d ~~~~"</span>, nfds);
            break;
        }
    }
    MUTEX_RELEASE();
    dlog(<span class="hljs-string">"~~~~ -ril_event_add ~~~~"</span>);
}

<span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> triggerEvLoop() {
    int ret;
    <span class="hljs-comment">//pthread_self返回调用线程的线程ID</span>
    <span class="hljs-comment">//这里调用triggerEvLoop的就是eventLoop,因此不进入该分支</span>
    <span class="hljs-keyword">if</span> (!pthread_equal(pthread_self(), s_tid_dispatch)) {
        /* trigger event loop <span class="hljs-keyword">to</span> wakeup. No reason <span class="hljs-keyword">to</span> <span class="hljs-keyword">do</span> this,
         * <span class="hljs-keyword">if</span> we're <span class="hljs-keyword">in</span> the event loop thread */
         <span class="hljs-keyword">do</span> {
            <span class="hljs-comment">//但看代码我们知道,如果其它线程调用rilEventAddWakeup加入ril_event时,就会向pipe的写端写入数据</span>
            ret = write (s_fdWakeupWrite, <span class="hljs-string">" "</span>, <span class="hljs-number">1</span>);
         } <span class="hljs-keyword">while</span> (ret < <span class="hljs-number">0</span> && errno == EINTR);
    }
}</code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li><li>42</li><li>43</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li><li>42</li><li>43</li></ul>

1.4 进入事件等待循环中
接下来工作线程进入到事件等待循环中:

<code class="hljs objectivec has-numbering"><span class="hljs-keyword">void</span> ril_event_loop() {
    ........
    <span class="hljs-keyword">for</span> (;;) {
        <span class="hljs-comment">// make local copy of read fd_set</span>
        memcpy(&rfds, &readFds, <span class="hljs-keyword">sizeof</span>(fd_set));
        <span class="hljs-comment">//根据timer_list来计算select函数等待的时间,timer_list已经按任务的执行时间排序</span>
        <span class="hljs-keyword">if</span> (-<span class="hljs-number">1</span> == calcNextTimeout(&tv)) {
            <span class="hljs-comment">// no pending timers; block indefinitely</span>
            dlog(<span class="hljs-string">"~~~~ no timers; blocking indefinitely ~~~~"</span>);
            ptv = <span class="hljs-literal">NULL</span>;
        } <span class="hljs-keyword">else</span> {
            dlog(<span class="hljs-string">"~~~~ blocking for %ds + %dus ~~~~"</span>, (<span class="hljs-keyword">int</span>)tv<span class="hljs-variable">.tv_sec</span>, (<span class="hljs-keyword">int</span>)tv<span class="hljs-variable">.tv_usec</span>);
            ptv = &tv;
        }
        ............
        n = select(nfds, &rfds, <span class="hljs-literal">NULL</span>, <span class="hljs-literal">NULL</span>, ptv);
        <span class="hljs-comment">//将timer_list中超时的任务加入到pending_list中</span>
        processTimeouts();
        <span class="hljs-comment">//将watchtables中收到的任务加入到pending_list中</span>
        processReadReadies(&rfds, n);
        <span class="hljs-comment">//处理pendinglist中的任务</span>
        firePending();
    }
}

<span class="hljs-keyword">static</span> <span class="hljs-keyword">int</span> calcNextTimeout(<span class="hljs-keyword">struct</span> timeval * tv) 
{
    <span class="hljs-keyword">struct</span> ril_event * tev = timer_list<span class="hljs-variable">.next</span>;
    <span class="hljs-keyword">struct</span> timeval now;

    <span class="hljs-comment">//利用clock_gettime获取当前时间</span>
    getNow(&now);

    <span class="hljs-comment">// Sorted list, so calc based on first node</span>
    <span class="hljs-keyword">if</span> (tev == &timer_list) {
        <span class="hljs-comment">// no pending timers</span>
        <span class="hljs-keyword">return</span> -<span class="hljs-number">1</span>;
    }

    <span class="hljs-keyword">if</span> (timercmp(&tev->timeout, &now, >)) {
        <span class="hljs-comment">//计算出等待时间</span>
        timersub(&tev->timeout, &now, tv);
    } <span class="hljs-keyword">else</span> {
        <span class="hljs-comment">// timer already expired.</span>
        tv->tv_sec = tv->tv_usec = <span class="hljs-number">0</span>;
    }
    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
}

<span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> processTimeouts()
{
    ............
    <span class="hljs-keyword">struct</span> timeval now;
    <span class="hljs-keyword">struct</span> ril_event * tev = timer_list<span class="hljs-variable">.next</span>;
    <span class="hljs-keyword">struct</span> ril_event * next;

    getNow(&now);
    ............
    <span class="hljs-comment">//目前还没提及timer_list,实际上调用ril_timer_add函数时,可以将对时间有要求的ril_event加入到timer_list中,按照超时时间从小到大排列</span>
    <span class="hljs-keyword">while</span> ((tev != &timer_list) && (timercmp(&now, &tev->timeout, >))) {
        <span class="hljs-comment">// Timer expired</span>
        dlog(<span class="hljs-string">"~~~~ firing timer ~~~~"</span>);
        next = tev->next;
        removeFromList(tev);
        <span class="hljs-comment">//轮询timerlist表,将timer_list中的任务加入到pending_list中</span>
        addToList(tev, &pending_list);
        tev = next;
    }
}

<span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> processReadReadies(fd_set * rfds, <span class="hljs-keyword">int</span> n)
{
    ..........
    <span class="hljs-comment">//前面代码已提过,当调用ril_event_add时,新加入的ril_event将存入watch_table</span>
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; (i < MAX_FD_EVENTS) && (n > <span class="hljs-number">0</span>); i++) {
        <span class="hljs-keyword">struct</span> ril_event * rev = watch_table[i];
        <span class="hljs-keyword">if</span> (rev != <span class="hljs-literal">NULL</span> && FD_ISSET(rev->fd, rfds)) {
            addToList(rev, &pending_list);
            <span class="hljs-comment">//persist值为false时,才会移除</span>
            <span class="hljs-comment">//记得么?在eventLoop调用ril_event_loop前,加入了一个s_wakeupfd_event,其persist值为true,永不移除</span>
            <span class="hljs-keyword">if</span> (rev->persist == <span class="hljs-literal">false</span>) {
                removeWatch(rev, i);
            }
            n--;
        }
    }
    ..........
}

<span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> firePending() {
    ...........
    <span class="hljs-keyword">struct</span> ril_event * ev = pending_list<span class="hljs-variable">.next</span>;
    <span class="hljs-keyword">while</span> (ev != &pending_list) {
        <span class="hljs-keyword">struct</span> ril_event * next = ev->next;
        removeFromList(ev);
        <span class="hljs-comment">//执行对对应的执行函数</span>
        <span class="hljs-comment">//每次循环时s_wakeupfd_event的执行函数processWakeupCallback都会被调用</span>
        ev->func(ev->fd, <span class="hljs-number">0</span>, ev->param);
        ev = next;
    }
    ..........
}

<span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> processWakeupCallback(<span class="hljs-keyword">int</span> fd, <span class="hljs-keyword">short</span> flags, <span class="hljs-keyword">void</span> *param) {
    .......
    <span class="hljs-comment">/* empty our wakeup socket out */</span>
    <span class="hljs-keyword">do</span> {
        <span class="hljs-comment">//当有其它线程调用triggerEvLoop时,会向s_fdWakeupWrite中写入数据</span>
        <span class="hljs-comment">//s_wakeupfd_event被触发时,负责清空缓存</span>
        ret = read(s_fdWakeupRead, &buff, <span class="hljs-keyword">sizeof</span>(buff));
    } <span class="hljs-keyword">while</span> (ret > <span class="hljs-number">0</span> || (ret < <span class="hljs-number">0</span> && errno == EINTR));
}</code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li><li>42</li><li>43</li><li>44</li><li>45</li><li>46</li><li>47</li><li>48</li><li>49</li><li>50</li><li>51</li><li>52</li><li>53</li><li>54</li><li>55</li><li>56</li><li>57</li><li>58</li><li>59</li><li>60</li><li>61</li><li>62</li><li>63</li><li>64</li><li>65</li><li>66</li><li>67</li><li>68</li><li>69</li><li>70</li><li>71</li><li>72</li><li>73</li><li>74</li><li>75</li><li>76</li><li>77</li><li>78</li><li>79</li><li>80</li><li>81</li><li>82</li><li>83</li><li>84</li><li>85</li><li>86</li><li>87</li><li>88</li><li>89</li><li>90</li><li>91</li><li>92</li><li>93</li><li>94</li><li>95</li><li>96</li><li>97</li><li>98</li><li>99</li><li>100</li><li>101</li><li>102</li><li>103</li><li>104</li><li>105</li><li>106</li><li>107</li><li>108</li><li>109</li><li>110</li><li>111</li><li>112</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li><li>42</li><li>43</li><li>44</li><li>45</li><li>46</li><li>47</li><li>48</li><li>49</li><li>50</li><li>51</li><li>52</li><li>53</li><li>54</li><li>55</li><li>56</li><li>57</li><li>58</li><li>59</li><li>60</li><li>61</li><li>62</li><li>63</li><li>64</li><li>65</li><li>66</li><li>67</li><li>68</li><li>69</li><li>70</li><li>71</li><li>72</li><li>73</li><li>74</li><li>75</li><li>76</li><li>77</li><li>78</li><li>79</li><li>80</li><li>81</li><li>82</li><li>83</li><li>84</li><li>85</li><li>86</li><li>87</li><li>88</li><li>89</li><li>90</li><li>91</li><li>92</li><li>93</li><li>94</li><li>95</li><li>96</li><li>97</li><li>98</li><li>99</li><li>100</li><li>101</li><li>102</li><li>103</li><li>104</li><li>105</li><li>106</li><li>107</li><li>108</li><li>109</li><li>110</li><li>111</li><li>112</li></ul>

至此,RIL_startEventLoop的工作介绍完毕,虽然还没有实际开始工作,但它搭建出了整个事件的处理框架。这里涉及的代码比较繁杂,我们还是借助于图形总结一下整个过程:

1.4.1 整体架构
如上图所示,Rild的main函数中调用RIL_startEventLoop。在RIL_startEventLoop中创建出工作线程,执行eventLoop函数:
Step 1、利用ril_event_init函数初始化数据结构,主要包括readFds、timer_list、pending_list和watch_table;

Step 2、创建出一个pipe对象;

Step 3、创建s_wakeupfd_event,该event的fd指定为pipe的读端;这个event将被加入到watch_table,同时pipe的读端将被加入到readFds中;注意这个event的persist属性为true,于是将永远存在于watch_table中;

Step 4、调用ril_event_loop开始监听事件的到来。

先在我们结合图形,举几个例子看看,整个事件处理框架是如何工作的。
注意到初始时,timer_list为空,因此ril_event_loop中将不限时地等待readFds。

1.4.2 ril_event加入到timer_list
当其它线程调用ril_timer_add函数(定义于ril_event.cpp中)填加ril_event事件时:
Step 1、新到来的ril_event将按超时时间,由小到大加入到timer_list中;同时,其它线程一般会调用triggerEvLoop,该函数将会向pipe的写端写入数据。

Step 2、于是,pipe的读端将会收到数据;由于初始时pipe读端已经加入到来readFds,因此ril_event_loop将从等待中唤醒。

Step 3、此时,ril_event_loop将执行timer_list和watch_table中存储的事件。注意到在timer_list中,只有超时的事件才会被处理;在watch_table中,只有对应fd已经存入readFds(此时使用的是拷贝对象)的事件才会被执行。
注意到初始时加入watch_table的s_wakeupfd_event,永远满足执行条件;因此,每次ril_event_loop被唤醒时,该事件都被添加到pending_list。
s_wakeupfd_event对应的执行函数,将会清空pipe的buffer。

Step 4、 处理完加入到pending_list中的事件后,ril_event_loop将根据timer_list中事件的超时时间,决定等待readFds的时间。
如果在等待超时之前,没有其它事件到来,那么ril_event_loop将在等待超时后处理timer_list中的事件;否则,仅会处理新到来的事件,不会处理timer_list事件。

1.4.3 ril_event加入到watch_table
当其它线程调用ril_event_add函数(定义于ril_event.cpp中)增加ril_event事件时:
Step 1、当watch_table有空位时,新加入的ril_event将被加入到watch_table中,同时对应的fd被添加到readFds;同时,其它线程可能会调用triggerEvLoop,以唤醒ril_event_loop。

Step 2、 ril_event_loop被唤醒后,并不会执行新加入到watch_table中的ril_event,因为它们的fd才刚被加入到readFds中。
从代码里我们可以看到,ril_event_loop当次循环处理的是readFds的拷贝对应的数据,因此新加入watch_table的ril_event在下次唤醒时才能够被处理。

Step 3、由于加入ril_event对应的fd被加入到readFds中,因此如果对应的fd写入数据时,也会唤醒ril_event_loop。

至此,RIL_startEventLoop的主要流程介绍完毕,可以看到它的主要工作就是启动工作线程,然后等待事件的添加
那么接下来我们可以看看下一个Rild中下一个重要操作,即调用RIL_Init函数。

2、 RIL_Init
RIL_Init定义于动态库中,考虑到厂商的保密性,我们只能分析Android原生的Reference-ril库。
在Android的原生库中,RIL_Init定义于hardware/ril/reference-ril/reference-ril.c中。

<code class="hljs java has-numbering"><span class="hljs-keyword">const</span> RIL_RadioFunctions *RIL_Init(<span class="hljs-keyword">const</span> struct RIL_Env *env, <span class="hljs-keyword">int</span> argc, <span class="hljs-keyword">char</span> **argv)
{
    .............
    s_rilenv = env;
    <span class="hljs-comment">//参数处理</span>
    ...........
    pthread_attr_init (&attr);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    ret = pthread_create(&s_tid_mainloop, &attr, mainLoop, NULL);

    <span class="hljs-keyword">return</span> &s_callbacks;
}

<span class="hljs-javadoc">/*** Static Variables ***/</span>
<span class="hljs-keyword">static</span> <span class="hljs-keyword">const</span> RIL_RadioFunctions s_callbacks = {
    RIL_VERSION,
    <span class="hljs-comment">//以下皆是函数指针</span>
    onRequest,
    currentState,
    onSupports,
    onCancel,
    getVersion
};</code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li></ul>

从代码上来看RIL_Init函数比较简单,就干了三件事:保存Rild传入的RIL_Env结构体;创建s_tid_mainloop线程,执行函数为mainLoop;返回RIL_RadioFunctions结构体。
这里需要注意的是:RIL_Env和RIL_RadioFunctions结构体,就是Rild架构中用来隔离通用代码和厂商相关代码的接口。即动态库通过RIL_Env调用Rild中的接口,Rild通过RIL_RadioFunctions调用动态库中的接口。

2.1 通信接口
我们先看看RIL_RadioFunctions结构体:

<code class="hljs d has-numbering"><span class="hljs-comment">//此处略去函数指针的定义</span>
<span class="hljs-keyword">typedef</span> <span class="hljs-keyword">struct</span> {
    <span class="hljs-keyword">int</span> <span class="hljs-keyword">version</span>;        <span class="hljs-comment">/* set to RIL_VERSION */</span>
    <span class="hljs-comment">//用于向BP提交一个请求</span>
    RIL_RequestFunc onRequest;

    <span class="hljs-comment">//用于查询BP的状态</span>
    RIL_RadioStateRequest onStateRequest;

    <span class="hljs-comment">//用于判断动态库是否支持某人requestCode</span>
    RIL_Supports supports;

    <span class="hljs-comment">//用于取消一个提交给BP的请求</span>
    RIL_Cancel onCancel;

    <span class="hljs-comment">//查询动态库版本</span>
    RIL_GetVersion getVersion;
} RIL_RadioFunctions;</code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li></ul>

这里需要重点关注的函数是onRequest,它被Rild用来向动态库提交一个请求。
Rild架构采用的是异步请求/处理的通信方式,Rild通过onRequest向动态库提交一个请求,然后返回进行自己的工作;动态库处理这个请求,当处理完请求后,通过回调的方式将结果通知给Rild。

我们再来看看RIL_Env结构体:

<code class="hljs cs has-numbering"><span class="hljs-keyword">struct</span> RIL_Env {
    <span class="hljs-comment">//动态库完成一个请求后,通过OnRequestComplete通知处理结果,RIL_Token用于标明是哪个请求的处理结果</span>
    <span class="hljs-keyword">void</span> (*OnRequestComplete)(RIL_Token t, RIL_Errno e,
                           <span class="hljs-keyword">void</span> *response, size_t responselen);

    <span class="hljs-comment">//动态库主动上报时,调用的接口</span>
<span class="hljs-preprocessor">#<span class="hljs-keyword">if</span> defined(ANDROID_MULTI_SIM)</span>
    <span class="hljs-keyword">void</span> (*OnUnsolicitedResponse)(<span class="hljs-keyword">int</span> unsolResponse, <span class="hljs-keyword">const</span> <span class="hljs-keyword">void</span> *data, size_t datalen, RIL_SOCKET_ID socket_id);
<span class="hljs-preprocessor">#<span class="hljs-keyword">else</span></span>
    <span class="hljs-keyword">void</span> (*OnUnsolicitedResponse)(<span class="hljs-keyword">int</span> unsolResponse, <span class="hljs-keyword">const</span> <span class="hljs-keyword">void</span> *data, size_t datalen);
<span class="hljs-preprocessor">#<span class="hljs-keyword">endif</span>  </span>

    <span class="hljs-comment">//给rild提交一个超时任务</span>
    <span class="hljs-keyword">void</span> (*RequestTimedCallback) (RIL_TimedCallback callback,
                              <span class="hljs-keyword">void</span> *param, <span class="hljs-keyword">const</span> <span class="hljs-keyword">struct</span> timeval *relativeTime);

    <span class="hljs-comment">//对于同步的请求,发送应答消息时,使用该接口,目前没看到使用</span>
    <span class="hljs-keyword">void</span> (*OnRequestAck) (RIL_Token t);
}</code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li></ul>

在RIL_Env的结构体中,主要需要关注的是OnRequestComplete和OnUnsolicitedResponse。

2.2 mainLoop
动态库的RIL_Init被调用后,将会创建一个工作线程,其运行函数为mainLoop:

<code class="hljs lasso has-numbering">static <span class="hljs-literal">void</span> <span class="hljs-subst">*</span>
mainLoop(<span class="hljs-literal">void</span> <span class="hljs-subst">*</span>param __unused)
{
    <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-built_in">..</span>
    <span class="hljs-comment">//为AT模块设置一些回调函数。</span>
    <span class="hljs-comment">//对于Reference-Ril库而言,AT模块就是对串口设备通信的封装,用于和BP通信</span>
    at_set_on_reader_closed(onATReaderClosed);
    at_set_on_timeout(onATTimeout);

    for (;;) {
        fd <span class="hljs-subst">=</span> <span class="hljs-subst">-</span><span class="hljs-number">1</span>;
        <span class="hljs-keyword">while</span>(fd <span class="hljs-subst"><</span> <span class="hljs-number">0</span>) {
            <span class="hljs-comment">//得到串口设备的文件描述符</span>
            <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-built_in">.</span>
        }
        <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span>
        <span class="hljs-comment">//打开AT设备,传入回调函数</span>
        ret <span class="hljs-subst">=</span> at_open(fd, onUnsolicited);
        <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-built_in">.</span>
        <span class="hljs-comment">//向Rild提交一个超时任务,该任务的处理函数为initializeCallback</span>
        RIL_requestTimedCallback(initializeCallback, <span class="hljs-built_in">NULL</span>, <span class="hljs-subst">&</span>TIMEVAL_0);
        <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-built_in">.</span>
        <span class="hljs-comment">//如果AT模块被关闭,则waitForClose返回,但是该线程不会退出,而是从for循环那开始重新执行一次</span>
        <span class="hljs-comment">//因此AT模块一旦被关闭,将会重新被打开</span>
        waitForClose();
        <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-built_in">.</span>
    }
}</code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li></ul>

从上面的代码可以看出,mainLoop的工作其实就是初始化并监控AT模块,一但AT模块被关闭,那么mainLoop就要重新打开并初始化它。

2.2.1 at_open

<code class="hljs lasso has-numbering">int at_open(int fd, ATUnsolHandler h) 
{
    <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-built_in">..</span>
    pthread_attr_init (<span class="hljs-subst">&</span>attr);
    pthread_attr_setdetachstate(<span class="hljs-subst">&</span>attr, PTHREAD_CREATE_DETACHED);

    ret <span class="hljs-subst">=</span> pthread_create(<span class="hljs-subst">&</span>s_tid_reader, <span class="hljs-subst">&</span>attr, readerLoop, <span class="hljs-subst">&</span>attr);
    <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-attribute">...</span>
}</code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li></ul>

在at_open中创建了一个工作线程,运行函数为readLoop:

<code class="hljs lasso has-numbering">static <span class="hljs-literal">void</span> <span class="hljs-subst">*</span>readerLoop(<span class="hljs-literal">void</span> <span class="hljs-subst">*</span>arg)
{
    for (;;) {
        const char <span class="hljs-subst">*</span> line;

        <span class="hljs-comment">//从串口设备读取数据</span>
        line <span class="hljs-subst">=</span> readline();
        <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span>
        <span class="hljs-keyword">if</span>(isSMSUnsolicited(line)) {
            <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-built_in">.</span>
            <span class="hljs-comment">//调用回调函数</span>
            <span class="hljs-keyword">if</span> (s_unsolHandler <span class="hljs-subst">!=</span> <span class="hljs-built_in">NULL</span>) {
                s_unsolHandler (line1, line2);
            }
            <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-built_in">.</span>
        } <span class="hljs-keyword">else</span> {
            <span class="hljs-comment">//根据line中的数据,调用不同的回调函数</span>
            processLine(line);
        }
    }
    <span class="hljs-comment">//如果从for循环退出,则通知mainLoop AT设备关闭</span>
    onReaderClosed();
    <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-built_in">..</span>
}</code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li></ul>

从上面的代码,我们知道at_open函数其实就是启动一个工作线程,用于接收AT设备的数据,然后进行处理。

2.2.1 initializeCallback
调用at_open后,main利用RIL_requestTimedCallback向Rild发送一个超时任务。

<code class="hljs cs has-numbering"><span class="hljs-preprocessor">#<span class="hljs-keyword">define</span> RIL_requestTimedCallback(a,b,c) s_rilenv->RequestTimedCallback(a,b,c)</span></code><ul class="pre-numbering" style=""><li>1</li></ul><ul class="pre-numbering" style=""><li>1</li></ul>

可以看到RIL_requestTimedCallback是一个宏,实际上还是通过RIL_Env中RequestTimedCallback函数发送超时任务。

我们看看ril.cpp中,该函数的实现:

<code class="hljs cpp has-numbering"><span class="hljs-keyword">extern</span> <span class="hljs-string">"C"</span> <span class="hljs-keyword">void</span>
RIL_requestTimedCallback (RIL_TimedCallback callback, <span class="hljs-keyword">void</span> *param,
                                <span class="hljs-keyword">const</span> <span class="hljs-keyword">struct</span> timeval *relativeTime) {
    internalRequestTimedCallback (callback, param, relativeTime);
}

<span class="hljs-keyword">static</span> UserCallbackInfo *
internalRequestTimedCallback (RIL_TimedCallback callback, <span class="hljs-keyword">void</span> *param,
                        <span class="hljs-keyword">const</span> <span class="hljs-keyword">struct</span> timeval *relativeTime)
{
    <span class="hljs-keyword">struct</span> timeval myRelativeTime;
    UserCallbackInfo *p_info;

    p_info = (UserCallbackInfo *) <span class="hljs-built_in">calloc</span>(<span class="hljs-number">1</span>, <span class="hljs-keyword">sizeof</span>(UserCallbackInfo));
    .........
    <span class="hljs-comment">//回调</span>
    p_info->p_callback = callback;
    <span class="hljs-comment">//参数</span>
    p_info->userParam = param;

    <span class="hljs-keyword">if</span> (relativeTime == NULL) {
        <span class="hljs-comment">/* treat null parameter as a 0 relative time */</span>
        <span class="hljs-built_in">memset</span> (&myRelativeTime, <span class="hljs-number">0</span>, <span class="hljs-keyword">sizeof</span>(myRelativeTime));
    } <span class="hljs-keyword">else</span> {
        <span class="hljs-comment">/* FIXME I think event_add's tv param is really const anyway */</span>
        <span class="hljs-comment">//时间</span>
        <span class="hljs-built_in">memcpy</span> (&myRelativeTime, relativeTime, <span class="hljs-keyword">sizeof</span>(myRelativeTime));
    }

    <span class="hljs-comment">//构造ril_event</span>
    ril_event_set(&(p_info->event), -<span class="hljs-number">1</span>, <span class="hljs-keyword">false</span>, userTimerCallback, p_info);

    <span class="hljs-comment">//加入到timer_list中</span>
    ril_timer_add(&(p_info->event), &myRelativeTime);

    <span class="hljs-comment">//触发EventLoop处理</span>
    triggerEvLoop();
    <span class="hljs-keyword">return</span> p_info;
}</code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li></ul>

当Rild中的eventLoop处理该超时任务时,就会回调Reference-ril库中的initializeCallback:

<code class="hljs lasso has-numbering">static <span class="hljs-literal">void</span> initializeCallback(<span class="hljs-literal">void</span> <span class="hljs-subst">*</span>param __unused)
{
    <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-built_in">..</span>
    <span class="hljs-comment">//同步radio状态</span>
    setRadioState (RADIO_STATE_OFF);

    <span class="hljs-comment">//不断地尝试发送AT指令给BP并等待回复,以确定AT channel正常</span>
    at_handshake();

    <span class="hljs-comment">//下发一系列的AT指令,完成modem初始化</span>
    <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-built_in">.</span>
}</code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li></ul>

至此,我们以Reference-ril库为例,分析了RIL_Init函数的基本功能。
如上图所示,RIL_Init的主要工作包括:
1、创建一个mainLoop工作线程,该线程用于完成实际的工作。
2、在mainLoop线程中,通过at_open开启AT模块,同时启动readLoop工作线程。readLoop工作线程负责从AT设备中读取信息,并执行对应的函数调用。
3、调用at_open后,mainLoop线程向Rild进程发送一个超时事件,该事件被Rild处理后,将调用initializeCallback函数。initializeCallback函数,将完成Modem的初始化工作。
其实上,mainLoop可以直接进行Modem初始化的工作;这里发送超时事件给Rild,通过回调进行初始化,可能是为了确保RIL_startEventLoop已经执行成功。
4、mainLoop最后通过waitForClose监控AT模块,一旦AT模块被关闭,mainLoop将重新进行初始化AT模块的工作。

3、RIL_register
现在我们分析一下Rild的main函数中,最后一个关键函数RIL_register:

<code class="hljs lasso has-numbering">extern <span class="hljs-string">"C"</span> <span class="hljs-literal">void</span>
RIL_register (const RIL_RadioFunctions <span class="hljs-subst">*</span>callbacks) {
    <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-attribute">...</span>
    <span class="hljs-comment">//判断之前是否初始化过</span>
    <span class="hljs-keyword">if</span> (s_registerCalled <span class="hljs-subst">></span> <span class="hljs-number">0</span>) {
        RLOGE(<span class="hljs-string">"RIL_register has been called more than once. "</span>
                <span class="hljs-string">"Subsequent call ignored"</span>);
        <span class="hljs-keyword">return</span>;
    }
    <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-attribute">...</span>
    <span class="hljs-comment">/* Initialize socket1 parameters */</span>
    s_ril_param_socket <span class="hljs-subst">=</span> {
                        RIL_SOCKET_1,             <span class="hljs-comment">/* socket_id */</span>
                        <span class="hljs-subst">-</span><span class="hljs-number">1</span>,                       <span class="hljs-comment">/* fdListen */</span>
                        <span class="hljs-subst">-</span><span class="hljs-number">1</span>,                       <span class="hljs-comment">/* fdCommand */</span>
                        PHONE_PROCESS,            <span class="hljs-comment">/* processName */</span>
                        <span class="hljs-subst">&</span>s_commands_event,        <span class="hljs-comment">/* commands_event */</span>
                        <span class="hljs-subst">&</span>s_listen_event,          <span class="hljs-comment">/* listen_event */</span>
                        processCommandsCallback,  <span class="hljs-comment">/* processCommandsCallback */</span>
                        <span class="hljs-built_in">NULL</span>                      <span class="hljs-comment">/* p_rs */</span>
                        };
    <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-attribute">...</span>
    s_registerCalled <span class="hljs-subst">=</span> <span class="hljs-number">1</span>;
    <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-attribute">...</span>
    <span class="hljs-comment">// start listen socket1</span>
    startListen(RIL_SOCKET_1, <span class="hljs-subst">&</span>s_ril_param_socket);
    <span class="hljs-comment">//代码中的SIM_COUNT宏并未定义,略去下文</span>
    <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-built_in">..</span>
}

typedef struct SocketListenParam {
    RIL_SOCKET_ID socket_id;
    int fdListen;
    int fdCommand;
    char<span class="hljs-subst">*</span> processName;
    struct ril_event<span class="hljs-subst">*</span> commands_event;
    struct ril_event<span class="hljs-subst">*</span> listen_event;
    <span class="hljs-literal">void</span> (<span class="hljs-subst">*</span>processCommandsCallback)(int fd, short flags, <span class="hljs-literal">void</span> <span class="hljs-subst">*</span>param);
    RecordStream <span class="hljs-subst">*</span>p_rs;
    RIL_SOCKET_TYPE <span class="hljs-keyword">type</span>;
} SocketListenParam;</code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li></ul>

从上面的代码可以看出,RIL_register实际就是初始化监听socket所需的参数,然后开始监听socket是否有数据到来。

在前面已经提到过,Android中会创建出两个Rild进程,每个Rild进程均会调用RIL_register函数。
虽然s_registerCalled为一个静态变量,但在进程的维度上,它是私有的。因此,每个Rild进程均会成功调用一次RIL_register。

接下来,我们看看startListen函数:

<code class="hljs lasso has-numbering">static <span class="hljs-literal">void</span> startListen(RIL_SOCKET_ID socket_id, SocketListenParam<span class="hljs-subst">*</span> socket_listen_p) {
    <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-attribute">...</span>
    switch(socket_id) {
        <span class="hljs-keyword">case</span> RIL_SOCKET_1:
            <span class="hljs-comment">//注意此处的RIL_getRilSocketName</span>
            strncpy(socket_name, RIL_getRilSocketName(), <span class="hljs-number">9</span>);
            break;
        <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-built_in">.</span>
    }

    <span class="hljs-comment">//根据socket_name获取对应的文件描述符</span>
    fdListen <span class="hljs-subst">=</span> android_get_control_socket(socket_name);
    <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-built_in">..</span>
    <span class="hljs-comment">//使Rild进程变成被动服务进程</span>
    ret <span class="hljs-subst">=</span> listen(fdListen, <span class="hljs-number">4</span>);
    <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-built_in">..</span>
    socket_listen_p<span class="hljs-subst">-></span>fdListen <span class="hljs-subst">=</span> fdListen;

    <span class="hljs-comment">/* note: non-persistent so we can accept only one connection at a time */</span>
    <span class="hljs-comment">//构造一个非超时任务加,注意persist为false,处理函数为listenCallback</span>
    ril_event_set (socket_listen_p<span class="hljs-subst">-></span>listen_event, fdListen, <span class="hljs-literal">false</span>,
                listenCallback, socket_listen_p);

    <span class="hljs-comment">//加入队列,并trigger</span>
    rilEventAddWakeup (socket_listen_p<span class="hljs-subst">-></span>listen_event);
}</code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li></ul>

3.1 RIL_getRilSocketName
startListen函数中,通过调用RIL_getRilSocketName得到需监听的socket的名称。

<code class="hljs cs has-numbering"><span class="hljs-keyword">static</span> <span class="hljs-keyword">char</span> * RIL_getRilSocketName() {
    <span class="hljs-keyword">return</span> rild;
}</code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li></ul>

RIL_getRilSocketName的内容很简单,就是返回变量rild。
那么rild变量又是何时设置的呢?

对于第一个Rild进程,在ril.cpp中,定义了rild的内容为“rild”。

<code class="hljs asciidoc has-numbering"><span class="hljs-code">.........
extern "C"
char rild[MAX_SOCKET_NAME_LENGTH] = SOCKET_NAME_RIL;
........</span>

#define SOCKET<span class="hljs-emphasis">_NAME_</span>RIL "rild"</code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li></ul>

对于第二个Rild进程,在Rild启动后,对应的main函数中,利用RIL_setRilSocketName修改rild的内容:

<code class="hljs lasso has-numbering">int main(int argc, char <span class="hljs-subst">**</span>argv) {
    <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-built_in">..</span>
    <span class="hljs-comment">//第二个Rild进程,clientId不为0</span>
    <span class="hljs-keyword">if</span> (strncmp(clientId, <span class="hljs-string">"0"</span>, MAX_CLIENT_ID_LENGTH)) {
        strlcat(rild, clientId, MAX_SOCKET_NAME_LENGTH);
        RIL_setRilSocketName(rild);
    }
    <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-built_in">..</span>
}</code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li></ul>
<code class="hljs cpp has-numbering"><span class="hljs-keyword">extern</span> <span class="hljs-string">"C"</span>
<span class="hljs-keyword">void</span> RIL_setRilSocketName(<span class="hljs-keyword">const</span> <span class="hljs-keyword">char</span> * s) {
    <span class="hljs-built_in">strncpy</span>(rild, s, MAX_SOCKET_NAME_LENGTH);
}</code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li></ul>

从上面的代码,我们可以看出两个Rild进程确实监听的是不同的socket。

3.2 listenCallback
利用listen函数将Rild变成监听进程后,start_listen通过ril_event_set构造了一个非超时的任务,并利用rilEventAddWakeup将该任务加入到watch_table中。
注意到ril_event的fd为待监听的socket,因此当ril_event被加入到watch_table后,该socket对应的fd将被加入到readFds中。

一旦该socket可读(即客户端connect成功),那么eventLoop中的select函数将会返回,执行listenCallback函数。
实际上,由于该任务的persist属性为false,因此执行完毕后,ril_event将从watch_table中移除,socket对应的fd也将被从readFds中移除。
这表明,Rild进程不会再监听socket对应的connect请求,只支持一个客户端的连接,仅会调用一次listenCallback函数。

<code class="hljs lasso has-numbering">static <span class="hljs-literal">void</span> listenCallback (int fd, short flags, <span class="hljs-literal">void</span> <span class="hljs-subst">*</span>param) {
    <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-built_in">..</span>
    <span class="hljs-comment">//保存配置的socket监听参数</span>
    SocketListenParam <span class="hljs-subst">*</span>p_info <span class="hljs-subst">=</span> (SocketListenParam <span class="hljs-subst">*</span>)param;
    <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-built_in">..</span>
    <span class="hljs-comment">//接收客户端连接,并将返回的socket保存起来</span>
    fdCommand <span class="hljs-subst">=</span> accept(fd, (sockaddr <span class="hljs-subst">*</span>) <span class="hljs-subst">&</span>peeraddr, <span class="hljs-subst">&</span>socklen);
    <span class="hljs-comment">//进行权限控制</span>
    <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-built_in">..</span>
    <span class="hljs-comment">//设置socket为非阻塞的</span>
    ret <span class="hljs-subst">=</span> fcntl(fdCommand, F_SETFL, O_NONBLOCK);
    <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-built_in">..</span>
    <span class="hljs-keyword">if</span>(<span class="hljs-built_in">NULL</span> <span class="hljs-subst">==</span> sapSocket) {
        <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-built_in">..</span>
        p_info<span class="hljs-subst">-></span>fdCommand <span class="hljs-subst">=</span> fdCommand;
        <span class="hljs-comment">//为socket分配一个接收缓存</span>
        p_rs <span class="hljs-subst">=</span> record_stream_new(p_info<span class="hljs-subst">-></span>fdCommand, MAX_COMMAND_BYTES);
        p_info<span class="hljs-subst">-></span>p_rs <span class="hljs-subst">=</span> p_rs;

        <span class="hljs-comment">//构造一个新的非超时任务,此时persist属性为true(1),于是eventLoop将一致select监听socket是否有数据到来</span>
        <span class="hljs-comment">//当有数据到来时,将调用processCommandsCallback进行处理</span>
        ril_event_set (p_info<span class="hljs-subst">-></span>commands_event, p_info<span class="hljs-subst">-></span>fdCommand, <span class="hljs-number">1</span>,
        p_info<span class="hljs-subst">-></span>processCommandsCallback, p_info);
        rilEventAddWakeup (p_info<span class="hljs-subst">-></span>commands_event);

        <span class="hljs-comment">//向客户端发送主动上报信息,即向RIL.java上报信息</span>
        onNewCommandConnect(p_info<span class="hljs-subst">-></span>socket_id);
    } <span class="hljs-keyword">else</span> {
        <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-built_in">.</span>
    }
}</code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li></ul>

至此,RIL_register的主要工作介绍完毕。从上述分析,我们可以看出RIL_register其实就是创建出与RIL.Java通信的服务端socket,然后监听客户端请求。一旦监听到客户端请求后,利用accept分配出对应的通信用socket。然后,再监听该分配出的socket,以处理客户端发来的数据。

4、 Rild main函数总结
现在我们已经分析完Rild main函数的主要流程了,回过头来看看Rild整体的设计思路:

1、利用RIL_startEventLoop,初始化通信框架。不论是初始化AT设备,还是接收来自RIL.java的请求,都依赖于Rild进程的通信架构,因此在main函数的最开始,对通信框架进行了初始化。
2、利用RIL_Init开启AT设备,并完成modem的初始化。AP侧利用RIL.java下发指令,最终还是需要利用AT传给modem来执行。因此,在通信框架初始化完毕后,首先就要完成AT和modem的配置。
3、利用RIL_register将Rild进程变成服务进程,等待RIL.java中socket的连接;连接成功后,开始处理来自RIL.java的数据。

三、实例分析
我们已经分析了Rild进程的工作,现在来结合数据业务拨号,看看实际过程中,Rild的工作情况。

1、RIL.java
首先,在之前的博客中,介绍数据业务基础类的创建时,我们提到过RIL.java在PhoneFactory的makeDefaultPhone中创建:

<code class="hljs cs has-numbering"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">makeDefaultPhone</span>(Context context) {
    .......
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i < numPhones; i++) {
        ........
        sCommandsInterfaces[i] = <span class="hljs-keyword">new</span> RIL(context, networkModes[i],
                cdmaSubscription, i);
    }
    ......  
}</code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li></ul>

我们看看RIL的构造函数:

<code class="hljs lasso has-numbering"><span class="hljs-keyword">public</span> RIL(Context context, int preferredNetworkType, int cdmaSubscription) {
    this(context, preferredNetworkType, cdmaSubscription, <span class="hljs-built_in">null</span>);
}

<span class="hljs-keyword">public</span> RIL(Context context, int preferredNetworkType,
        int cdmaSubscription, <span class="hljs-built_in">Integer</span> instanceId) {
    <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-built_in">..</span>
    mSenderThread <span class="hljs-subst">=</span> <span class="hljs-literal">new</span> HandlerThread(<span class="hljs-string">"RILSender"</span> <span class="hljs-subst">+</span> mInstanceId);
    mSenderThread<span class="hljs-built_in">.</span>start();

    Looper looper <span class="hljs-subst">=</span> mSenderThread<span class="hljs-built_in">.</span>getLooper();
    <span class="hljs-comment">//负责向Rild发送消息</span>
    mSender <span class="hljs-subst">=</span> <span class="hljs-literal">new</span> RILSender(looper);

    ConnectivityManager cm <span class="hljs-subst">=</span> (ConnectivityManager)context<span class="hljs-built_in">.</span>getSystemService(
            Context<span class="hljs-built_in">.</span>CONNECTIVITY_SERVICE);
    <span class="hljs-keyword">if</span> (cm<span class="hljs-built_in">.</span>isNetworkSupported(ConnectivityManager<span class="hljs-built_in">.</span>TYPE_MOBILE) <span class="hljs-subst">==</span> <span class="hljs-literal">false</span>) {
        riljLog(<span class="hljs-string">"Not starting RILReceiver: wifi-only"</span>);
    } <span class="hljs-keyword">else</span> {
        <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-built_in">..</span>
        <span class="hljs-comment">//负责接收Rild发送的消息</span>
        mReceiver <span class="hljs-subst">=</span> <span class="hljs-literal">new</span> RILReceiver();
        mReceiverThread <span class="hljs-subst">=</span> <span class="hljs-literal">new</span> <span class="hljs-keyword">Thread</span>(mReceiver, <span class="hljs-string">"RILReceiver"</span> <span class="hljs-subst">+</span> mInstanceId);
        mReceiverThread<span class="hljs-built_in">.</span>start();
        <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-built_in">..</span>
    }
    <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-built_in">.</span>
}</code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li></ul>

2、 RILReceiver
我们看看RILReceiver相关的函数:

<code class="hljs axapta has-numbering"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">RILReceiver</span> <span class="hljs-inheritance"><span class="hljs-keyword">implements</span></span> <span class="hljs-title">Runnable</span> {</span>
    <span class="hljs-keyword">byte</span>[] buffer;

    RILReceiver() {
        buffer = <span class="hljs-keyword">new</span> <span class="hljs-keyword">byte</span>[RIL_MAX_COMMAND_BYTES];
    }

    @Override
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> run() {
        <span class="hljs-keyword">int</span> retryCount = <span class="hljs-number">0</span>;
        String rilSocket = <span class="hljs-string">"rild"</span>;

        <span class="hljs-keyword">try</span> {
            <span class="hljs-keyword">for</span>(;;) {
                LocalSocket s = <span class="hljs-keyword">null</span>;
                LocalSocketAddress l;

                <span class="hljs-comment">//根据InstanceId决定连接哪个Rild进程的socket</span>
                <span class="hljs-keyword">if</span> (mInstanceId == <span class="hljs-keyword">null</span> || mInstanceId == <span class="hljs-number">0</span> ) {
                    rilSocket = SOCKET_NAME_RIL[<span class="hljs-number">0</span>];
                } <span class="hljs-keyword">else</span> {
                    rilSocket = SOCKET_NAME_RIL[mInstanceId];
                }

                <span class="hljs-keyword">try</span> {
                    s = <span class="hljs-keyword">new</span> LocalSocket();
                    l = <span class="hljs-keyword">new</span> LocalSocketAddress(rilSocket,
                            LocalSocketAddress.Namespace.RESERVED);
                    <span class="hljs-comment">//连接rild进程</span>
                    s.connect(l);
                } <span class="hljs-keyword">catch</span>(IOException ex) {
                    .........
                }

                retryCount = <span class="hljs-number">0</span>;

                <span class="hljs-comment">//连接Rild进程socket后,保留创建出的socket</span>
                mSocket = s;

                <span class="hljs-keyword">try</span> {
                    InputStream is = mSocket.getInputStream();

                    <span class="hljs-keyword">for</span> (;;) {
                        Parcel p;

                        <span class="hljs-comment">//不断读取到来的数据</span>
                        length = readRilMessage(is, buffer);
                        <span class="hljs-comment">//解析字节流</span>
                        ......
                        <span class="hljs-comment">//进行处理</span>
                        processResponse(p);
                        ......
                    } <span class="hljs-keyword">catch</span> (java.io.IOException ex) {
                        .......
                    } <span class="hljs-keyword">catch</span> (Throwable tr) {
                        .......
                    }

                    <span class="hljs-comment">//异常断开,执行关闭socket的操作</span>
                    .......
            }
        } <span class="hljs-keyword">catch</span> (Throwable tr) {
            ..........
        }
    }
    .........
}</code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li><li>42</li><li>43</li><li>44</li><li>45</li><li>46</li><li>47</li><li>48</li><li>49</li><li>50</li><li>51</li><li>52</li><li>53</li><li>54</li><li>55</li><li>56</li><li>57</li><li>58</li><li>59</li><li>60</li><li>61</li><li>62</li><li>63</li><li>64</li><li>65</li><li>66</li><li>67</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li><li>42</li><li>43</li><li>44</li><li>45</li><li>46</li><li>47</li><li>48</li><li>49</li><li>50</li><li>51</li><li>52</li><li>53</li><li>54</li><li>55</li><li>56</li><li>57</li><li>58</li><li>59</li><li>60</li><li>61</li><li>62</li><li>63</li><li>64</li><li>65</li><li>66</li><li>67</li></ul>

从RILReceiver的代码可以看出,其主要功能就是完成与Rild进程中server socket的连接,然后接收并处理Rild进程发来的数据。

3、 setupDataCall
之前的博客介绍数据业务拨号流程时,我们知道在DataConnection中,最终将通过调用RIL的setupDataCall函数,将消息发往modem:

<code class="hljs java has-numbering"><span class="hljs-annotation">@Override</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setupDataCall</span>(....) {
    <span class="hljs-comment">//构造一个request,有唯一的serialNumber,RIL_REQUEST_SETUP_DATA_CALL表明该Request的目的</span>
    RILRequest rr = RILRequest.obtain(RIL_REQUEST_SETUP_DATA_CALL, result);

    <span class="hljs-comment">//将参数写入到RILRequest的Parcel对象中</span>
    ........

    send(rr);
}

<span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">send</span>(RILRequest rr) {
    Message msg;

    <span class="hljs-comment">//RILReceiver中已经创建出mSocket,同时连接了Rild进程</span>
    <span class="hljs-keyword">if</span> (mSocket == <span class="hljs-keyword">null</span>) {
        rr.onError(RADIO_NOT_AVAILABLE, <span class="hljs-keyword">null</span>);
        rr.release();
        <span class="hljs-keyword">return</span>;
    }

    <span class="hljs-comment">//构造消息发送给RILSender</span>
    msg = mSender.obtainMessage(EVENT_SEND, rr);
    acquireWakeLock(rr, FOR_WAKELOCK);
    msg.sendToTarget();
}</code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li></ul>

我们看看RILSender:

<code class="hljs axapta has-numbering"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">RILSender</span> <span class="hljs-inheritance"><span class="hljs-keyword">extends</span></span> <span class="hljs-title">Handler</span> <span class="hljs-inheritance"><span class="hljs-keyword">implements</span></span> <span class="hljs-title">Runnable</span> {</span>
    .......
    @Override <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span>
    handleMessage(Message msg) {
        RILRequest rr = (RILRequest)(msg.obj);
        RILRequest req = <span class="hljs-keyword">null</span>;

        <span class="hljs-keyword">switch</span> (msg.what) {
            <span class="hljs-keyword">case</span> EVENT_SEND:
            <span class="hljs-keyword">case</span> EVENT_SEND_ACK:
                <span class="hljs-keyword">try</span> {
                    LocalSocket s;

                    s = mSocket;
                    <span class="hljs-comment">//将数据打包到data,发往Rild进程</span>
                    .........
                    s.getOutputStream().write(dataLength);
                    s.getOutputStream().write(data);
                    .....
                <span class="hljs-keyword">catch</span>(IOException ex) {
                    .......
                } <span class="hljs-keyword">catch</span> (RuntimeException exc) {
                    .......
                }
                <span class="hljs-keyword">break</span>;
            ........
        }
    }
}</code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li></ul>

4、processCommandsCallback
根据前面对Rild进程的分析,我们知道当Rild进程收到RIL.java中发送来的数据后,将利用processCommandsCallback进行处理:

<code class="hljs lasso has-numbering">static <span class="hljs-literal">void</span> processCommandsCallback(int fd, short flags, <span class="hljs-literal">void</span> <span class="hljs-subst">*</span>param) {
    <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-attribute">...</span>
    for (;;) {
        <span class="hljs-comment">/* loop until EAGAIN/EINTR, end of stream, or other error */</span>
        <span class="hljs-comment">//record_stream_get_next将socket中接收的数据全部读取到缓冲区</span>
        <span class="hljs-comment">//当缓冲区还有数据时,优先解析缓冲区数据;缓冲区无数据时,才从socket再次read</span>
        ret <span class="hljs-subst">=</span> record_stream_get_next(p_rs, <span class="hljs-subst">&</span>p_record, <span class="hljs-subst">&</span>recordlen);

        <span class="hljs-keyword">if</span> (ret <span class="hljs-subst">==</span> <span class="hljs-number">0</span> <span class="hljs-subst">&&</span> p_record <span class="hljs-subst">==</span> <span class="hljs-built_in">NULL</span>) {
            <span class="hljs-comment">/* end-of-stream */</span>
            break;
        } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (ret <span class="hljs-subst"><</span> <span class="hljs-number">0</span>) {
            break;
        } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (ret <span class="hljs-subst">==</span> <span class="hljs-number">0</span>) { <span class="hljs-comment">/* && p_record != NULL */</span>
            <span class="hljs-comment">//解析出的命令利用processCommandBuffer处理</span>
            processCommandBuffer(p_record, recordlen, p_info<span class="hljs-subst">-></span>socket_id);
        }
    }
    <span class="hljs-comment">//错误处理</span>
    <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-attribute">...</span>
}

static int
processCommandBuffer(<span class="hljs-literal">void</span> <span class="hljs-subst">*</span>buffer, size_t buflen, RIL_SOCKET_ID socket_id) {
    <span class="hljs-comment">//判断参数有效性,解析数据等操作</span>
    <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-built_in">.</span>
    pRI <span class="hljs-subst">=</span> (RequestInfo <span class="hljs-subst">*</span>)calloc(<span class="hljs-number">1</span>, sizeof(RequestInfo));
    <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-attribute">...</span>
    pRI<span class="hljs-subst">-></span>token <span class="hljs-subst">=</span> token;
    <span class="hljs-comment">//决定了对应的执行函数</span>
    pRI<span class="hljs-subst">-></span>pCI <span class="hljs-subst">=</span> <span class="hljs-subst">&</span>(s_commands<span class="hljs-preprocessor">[</span>request<span class="hljs-preprocessor">]</span><span class="hljs-markup">);
    pRI->socket_id = socket_id;
    ...........
    pRI->pCI->dispatchFunction(p, pRI);
    return 0;
}</span></code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li></ul>

上面的代码中,出现了一个s_commands数组,它保存了一些CommandInfo结构,这个结构封装了Rild对AT指令的处理函数。另外,Rild还定义了一个s_unsolResponses数组,它封装了unsolicited Response对应的一些处理函数。

<code class="hljs vala has-numbering"><span class="hljs-keyword">static</span> CommandInfo s_commands[] = {
<span class="hljs-preprocessor">#include "ril_commands.h"</span>
};

<span class="hljs-keyword">static</span> UnsolResponseInfo s_unsolResponses[] = {
<span class="hljs-preprocessor">#include "ril_unsol_commands.h"</span>
};

typedef <span class="hljs-keyword">struct</span> {
    <span class="hljs-comment">//请求号</span>
    <span class="hljs-keyword">int</span> requestNumber;
    <span class="hljs-comment">//请求处理函数</span>
    <span class="hljs-keyword">void</span> (*dispatchFunction) (Parcel &p, <span class="hljs-keyword">struct</span> RequestInfo *pRI);
    <span class="hljs-comment">//结果处理函数</span>
    <span class="hljs-keyword">int</span>(*responseFunction) (Parcel &p, <span class="hljs-keyword">void</span> *response, size_t responselen);
} CommandInfo;

typedef <span class="hljs-keyword">struct</span> {
    <span class="hljs-keyword">int</span> requestNumber;
    <span class="hljs-keyword">int</span> (*responseFunction) (Parcel &p, <span class="hljs-keyword">void</span> *response, size_t responselen);
    WakeType wakeType;
} UnsolResponseInfo;</code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li></ul>

这里我们重点看一下s_commands数组。
CommandInfo按照requestNumber的先后顺序加入到s_commands中,因此requestNumber就是对应CommandInfo的索引。
我们看看ril_commands.h:

<code class="hljs asciidoc has-numbering">{0, NULL, NULL},
<span class="hljs-code">......
{RIL_REQUEST_SETUP_DATA_CALL, dispatchDataCall, responseSetupDataCall},
......</span></code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li></ul>

在RIL.java中,指定了拨号对应的请求号为RIL_REQUEST_SETUP_DATA_CALL,因此Rild中对应的处理函数为dispatchDataCall。

5、dispatchDataCall

<code class="hljs lasso has-numbering">static <span class="hljs-literal">void</span> dispatchDataCall(Parcel<span class="hljs-subst">&</span> p, RequestInfo <span class="hljs-subst">*</span>pRI) {
    <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-attribute">...</span>
    <span class="hljs-comment">//转换输入参数后处理</span>
    <span class="hljs-keyword">if</span> (s_callbacks<span class="hljs-built_in">.</span>version <span class="hljs-subst"><</span> <span class="hljs-number">4</span> <span class="hljs-subst">&&</span> numParams <span class="hljs-subst">></span> numParamsRilV3) {
        <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-built_in">.</span>
        dispatchStrings(p2, pRI);
    } <span class="hljs-keyword">else</span> {
        <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-attribute">...</span>
        dispatchStrings(p, pRI);
    }
}

static <span class="hljs-literal">void</span>
dispatchStrings (Parcel <span class="hljs-subst">&</span>p, RequestInfo <span class="hljs-subst">*</span>pRI) {
    <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-built_in">..</span>
    startRequest;
    <span class="hljs-comment">//处理输入参数</span>
    <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-attribute">...</span>
    removeLastChar;
    closeRequest;

    <span class="hljs-comment">//CALL_ONREQUEST是个宏,实际上调用s_callbacks的onRequest函数</span>
    <span class="hljs-comment">//s_callbacks的类型为RIL_RadioFunctions,在rild.c的main函数中,利用动态库的RIL_Init函数得到;利用RIL_register函数保存</span>
    CALL_ONREQUEST(pRI<span class="hljs-subst">-></span>pCI<span class="hljs-subst">-></span>requestNumber, pStrings, datalen, pRI, pRI<span class="hljs-subst">-></span>socket_id);
    <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-built_in">.</span>
}</code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li></ul>

6、onRequest
此处,我们以Reference-ril中的onRequest为例,进行分析:

<code class="hljs lasso has-numbering">static <span class="hljs-literal">void</span>
onRequest (int request, <span class="hljs-literal">void</span> <span class="hljs-subst">*</span><span class="hljs-built_in">data</span>, size_t datalen, RIL_Token t) {
    <span class="hljs-comment">//判断当前radio状态,是否能够下发AT指令</span>
    <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-built_in">.</span>
    switch (request) {
        <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-built_in">.</span>
        <span class="hljs-keyword">case</span> RIL_REQUEST_SETUP_DATA_CALL:
            <span class="hljs-comment">//下发AT指令,完成拨号</span>
            requestSetupDataCall(<span class="hljs-built_in">data</span>, datalen, t);
            break;
        <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-built_in">.</span>
    }
}</code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li></ul>

7、RIL_onRequestComplete
当指令处理完毕后,Reference-ril将调用RIL_onRequestComplete通知RIL.java处理结果。

<code class="hljs cs has-numbering"><span class="hljs-preprocessor">#<span class="hljs-keyword">define</span> RIL_onRequestComplete(t, e, response, responselen) s_rilenv->OnRequestComplete(t,e, response, responselen)</span></code><ul class="pre-numbering" style=""><li>1</li></ul><ul class="pre-numbering" style=""><li>1</li></ul>

可以看到RIL_onRequestComplete是一个宏,实际上调用的是s_rilenv的OnRequestComplete函数。
在Rild进程的main函数中,调用RIL_Init时传入了s_rilEnv,我们看看ril.cpp中的RIL_onRequestComplete:

<code class="hljs lasso has-numbering">extern <span class="hljs-string">"C"</span> <span class="hljs-literal">void</span>
RIL_onRequestComplete(RIL_Token t, RIL_Errno e, <span class="hljs-literal">void</span> <span class="hljs-subst">*</span>response, size_t responselen) {
    <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-built_in">..</span>
    <span class="hljs-comment">//从参数中,知道请求是从哪个socket发过来的</span>
    socket_id <span class="hljs-subst">=</span> pRI<span class="hljs-subst">-></span>socket_id;
    fd <span class="hljs-subst">=</span> findFd(socket_id);
    <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-built_in">..</span>
    <span class="hljs-keyword">if</span> (pRI<span class="hljs-subst">-></span>cancelled <span class="hljs-subst">==</span> <span class="hljs-number">0</span>) {
        <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-built_in">..</span>
        <span class="hljs-keyword">if</span> (response <span class="hljs-subst">!=</span> <span class="hljs-built_in">NULL</span>) {
            <span class="hljs-comment">// there is a response payload, no matter success or not.</span>
            <span class="hljs-comment">//调用responseDataCall,在返回结果中加入ip地址等信息</span>
            ret <span class="hljs-subst">=</span> pRI<span class="hljs-subst">-></span>pCI<span class="hljs-subst">-></span>responseFunction(p, response, responselen);
            <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-built_in">..</span>
        }
        <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-built_in">..</span>
        sendResponse(p, socket_id);
    }
    <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-built_in">..</span>
}

static int
sendResponse (Parcel <span class="hljs-subst">&</span>p, RIL_SOCKET_ID socket_id) {
    printResponse;
    <span class="hljs-comment">//利用write函数,将数据发往RIL.java</span>
    <span class="hljs-keyword">return</span> sendResponseRaw(p<span class="hljs-built_in">.</span><span class="hljs-built_in">data</span>(), p<span class="hljs-built_in">.</span>dataSize(), socket_id);
}</code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li></ul>

8、processResponse
在前面介绍RILReceiver时,我们知道RILReceiver与Rild连接成功后,将会一直监听发来的数据,并调用processResponse进行处理。

<code class="hljs lasso has-numbering"><span class="hljs-keyword">private</span> <span class="hljs-literal">void</span>
processResponse (Parcel p) {
    int <span class="hljs-keyword">type</span>;

    <span class="hljs-keyword">type</span> <span class="hljs-subst">=</span> p<span class="hljs-built_in">.</span>readInt();

    <span class="hljs-keyword">if</span> (<span class="hljs-keyword">type</span> <span class="hljs-subst">==</span> RESPONSE_UNSOLICITED <span class="hljs-subst">||</span> <span class="hljs-keyword">type</span> <span class="hljs-subst">==</span> RESPONSE_UNSOLICITED_ACK_EXP) {
        <span class="hljs-comment">//处理主动上报</span>
        processUnsolicited (p, <span class="hljs-keyword">type</span>);
    } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (<span class="hljs-keyword">type</span> <span class="hljs-subst">==</span> RESPONSE_SOLICITED <span class="hljs-subst">||</span> <span class="hljs-keyword">type</span> <span class="hljs-subst">==</span> RESPONSE_SOLICITED_ACK_EXP) {
        RILRequest rr <span class="hljs-subst">=</span> processSolicited (p, <span class="hljs-keyword">type</span>);
        <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-built_in">.</span>
    } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (<span class="hljs-keyword">type</span> <span class="hljs-subst">==</span> RESPONSE_SOLICITED_ACK) {
        <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-built_in">.</span>
    }
}

<span class="hljs-keyword">private</span> RILRequest
processSolicited (Parcel p, int <span class="hljs-keyword">type</span>) {
    <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-built_in">.</span>
    <span class="hljs-comment">//根据serialNumber,将队列中的记录移除</span>
    rr <span class="hljs-subst">=</span> findAndRemoveRequestFromList(serial);
    <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-built_in">.</span>
    <span class="hljs-keyword">if</span> (error <span class="hljs-subst">==</span> <span class="hljs-number">0</span> <span class="hljs-subst">||</span> p<span class="hljs-built_in">.</span>dataAvail() <span class="hljs-subst">></span> <span class="hljs-number">0</span>) {
        try {switch (rr<span class="hljs-built_in">.</span>mRequest) {
        <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-built_in">..</span>
        <span class="hljs-keyword">case</span> RIL_REQUEST_SETUP_DATA_CALL: ret <span class="hljs-subst">=</span>  responseSetupDataCall(p); break;
        <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-built_in">..</span>
        }
        <span class="hljs-attribute">...</span><span class="hljs-built_in">.</span>
    }
    <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-built_in">.</span>
    <span class="hljs-keyword">if</span> (error <span class="hljs-subst">==</span> <span class="hljs-number">0</span>) {
        <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-built_in">.</span>
        <span class="hljs-keyword">if</span> (rr<span class="hljs-built_in">.</span>mResult <span class="hljs-subst">!=</span> <span class="hljs-built_in">null</span>) {
            AsyncResult<span class="hljs-built_in">.</span>forMessage(rr<span class="hljs-built_in">.</span>mResult, ret, <span class="hljs-built_in">null</span>);
            <span class="hljs-comment">//将结果返回给DataConnection</span>
            rr<span class="hljs-built_in">.</span>mResult<span class="hljs-built_in">.</span>sendToTarget();
        }
    }
    <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-built_in">.</span>
}</code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li><li>42</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li><li>42</li></ul>

在理解了Rild搭建的通信架构后,分析底层拨号的流程还是比较简单的。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值