Android 通信Ril
发布日期:2021-06-30 21:23:22 浏览次数:2 分类:技术文章

本文共 66436 字,大约阅读时间需要 221 分钟。

1总体框架

    Rild是Init进程启动的一个本地服务,这个本地服务并没有使用Binder之类的通讯手段,而是采用了socket通讯这种方式。

Andoid将RIL层分为两个代码空间:RILD管理框架(rild、libril.so),AT相关的xxxril.so动态链接库(libreference-ril.so)。rild把libril.so和libreference-ril.so联系起来,libril.so对上是java的socket通信,对下是把java层的命名分发到libreference-ril.so,而libreference-ril.so则把命名转换层AT的命令,通过串口发送给Modem。将RIL独立成一个动态链接库的好处就是Android系统适应不同的Modem,不同的Mode可以有一个独立的Ril与之对应。

     而ril是具体的AT指令合成者和应答解析者。从最基本的功能来讲,ril建立了一个侦听Socket,等待客户端的连接,然后从该连接上读取RIL-Java成传递来的命令并转化成AT指令发送到Modem。并等待Modem的回应,然后将结果通过套接口传回到Ril-Java层。下图是Ril-D的基本框架:

下面的数据流传递描述图表描述了RIL-JAVA层发出一个电话指令的5 步曲:

 

 

① JAVA层通过socket发送命令到RILD

② RILD在EventLoop线程监听到socket消息,读取后封装成AT指令,通过串口发送给

     Modem。并等待Modem的回应命令

③ ReaderLoop线程不断读取串口端口数据,得到回应。回应信息分为两种,一种是对

于第二步AT指令的回应,另一种是主动上报信息,即URC消息,例如短信送达的

消息。

④ 判断是回应AT命令的回应信息,将消息传送到ril再次处理

⑤ 通过socket,将AT回应消息发送到JAVA

⑥ URC消息通过socket,通知到JAVA。

Ril-d的整体数据流及其控制流示意图:

 

4response流程分析

    Response即modem通过串口回应信息到java层,在AT通讯的过程中有两类Response:一种是请求后给出应答,另一种是通知类,即为不请自来的,例如短信通知达到,我们称该类通知为URC。在Rild中URC和一般的Response是分开处理的,概念上URC由handleUnsolicited处理,而Response由handleFinalResponse来处理。

4.1response调用关系图

 

 




Android的通话RIL通信由浅到深跨越了三个层次:

 

第一层 Applications应用层 (Dialer拨号盘和Phone应用)

第二层 Frameworks框架层(Telephony Frameworks)
第三层 UserLibraries系统运行库层(HAL)
Android手机要实现与网络端的通信,需要跨越三个层:
RIL Java(RILJ):负责将上层APP的通信请求发送给HAL层;(第一层和第二层)
RIL C++(RILD): 系统守护进程,负责将RILJ的请求命令发送给CP(Communication Processor)(第三层)
RILJ属于系统Phone进程的一部分,随Phone进程启动而加载;而RILD守护进程是通过Android的Init进程进行加载的。
RILJ分为了两个模块,RIL模块与Phone模块。其中RIL模块负责进行请求以及相应的处理,它将直接与RIL的原声代码进行通信。而Phone模块则向应用程序开发者提供了一系列的电话功能接口。

1.RIL模块结构

在RIL.java中实现了几个类来进行与下层rild的通信。
它实现了如下几个类来完成操作:
RILRequest:代表一个命令请求
     RIL.RILSender:负责AT指令的发送
     RIL.RILReceiver:用于处理主动和普通上报信息
     RIL.RILSender与RIL.RILReceiver是两个线程。
        RILRequest提供了obtain()方法,用于得到具体的request操作,这些操作被定义在RILConstants.java中 (RILConstants.java中定义的request命令与RIL原生代码中ril.h中定义的request命令是相同的),然后通过 send()函数发送EVENT_SEND,在RIL_Sender线程中处理这个EVENT_SEND将命令写入到stream(socket)中去。 Socket是来自常量SOCKET_NAME_RIL,它与RIL 原生代码部分的s_fdListen所指的socket是同一个。
  当有上报信息来到时,系统将通过RILReciver来得到信息,并进行处理。在RILReciver的生命周期里,它一直监视着 SOCKET_NAME_RIL这个socket,当有数据到来时,它将通过readRilMessage()方法读取到一个完整的响应,然后通过 processResponse来进行处理。
2.Phone模块结构
  Android通过暴露Phone模块来供上层应用程序用户使用电话功能相关的接口。它为用户提供了诸如电话呼叫,短信息,SIM卡管理之类的接口调用。它的核心部分是类GSMPhone,这个是Gsm的电话实现,需要通过PhoneFactory获取这个GSMPhone。
  GSMPhone并不是直接提供接口给上层用户使用,而是通过另外一个管理类TelephonyManager来供应用程序用户使用。
  类TelephonyManager实现了android的电话相关操作。它主要使用两个服务来访问telephony功能:

1.ITelephony,提供给上层应用程序用户与telephony进行操作,交互的接口,在packages/apps/Phone中由PhoneInterfaceManager.java实现。

2.ItelephonyRegistry提供了一个通知机制,将底层来的上报通知给框架中需要得到通知的部分,由TelephonyRegistry.java实现。

  GSMPhone通过PhoneNotifier的实现者DefaultPhoneNotifier将具体的事件转化为函数调用,通知到 TelephonyRegistry。TelephonyRegistry再通过两种方式通知给用户,其一是广播事件,另外一种是通过服务用户在 TelephonyRegistry中注册的IphoneStateListener接口,实现回调(回调方式参见android的aidl机制)。
为方便上层实时监听网络状态、通话状态以及CP的状态变化,RIL提供了一个专门的监听接口IPhoneStateListener.aidl,上层需要监听上述状态变化时,只需要实现上述接口!
详情查看我另外一篇帖子:[系统漏洞]模拟耳机广播实现来电自动接听和拒接 https://www.52pojie.cn/thread-710525-1-1.html

 

 

Android的RIL驱动模块:

在hardware/ril目录下,一共分rild,libril.so以及librefrence_ril.so三个部分,另有一 radiooptions可供自动或手动调试使用。都依赖于include目录中ril.h头文件。
目前cupcake分支上带的是gsm的支持,另有一 cdma分支,这里分析的是gsm驱动。
  GSM模块,AP一直是通过基于串口的AT命令与BB交互。包括到了目前的一些edge或3g模块,或像omap这类ap,bp集成的芯片,已经使用了USB或其他等高速总线通信,但大多仍然使用模拟串口机制来使用AT命令。这里的RIL(Radio Interface Layer)层,主要也就是基于AT命令的操作,如发命令,response解析等。
rild与libril.so以及librefrence_ril.so的关系:

1. rild:仅实现一main函数作为整个ril层的入口点,负责完成初始化。

2. libril.so:与rild结合相当紧密,是其共享库,编译时就已经建立了这一关系。组成部分为ril.cpp,ril_event.cpp。libril.so驻留在rild这一守护进程中,主要完成同上层通信的工作,接受ril请求并传递给librefrence_ril.so, 同时把来自librefrence_ril.so的反馈回传给调用进程。

3. librefrence_ril.so:rild通过手动的dlopen方式加载,结合稍微松散,这也是因为librefrence.so主要负责跟Modem硬件通信的缘故。这样做更方便替换或修改以适配更多的Modem种类。它转换来自libril.so的请求为AT命令,同时监控Modem的反馈信息,并传递回libril.so。在初始化时, rild通过符号RIL_Init获取一组函数指针并以此与之建立联系。

4. radiooptions:radiooptiongs通过获取启动参数, 利用socket与rild通信,可供调试时配置Modem参数。

RILD的初始化

1)   Init.rc执行rild,并创建两个socket:/dev/socket/rild和/dev/socket/rild-debug

service ril-daemon /system/bin/rild
socket rild stream 660 root radio
socket rild stream 660 radio system
另外注意一下这两行,在init中会解析这个socket,并初始化这个socket,所以我们在rild中是找不到socket建立的代码,这里就已经完成了。
     socket rild stream 660 root radio
     socket rild-debug stream 660 radio system
进程中rild.c主要代码:

int main(int argc, char **argv){const char * rilLibPath = NULL;const RIL_RadioFunctions *(*rilInit)(const struct RIL_Env *, int, char **);RIL_setRilSocketName("rild");//通过属性系统获取lib路径:rild.libpathproperty_get(LIB_PATH_PROPERTY, rilLibPath, NULL);//动态加载链接库返回句柄 dlclose卸载掉动态链接库dlHandle = dlopen(rilLibPath, RTLD_NOW);//创建客户端事件监听线程RIL_startEventLoop();//通过dlsym定位到需要执行的函数指针   rilInit = (const RIL_RadioFunctions *(*)(const struct RIL_Env *, int, char **))dlsym(dlHandle, "RIL_Init");//通过属性系统获取参数:rild.libargsproperty_get(LIB_ARGS_PROPERTY, args, "");argc = make_argv(args, s_argv);//reference-ril.so初始化 处理客户端请求的模块reference-ril.c//s_rilEnv建立应答回调机制//返回处理请求的相关接口funcs_inst[0] = rilInit(&s_rilEnv, argc, s_argv);//多卡模式if (isMultiSimEnabled() && !isMultiRild()) {}RIL_setMaxNumClients(numClients);//注册客户端事件处理接口,并创建socket监听事件for (i = 0; i < numClients; i++) {RIL_register(funcs_inst[i], i);}  done:while(1) {// sleep(UINT32_MAX) seems to return immediately on bionicsleep(0x00ffffff);}}

2)      进入rild.cpp的main函数,读取rild.lib的path和rild.libargs系统属性,确定厂商的RIL库和初始化参数。
3)      执行RIL_startEventLoop开启事件队列,进行事件监听。这个函数会建立s_tid_dispatch线程。
4)      加载厂商的RIL库,调用RIL_Init初始化RIL,建立s_tid_mainloop线程。在该线程主循环中会调用at_open建立另一个线程s_tid_reader。
5)      调用RIL_register建立vender ril和ril库之间的联系。获取init.rc中建立的两个socket(rild,rild-debug),进行侦听,并加入消息事件循环中(s_tid_dispatch负责轮询分发)。
RIL_startEventLoop在ril.cpp中实现, 它的主要目的是通过pthread_create(&s_tid_dispatch, &attr, eventLoop, NULL)建立一个dispatch线程,入口点在eventLoop. 而eventLoop中,
会调ril_event.cpp中的ril_event_loop()函数,建立起消息(event)队列机制。
我们来仔细看看这一消息队列的机制,这些代码都在ril_event.cpp中
ril_event.cpp关键代码解析:

enum WakeType {DONT_WAKE, WAKE_PARTIAL, WAKE_FULL}; /*一次请求的dispatch和response函数*/ typedef struct { int requestNumber; void (*dispatchFunction) (Parcel &p, struct RequestInfo *pRI); //只有成功了才回调,主要功能是处理返回值,把返回的数据写到Parcel里面 int(*responseFunction) (Parcel &p, void *response, size_t responselen); } CommandInfo; typedef struct { int requestNumber; int (*responseFunction) (Parcel &p, void *response, size_t responselen); WakeType wakeType; } UnsolResponseInfo; /*一次请求的信息,保包含了token*/ typedef struct RequestInfo { int32_t token;      //this is not RIL_Token ,是一个整形值 CommandInfo *pCI; //包含了request号,处理函数和处理返回值的函数 struct RequestInfo *p_next;//链表的下一个元素 char cancelled; //是否已经cancel了 /*responses to local commands do not go back to command process如果是本地发起的一个request,就不要再将回复发到command进程*/ char local;          } RequestInfo; /*timeout的event使用的,和RequestInfo对应,RequestInfo里面存的是一个来自客户端(或者debug)的请求信息,UserCallbackInfo存的是一个来自内部的请求(不是local,local对应于debug事件)*/ typedef struct UserCallbackInfo{ RIL_TimedCallback p_callback; void *userParam; struct ril_event event; struct UserCallbackInfo *p_next; } UserCallbackInfo;

 

RIL_RadioFunctions s_callbacks = {0, NULL, NULL, NULL, NULL, NULL}; static int s_registerCalled = 0; //RIL_Register已经调用,s_callbacks已经赋值 static pthread_t s_tid_dispatch;  static pthread_t s_tid_reader; //本文件的这个线程值没有使用 static int s_started = 0; //用于标识event_loop已经开始了 static int s_fdListen = -1; //监听客户端连接的server句柄,连接以后会得到s_fdCommand句柄 static int s_fdCommand = -1; //接收来自客户端命令的句柄,所有的request都来自这个句柄 static int s_fdDebug = -1;//监听Debug命令的句柄,连接以后会生成另外一个fd,不过是临时变量 //下面两个是唤醒多路复用(select)的pipe的两端句柄 static int s_fdWakeupRead;  static int s_fdWakeupWrite; static struct ril_event s_commands_event; static struct ril_event s_wakeupfd_event; static struct ril_event s_listen_event; static struct ril_event s_wake_timeout_event; //这个没有使用 static struct ril_event s_debug_event; static const struct timeval TIMEVAL_WAKE_TIMEOUT = {1,0}; static pthread_mutex_t s_pendingRequestsMutex = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t s_writeMutex = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t s_startupMutex = PTHREAD_MUTEX_INITIALIZER; static pthread_cond_t s_startupCond = PTHREAD_COND_INITIALIZER; static pthread_mutex_t s_dispatchMutex = PTHREAD_MUTEX_INITIALIZER; static pthread_cond_t s_dispatchCond = PTHREAD_COND_INITIALIZER; static RequestInfo *s_pendingRequests = NULL; //挂起的请求队列,也就是待处理的请求 static RequestInfo *s_toDispatchHead = NULL; static RequestInfo *s_toDispatchTail = NULL; static UserCallbackInfo *s_last_wake_timeout_info = NULL; static void *s_lastNITZTimeData = NULL; static size_t s_lastNITZTimeDataSize; #if RILC_LOG static char printBuf[PRINTBUF_SIZE]; #endif


 

 

[系统漏洞]模拟耳机广播实现来电自动接听和拒接

 

来电拒接这个应用的比较广泛,通讯录黑名单用的比较多,而来电自动接听由于安全性,4.1以上的系统已经被禁用了.但是android系统还是有漏洞,这里给大家分析下原理,请勿用于不法操作!

低版本实现来电接听和拒接:
新建ITelephony.aidl文件:

[Java] 纯文本查看 复制代码

// ITelephony.aidlpackage com.android.internal.telephony;// Declare any non-default types here with import statementsinterface ITelephony {    /**     * Demonstrates some basic types that you can use as parameters     * and return values in AIDL.     */    boolean void answerRingingCall();}

接听/挂断电话的方法在接口ITelephony.java里面,而这个接口时隐藏的,也就是sdk开发是看不到这个接口的。(注意包名不能改),系统会在gen目录下自动生成ITelephony.java这个接口文件。只要我们获得了ITelephony的实例对象就可以使用endCall()自动挂断和answerRingingCall();自动接听方法了!
因为 ITelephony对象是以一个系统服务我们只能通过反射来获取该对象,直接贴代码吧:

Method method = Class.forName("android.os.ServiceManager").getMethod("getService", String.class);IBinder binder = (IBinder) method.invoke(null, new Object[]{TELEPHONY_SERVICE});ITelephony telephony = ITelephony.Stub.asInterface(binder);

通过Binder机制得到的IBinder对象binder转化成ITelephony对象!
最后,我们还需要在AndroidManifest.xml里面配置下权限:
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.MODIFY_PHONE_STATE"/>然后获取TelephonyManager对象对电话状态进行监听,直接上代码吧

//获取电话服务mTelephonyManager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);mTelephonyManager.listen(new MyPhoneStateListener(), PhoneStateListener.LISTEN_CALL_STATE);

[Java] 纯文本查看 复制代码

/***     * 继承PhoneStateListener类,我们可以重新其内部的各种监听方法     *然后通过手机状态改变时,系统自动触发这些方法来实现我们想要的功能     */    private class MyPhoneStateListener extends PhoneStateListener {        @Override        public void onCallStateChanged(int state, String incomingNumber) {            switch (state) {                case TelephonyManager.CALL_STATE_IDLE:                    result = "手机空闲起来了";                    break;                case TelephonyManager.CALL_STATE_RINGING:                    result = "手机铃声响了,来电号码:" + incomingNumber;                    break;                case TelephonyManager.CALL_STATE_OFFHOOK:                    result = "电话被挂起了";                default:                    break;            }            //Toast.makeText(MyBroadCast.this, ""+result, Toast.LENGTH_SHORT).show();            //textView.setText(result);            super.onCallStateChanged(state, incomingNumber);        }

高版本实现思路:4.1以上系统对answerRingingCall()方法,增加权限检查。只有系统进程才有权限执行这个方法,按照以上的操作编译会报错!有以上2个思路,既然是系统进程才能实现,那么我们伪装成系统APK,在该版本的源码下编译用系统签名打包,植入到sysytem就可以了,这种方法难度比较大,而且有局限性,本人没有试过,按照理论应该是可以实现的!第二种方法android会提供这个MediaButtonBroadcastReceiver广播接收器,这个广播接收器是为了监听耳机上接听电话那个按钮的,来电时只要按一下,就可以接听电话,接着就会调用MediaButtonBroadcastReceiver广播接收器。我们的思路是模拟耳机按键然后发出一条广播,让MediaButtonBroadcastReceiver广播接收器接收,从而达到自动接听的目的!
代码跟之前的一样监听TelephonyManager.CALL_STATE_RINGING来电事件,直接上代码:

//注册模拟耳机接听电话广播IntentFilter mediaButtonIntentFilter = new IntentFilter(Intent.ACTION_MEDIA_BUTTON);registerReceiver(mMediaButtonReceiver, mediaButtonIntentFilter);

//TelephonyManager.CALL_STATE_RINGING中发送广播

Intent meidaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);KeyEvent keyEvent = new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_HEADSETHOOK);meidaButtonIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);sendOrderedBroadcast(meidaButtonIntent, null);

KeyEvent keyEvent = new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_HEADSETHOOK);就是模拟耳机按键动作
然后接收广播,判断耳机按键动作开启自动接听电话

protected class MediaButtonBroadcastReceiver extends BroadcastReceiver {        @Override        public void onReceive(Context context, Intent intent) {            KeyEvent event = (KeyEvent) intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);            if ((event != null) && (event.getKeyCode() == KeyEvent.KEYCODE_HEADSETHOOK)) {                //boolean consumed = PhoneUtils.handleHeadsetHook(phone, event);                //answerCall(phone.getRingingCall());                Method method = null;                try {                    method = Class.forName("android.os.ServiceManager")                            .getMethod("getService", String.class);                } catch (NoSuchMethodException e) {                    e.printStackTrace();                } catch (ClassNotFoundException e) {                    e.printStackTrace();                }                IBinder binder = null;                try {                    binder = (IBinder) method.invoke(null, new Object[]{TELEPHONY_SERVICE});                } catch (IllegalAccessException e) {                    e.printStackTrace();                } catch (InvocationTargetException e) {                    e.printStackTrace();                }                ITelephony telephony = ITelephony.Stub.asInterface(binder);                try {                    telephony.answerRingingCall();                } catch (RemoteException e) {                    e.printStackTrace();                }            } else {            }        }    }

 

不同手机厂商使用的AT命令不完全相同,为了保密,AP与BP之间通过各厂商自己的相关动态库来通信。

RIL模块由rild守护进程、libril.so、librefrence.so三部分组成:

  1.rild模块被编译为一个可执行文件,实现一个main函数作为整个ril模块的入口点。在初始化时使用dlopen打开librefrence_ril.so,从中取出并执行RIL_Init函数,得到RIL_RadioFunctions指针,通过RIL_register()函数注册到libril.so库中,其源码结构如下:

 

 2.libril.so是共享库,主要负责同上层的通信工作,接收ril的请求,并传递给librefrence_ril.so,同时将librefrence_ril.so返回的消息送给调用进程,源码结构如下所示:

 

3.librefrence_ril.so是由各手机厂商自己实现,在rild进程运行中通过dlopen方式加载,主要负责跟modem硬件通信,转换来自libril.so的请求为AT命令,同时监听Modem的反馈信息给libril.so

Android的电话系统主要分为三个部分,java层的各种电话相关应用,java层的Phone Service,主要为上层提供API,同时与native进行通信,可以看做为电话系统的客户端,native层的电话服务进程RILD,负责为上层提供各种电话功能服务,直接与modem进行交互:

Android电话系统设计框架图:

由于Android 开发者使用的Modem 是不一样的,各种指令格式,初始化序列都可能不一样,所以为了消除这些差别,Android 设计者将ril 做了一个抽象,使用一个虚拟电话的概念,不同modem相关的AT指令或者通信协议编译成相应的动态链接库.so文件,Rild 是具体的AT 指令合成者和应答解析者。

 

Android电话系统代码结构图:

 

RILD框架设计

在android的电话系统中,在native层实现了电话服务的服务端,由RILD服务与modem的交互,在java层实现电话的客户端,本文主要介绍电话系统的服务端RILD进程,以下是RILD的设计框架图:

 

RILD源码分析

接下来通过源码对RILD的整个框架进行详细介绍。

在kernel启动完成后,将启动第一个应用进程Init进程,在一文中对init进程的启动流程进行了详细的介绍。init进程在启动过程中将读取init.rc文件来启动一些重量级的native服务,rild进程就是通过配置在init.rc中来启动的。

service ril-daemon /system/bin/rild      class main      socket rild stream 660 root radio      socket rild-debug stream 660 radio system      user root      group radio cache inet misc audio sdcard_rw log  

RILD进程入口函数分析

接下来给出的是RILD进程启动的时序图:

hardware\ril\rild\rild.c

int main(int argc, char **argv)  {      const char * rilLibPath = NULL;      char **rilArgv;      void *dlHandle;      const RIL_RadioFunctions *(*rilInit)(const struct RIL_Env *, int, char **);      const RIL_RadioFunctions *funcs;      char libPath[PROPERTY_VALUE_MAX];      unsigned char hasLibArgs = 0;      int i;    umask(S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH);    //rild启动无参数      for (i = 1; i < argc ;) {          if (0 == strcmp(argv[i], "-l") && (argc - i > 1)) {              rilLibPath = argv[i + 1];              i += 2;          } else if (0 == strcmp(argv[i], "--")) {              i++;              hasLibArgs = 1;              break;          } else {              usage(argv[0]);          }      }    if (rilLibPath == NULL) {        //通过Android属性系统读取属性"rild.libpath"的值,即lib库的存放路径          if ( 0 == property_get(LIB_PATH_PROPERTY, libPath, NULL)) {              goto done;          } else {              rilLibPath = libPath;          }    }  ##################################################################################                              判断是否为模拟器  ##################################################################################  #if 1      {          static char*  arg_overrides[3];          static char   arg_device[32];          int           done = 0;  #define  REFERENCE_RIL_PATH  "/system/lib/libreference-ril.so"          /* first, read /proc/cmdline into memory */          char          buffer[1024], *p, *q;          int           len;          int           fd = open("/proc/cmdline",O_RDONLY);          if (fd < 0) {              LOGD("could not open /proc/cmdline:%s", strerror(errno));              goto OpenLib;          }          //读取/proc/cmdline文件中的内容          do {              len = read(fd,buffer,sizeof(buffer)); }          while (len == -1 && errno == EINTR);          if (len < 0) {              LOGD("could not read /proc/cmdline:%s", strerror(errno));              close(fd);              goto OpenLib;          }          close(fd);          //判断是否为模拟器,对于真机,此处条件为false          if (strstr(buffer, "android.qemud=") != NULL)          {              int  tries = 5;  #define  QEMUD_SOCKET_NAME    "qemud"              while (1) {                  int  fd;                  sleep(1);                  fd = socket_local_client(QEMUD_SOCKET_NAME,                              ANDROID_SOCKET_NAMESPACE_RESERVED,                              SOCK_STREAM );                  if (fd >= 0) {                      close(fd);                      snprintf( arg_device, sizeof(arg_device), "%s/%s",                                  ANDROID_SOCKET_DIR, QEMUD_SOCKET_NAME );                      arg_overrides[1] = "-s";                      arg_overrides[2] = arg_device;                      done = 1;                      break;                  }                  LOGD("could not connect to %s socket: %s",QEMUD_SOCKET_NAME, strerror(errno));                  if (--tries == 0)                      break;              }              if (!done) {                  LOGE("could not connect to %s socket (giving up): %s",                      QEMUD_SOCKET_NAME, strerror(errno));                  while(1)                      sleep(0x00ffffff);              }          }            /* otherwise, try to see if we passed a device name from the kernel */          if (!done) do { //true  #define  KERNEL_OPTION  "android.ril="  #define  DEV_PREFIX     "/dev/"              //判断/proc/cmdline中的内容是否包含"android.ril="              p = strstr( buffer, KERNEL_OPTION );              if (p == NULL)                  break;              p += sizeof(KERNEL_OPTION)-1;              q  = strpbrk( p, " \t\n\r" );              if (q != NULL)                  *q = 0;              snprintf( arg_device, sizeof(arg_device), DEV_PREFIX "%s", p );              arg_device[sizeof(arg_device)-1] = 0;              arg_overrides[1] = "-d";              arg_overrides[2] = arg_device;              done = 1;          } while (0);                    if (done) { //false              argv = arg_overrides;              argc = 3;              i    = 1;              hasLibArgs = 1;              rilLibPath = REFERENCE_RIL_PATH;              LOGD("overriding with %s %s", arg_overrides[1], arg_overrides[2]);          }      }  OpenLib:  #endif  ##################################################################################                              动态库装载  ##################################################################################      switchUser();//设置Rild进程的组用户为radio    //加载厂商自定义的库      ①dlHandle = dlopen(rilLibPath, RTLD_NOW);      if (dlHandle == NULL) {          fprintf(stderr, "dlopen failed: %s\n", dlerror());          exit(-1);    }    //创建客户端事件监听线程    ②RIL_startEventLoop();    //通过dlsym定位到RIL_Init函数的地址,并且强制转换为RIL_RadioFunctions的函数指针      ③rilInit = (const RIL_RadioFunctions *(*)(const struct RIL_Env *, int, char **))dlsym(dlHandle, "RIL_Init");      if (rilInit == NULL) {          fprintf(stderr, "RIL_Init not defined or exported in %s\n", rilLibPath);          exit(-1);      }      if (hasLibArgs) { //false          rilArgv = argv + i - 1;          argc = argc -i + 1;      } else {          static char * newArgv[MAX_LIB_ARGS];          static char args[PROPERTY_VALUE_MAX];          rilArgv = newArgv;          property_get(LIB_ARGS_PROPERTY, args, "");//通过属性系统读取"rild.libargs"属性值          argc = make_argv(args, rilArgv);      }      // Make sure there's a reasonable argv[0]    rilArgv[0] = argv[0];    //调用RIL_Init函数来初始化rild,传入参数s_rilEnv,返回RIL_RadioFunctions地址    ④funcs = rilInit(&s_rilEnv, argc, rilArgv);    //注册客户端事件处理接口RIL_RadioFunctions,并创建socket监听事件      ⑤RIL_register(funcs);  done:      while(1) {          // sleep(UINT32_MAX) seems to return immediately on bionic          sleep(0x00ffffff);      }  }

在main函数中主要完成以下工作:

1.解析命令行参数,通过判断是否为模拟器采取不同的方式来读取libreference-ril.so库的存放路径;

2.使用dlopen手动装载libreference-ril.so库;

3.启动事件循环处理;

4.从libreference-ril.so库中取得RIL_Init函数地址,并使用该函数将libril.so库中的RIL_Env接口注册到libreference-ril.so库,同时将libreference-ril.so库中的RIL_RadioFunctions接口注册到到libril.so库中,建立起libril.so库与libreference-ril.so库通信桥梁;

启动事件循环处理eventLoop工作线程

建立多路I/O驱动机制的消息队列,用来接收上层发出的命令以及往Modem发送AT指令的工作,时整个RIL系统的核心部分。创建一个事件分发线程s_tid_dispatch,线程执行体为eventLoop。

hardware\ril\libril\Ril.cpp 

extern "C" void RIL_startEventLoop(void) {      int ret;      pthread_attr_t attr;      /* spin up eventLoop thread and wait for it to get started */      s_started = 0;      pthread_mutex_lock(&s_startupMutex);      pthread_attr_init (&attr);    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);    //创建一个工作线程eventLoop    ret = pthread_create(&s_tid_dispatch, &attr, eventLoop, NULL);    //确保函数返回前eventLoop线程启动运行      while (s_started == 0) {          pthread_cond_wait(&s_startupCond, &s_startupMutex);      }      pthread_mutex_unlock(&s_startupMutex);      if (ret < 0) {          LOGE("Failed to create dispatch thread errno:%d", errno);          return;      }  }

eventLoop执行时序图:

static void * eventLoop(void *param) {      int ret;      int filedes[2];      ril_event_init(); //初始化请求队列      pthread_mutex_lock(&s_startupMutex);      s_started = 1; //eventLoop线程运行标志位      pthread_cond_broadcast(&s_startupCond);    pthread_mutex_unlock(&s_startupMutex);    //创建匿名管道      ret = pipe(filedes);      if (ret < 0) {          LOGE("Error in pipe() errno:%d", errno);          return NULL;    }    //s_fdWakeupRead为管道读端    s_fdWakeupRead = filedes[0];    //s_fdWakeupWrite为管道写端    s_fdWakeupWrite = filedes[1];    //设置管道读端为O_NONBLOCK非阻塞    fcntl(s_fdWakeupRead, F_SETFL, O_NONBLOCK);    //初始化s_wakeupfd_event结构体的内容,句柄为s_fdWakeupRead,回调函数为   processWakeupCallback      ril_event_set (&s_wakeupfd_event, s_fdWakeupRead, true,processWakeupCallback, NULL);      ①rilEventAddWakeup (&s_wakeupfd_event);      // Only returns on error      ②ril_event_loop();      LOGE ("error in event_loop_base errno:%d", errno);      return NULL;  }

在rild中定义了event的概念,Rild支持两种类型的事件:

1. 定时事件:根据事件的执行时间来启动执行,通过ril_timer_add添加到time_list队列中

2. Wakeup事件:这些事件的句柄fd将加入的select IO多路复用的句柄池readFDs中,当对应的fd可读时将触发这些事件。对于处于listen端的socket,fd可读表示有个客户端连接,此时需要调用accept接受连接。

事件定义如下:

struct ril_event {      struct ril_event *next;      struct ril_event *prev;      int fd;  //文件句柄      int index; //该事件在监控表中的索引       bool persist; //如果是保持的,则不从watch_list 中删除      struct timeval timeout; //任务执行时间      ril_event_cb func; //回调事件处理函数      void *param; //回调时参数  };

在Rild进程中的几个重要事件有

static struct ril_event s_commands_event;  ril_event_set (&s_commands_event, s_fdCommand, 1,processCommandsCallback, p_rs)    static struct ril_event s_wakeupfd_event;  ril_event_set (&s_wakeupfd_event, s_fdWakeupRead, true,processWakeupCallback, NULL)    static struct ril_event s_listen_event;  ril_event_set (&s_listen_event, s_fdListen, false,listenCallback, NULL)    static struct ril_event s_wake_timeout_event;  ril_timer_add(&(p_info->event), &myRelativeTime);  static struct ril_event s_debug_event;  ril_event_set (&s_debug_event, s_fdDebug, true,debugCallback, NULL)

在RILD中定义了三个事件队列,用于处理不同的事件:

/事件监控队列

static struct ril_event * watch_table[MAX_FD_EVENTS];

//定时事件队列

static struct ril_event timer_list;

//处理事件队列

static struct ril_event pending_list; //待处理事件队列,事件已经触发,需要所回调处理的事件

添加事件

1.添加Wakeup 事件

static void rilEventAddWakeup(struct ril_event *ev) {      ril_event_add(ev); //向监控表watch_table添加一个s_wakeupfd_event事件      triggerEvLoop(); //向管道s_fdWakeupWrite中写入之来触发事件循环  }  [cpp] view plaincopyvoid ril_event_add(struct ril_event * ev)  {      dlog("~~~~ +ril_event_add ~~~~");      MUTEX_ACQUIRE();      for (int i = 0; i < MAX_FD_EVENTS; i++) { //遍历监控表watch_table          if (watch_table[i] == NULL) { //从监控表中查找空闲的索引,然后把该任务加入到监控表中              watch_table[i] = ev; //向监控表中添加事件              ev->index = i; //事件的索引设置为在监控表中的索引              dlog("~~~~ added at %d ~~~~", i);              dump_event(ev);              FD_SET(ev->fd, &readFds); //将添加的事件对应的句柄添加到句柄池readFds中              if (ev->fd >= nfds) nfds = ev->fd+1; //修改句柄最大值              dlog("~~~~ nfds = %d ~~~~", nfds);              break;          }      }      MUTEX_RELEASE();      dlog("~~~~ -ril_event_add ~~~~");  }  2.添加定时事件[cpp] view plaincopyvoid ril_timer_add(struct ril_event * ev, struct timeval * tv)  {      dlog("~~~~ +ril_timer_add ~~~~");      MUTEX_ACQUIRE();      struct ril_event * list;      if (tv != NULL) {          list = timer_list.next;          ev->fd = -1; // make sure fd is invalid          struct timeval now;          getNow(&now);          timeradd(&now, tv, &ev->timeout);          // keep list sorted          while (timercmp(&list->timeout, &ev->timeout, < ) && (list != &timer_list)) {              list = list->next;          }          // list now points to the first event older than ev          addToList(ev, list);      }      MUTEX_RELEASE();      dlog("~~~~ -ril_timer_add ~~~~");  }
触发事件[cpp] view plaincopystatic void triggerEvLoop() {      int ret;    if (!pthread_equal(pthread_self(), s_tid_dispatch)) { //如果当前线程ID不等于事件分发线程eventLoop的线程ID        do {              ret = write (s_fdWakeupWrite, " ", 1); //向管道写端写入值1来触发eventLoop事件循环           } while (ret < 0 && errno == EINTR);      }  }  处理事件[cpp] view plaincopyvoid ril_event_loop()  {      int n;      fd_set rfds;      struct timeval tv;      struct timeval * ptv;      for (;;) {          memcpy(&rfds, &readFds, sizeof(fd_set));          if (-1 == calcNextTimeout(&tv)) {              dlog("~~~~ no timers; blocking indefinitely ~~~~");              ptv = NULL;          } else {              dlog("~~~~ blocking for %ds + %dus ~~~~", (int)tv.tv_sec, (int)tv.tv_usec);              ptv = &tv;          }          //使用select 函数等待在FDS 上,只要FDS 中记录的设备有数据到来,select 就会设置相应的标志位并返回。readFDS 记录了所有的事件相关设备句柄。readFDS 中句柄是在在AddEvent 加入的。          printReadies(&rfds);          n = select(nfds, &rfds, NULL, NULL, ptv);           printReadies(&rfds);          dlog("~~~~ %d events fired ~~~~", n);          if (n < 0) {              if (errno == EINTR) continue;              LOGE("ril_event: select error (%d)", errno);              return;          }          processTimeouts(); //从timer_list中查询执行时间已到的事件,并添加到pending_list中          processReadReadies(&rfds, n); //从watch_table中查询数据可读的事件,并添加到pending_list中去处理,如果该事件不是持久事件,则同时从watch_table中删除          //遍历pending_list,调用事件处理回调函数处理所有事件          firePending();      }  }

在eventLoop工作线程中,循环处理到来的事件及定时结束事件,整个处理流程如下图所示:

首先通过Linux中的select多路I/O复用对句柄池中的所有句柄进行监控,当有事件到来时select返回,否则阻塞。当select返回时,表示有事件的到来,通过调用processTimeouts函数来处理超时事件,处理方式是遍历time_list链表以查询超时事件,并将超时事件移入到pending_list链表中,接着调用processReadReadies函数来处理触发的事件,处理方式为遍历watch_table列表以查询触发的事件,并将触发的事件移入到pending_list链表中,如果该事件不是持久事件,还需要从watch_table列表中移除,当查询完两种待处理的事件并放入到pending_list链表中后,调用firePending函数对待处理的事件进行集中处理,处理方式为遍历链表,调用每一个事件的回调函数。

 

1.超时事件查询

static void processTimeouts()  {      dlog("~~~~ +processTimeouts ~~~~");      MUTEX_ACQUIRE();      struct timeval now;      struct ril_event * tev = timer_list.next;      struct ril_event * next;      getNow(&now); //获取当前时间    dlog("~~~~ Looking for timers <= %ds + %dus ~~~~", (int)now.tv_sec, (int)now.tv_usec);    //如果当前时间大于事件的超时时间,则将该事件从timer_list中移除,添加到pending_list      while ((tev != &timer_list) && (timercmp(&now, &tev->timeout, >))) {          dlog("~~~~ firing timer ~~~~");          next = tev->next;          removeFromList(tev); //从timer_list中移除事件          addToList(tev, &pending_list); //将事件添加到pending_list          tev = next;      }      MUTEX_RELEASE();      dlog("~~~~ -processTimeouts ~~~~");  }  2.可读事件查询[cpp] view plaincopystatic void processReadReadies(fd_set * rfds, int n)  {      dlog("~~~~ +processReadReadies (%d) ~~~~", n);    MUTEX_ACQUIRE();     //遍历watch_table数组,根据select返回的句柄n查找对应的事件      for (int i = 0; (i < MAX_FD_EVENTS) && (n > 0); i++) {          struct ril_event * rev = watch_table[i]; //得到相应的事件          if (rev != NULL && FD_ISSET(rev->fd, rfds)) {              addToList(rev, &pending_list); //将该事件添加到pending_list中              if (rev->persist == false) { //如果该事件不是持久事件还要从watch_table中移除                  removeWatch(rev, i);              }              n--;          }      }      MUTEX_RELEASE();      dlog("~~~~ -processReadReadies (%d) ~~~~", n);  }  3.事件处理[cpp] view plaincopystatic void firePending()  {      dlog("~~~~ +firePending ~~~~");      struct ril_event * ev = pending_list.next;      while (ev != &pending_list) { //遍历pending_list链表,处理链表中的所有事件          struct ril_event * next = ev->next;          removeFromList(ev); //将处理完的事件从pending_list中移除          ev->func(ev->fd, 0, ev->param); //调用事件处理的回调函数          ev = next;      }      dlog("~~~~ -firePending ~~~~");  }  RIL_Env定义hardware\ril\include\telephony\ril.h[cpp] view plaincopystruct RIL_Env {      //动态库完成请求后通知处理结果的接口    void (*OnRequestComplete)(RIL_Token t, RIL_Errno e,void *response, size_t responselen);      //动态库unSolicited Response通知接口    void (*OnUnsolicitedResponse)(int unsolResponse, const void *data,size_t datalen);      //向Rild提交一个超时任务的接口      void (*RequestTimedCallback) (RIL_TimedCallback callback,void *param, const struct timeval *relativeTime);  };  hardware\ril\rild\rild.cs_rilEnv变量定义:[cpp] view plaincopystatic struct RIL_Env s_rilEnv = {      RIL_onRequestComplete,      RIL_onUnsolicitedResponse,      RIL_requestTimedCallback  };  在hardware\ril\libril\ril.cpp中实现了RIL_Env的各个接口函数1.RIL_onRequestComplete[cpp] view plaincopyextern "C" void RIL_onRequestComplete(RIL_Token t, RIL_Errno e, void *response, size_t responselen) {      RequestInfo *pRI;      int ret;      size_t errorOffset;      pRI = (RequestInfo *)t;      if (!checkAndDequeueRequestInfo(pRI)) {          LOGE ("RIL_onRequestComplete: invalid RIL_Token");          return;      }      if (pRI->local > 0) {          // Locally issued command...void only!          // response does not go back up the command socket          LOGD("C[locl]< %s", requestToString(pRI->pCI->requestNumber));          goto done;      }      appendPrintBuf("[%04d]< %s",pRI->token, requestToString(pRI->pCI->requestNumber));      if (pRI->cancelled == 0) {          Parcel p;          p.writeInt32 (RESPONSE_SOLICITED);          p.writeInt32 (pRI->token);          errorOffset = p.dataPosition();          p.writeInt32 (e);          if (response != NULL) {              // there is a response payload, no matter success or not.              ret = pRI->pCI->responseFunction(p, response, responselen);              /* if an error occurred, rewind and mark it */              if (ret != 0) {                  p.setDataPosition(errorOffset);                  p.writeInt32 (ret);              }          }          if (e != RIL_E_SUCCESS) {              appendPrintBuf("%s fails by %s", printBuf, failCauseToString(e));          }          if (s_fdCommand < 0) {              LOGD ("RIL onRequestComplete: Command channel closed");          }          sendResponse(p);      }  done:      free(pRI);  }  通过调用responseXXX将底层响应传给客户进程2.RIL_onUnsolicitedResponse[cpp] view plaincopyextern "C" void RIL_onUnsolicitedResponse(int unsolResponse, void *data,                                  size_t datalen)  {      int unsolResponseIndex;      int ret;      int64_t timeReceived = 0;      bool shouldScheduleTimeout = false;      if (s_registerCalled == 0) {          // Ignore RIL_onUnsolicitedResponse before RIL_register          LOGW("RIL_onUnsolicitedResponse called before RIL_register");          return;      }      unsolResponseIndex = unsolResponse - RIL_UNSOL_RESPONSE_BASE;      if ((unsolResponseIndex < 0)          || (unsolResponseIndex >= (int32_t)NUM_ELEMS(s_unsolResponses))) {          LOGE("unsupported unsolicited response code %d", unsolResponse);          return;      }      // Grab a wake lock if needed for this reponse,      // as we exit we'll either release it immediately      // or set a timer to release it later.      switch (s_unsolResponses[unsolResponseIndex].wakeType) {          case WAKE_PARTIAL:              grabPartialWakeLock();              shouldScheduleTimeout = true;          break;          case DONT_WAKE:          default:              // No wake lock is grabed so don't set timeout              shouldScheduleTimeout = false;              break;      }      // Mark the time this was received, doing this      // after grabing the wakelock incase getting      // the elapsedRealTime might cause us to goto      // sleep.      if (unsolResponse == RIL_UNSOL_NITZ_TIME_RECEIVED) {          timeReceived = elapsedRealtime();      }      appendPrintBuf("[UNSL]< %s", requestToString(unsolResponse));      Parcel p;      p.writeInt32 (RESPONSE_UNSOLICITED);      p.writeInt32 (unsolResponse);      ret = s_unsolResponses[unsolResponseIndex].responseFunction(p, data, datalen);      if (ret != 0) {          // Problem with the response. Don't continue;          goto error_exit;      }      // some things get more payload      switch(unsolResponse) {          case RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED:              p.writeInt32(s_callbacks.onStateRequest());              appendPrintBuf("%s {%s}", printBuf,                  radioStateToString(s_callbacks.onStateRequest()));          break;          case RIL_UNSOL_NITZ_TIME_RECEIVED:              // Store the time that this was received so the              // handler of this message can account for              // the time it takes to arrive and process. In              // particular the system has been known to sleep              // before this message can be processed.              p.writeInt64(timeReceived);          break;      }      ret = sendResponse(p);      if (ret != 0 && unsolResponse == RIL_UNSOL_NITZ_TIME_RECEIVED) {          // Unfortunately, NITZ time is not poll/update like everything          // else in the system. So, if the upstream client isn't connected,          // keep a copy of the last NITZ response (with receive time noted          // above) around so we can deliver it when it is connected          if (s_lastNITZTimeData != NULL) {              free (s_lastNITZTimeData);              s_lastNITZTimeData = NULL;          }          s_lastNITZTimeData = malloc(p.dataSize());          s_lastNITZTimeDataSize = p.dataSize();          memcpy(s_lastNITZTimeData, p.data(), p.dataSize());      }      // For now, we automatically go back to sleep after TIMEVAL_WAKE_TIMEOUT      // FIXME The java code should handshake here to release wake lock      if (shouldScheduleTimeout) {          // Cancel the previous request          if (s_last_wake_timeout_info != NULL) {              s_last_wake_timeout_info->userParam = (void *)1;          }          s_last_wake_timeout_info= internalRequestTimedCallback(wakeTimeoutCallback, NULL,                                              &TIMEVAL_WAKE_TIMEOUT);      }      return;  error_exit:      if (shouldScheduleTimeout) {          releaseWakeLock();      }  }  这个函数处理modem从网络端接收到的各种事件,如网络信号变化,拨入的电话,收到短信等。然后传给客户进程。3.RIL_requestTimedCallback[cpp] view plaincopyextern "C" void RIL_requestTimedCallback (RIL_TimedCallback callback, void *param,                                  const struct timeval *relativeTime) {      internalRequestTimedCallback (callback, param, relativeTime);  }  [cpp] view plaincopystatic UserCallbackInfo *internalRequestTimedCallback (RIL_TimedCallback callback, void *param,                                  const struct timeval *relativeTime)  {      struct timeval myRelativeTime;      UserCallbackInfo *p_info;      p_info = (UserCallbackInfo *) malloc (sizeof(UserCallbackInfo));      p_info->p_callback = callback;      p_info->userParam = param;      if (relativeTime == NULL) {          /* treat null parameter as a 0 relative time */          memset (&myRelativeTime, 0, sizeof(myRelativeTime));      } else {          /* FIXME I think event_add's tv param is really const anyway */          memcpy (&myRelativeTime, relativeTime, sizeof(myRelativeTime));      }      ril_event_set(&(p_info->event), -1, false, userTimerCallback, p_info);      ril_timer_add(&(p_info->event), &myRelativeTime);      triggerEvLoop();      return p_info;  }  RIL_RadioFunctions定义客户端向Rild发送请求的接口,由各手机厂商实现。hardware\ril\include\telephony\Ril.h [cpp] view plaincopytypedef struct {      int version; //Rild版本      RIL_RequestFunc onRequest; //AP请求接口      RIL_RadioStateRequest onStateRequest;//BP状态查询      RIL_Supports supports;      RIL_Cancel onCancel;      RIL_GetVersion getVersion;//动态库版本  } RIL_RadioFunctions;  变量定义:[cpp] view plaincopystatic const RIL_RadioFunctions s_callbacks = {      RIL_VERSION,      onRequest,      currentState,      onSupports,      onCancel,      getVersion  };  在hardware\ril\reference-ril\reference-ril.c中实现了RIL_RadioFunctions的各个接口函数1.onRequest[cpp] view plaincopystatic void onRequest (int request, void *data, size_t datalen, RIL_Token t)  {      ATResponse *p_response;      int err;      LOGD("onRequest: %s", requestToString(request));      /* Ignore all requests except RIL_REQUEST_GET_SIM_STATUS      * when RADIO_STATE_UNAVAILABLE.      */      if (sState == RADIO_STATE_UNAVAILABLE          && request != RIL_REQUEST_GET_SIM_STATUS      ) {          RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);          return;      }      /* Ignore all non-power requests when RADIO_STATE_OFF      * (except RIL_REQUEST_GET_SIM_STATUS)      */      if (sState == RADIO_STATE_OFF&& !(request == RIL_REQUEST_RADIO_POWER              || request == RIL_REQUEST_GET_SIM_STATUS)      ) {          RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);          return;      }      switch (request) {          case RIL_REQUEST_GET_SIM_STATUS: {              RIL_CardStatus *p_card_status;              char *p_buffer;              int buffer_size;              int result = getCardStatus(&p_card_status);              if (result == RIL_E_SUCCESS) {                  p_buffer = (char *)p_card_status;                  buffer_size = sizeof(*p_card_status);              } else {                  p_buffer = NULL;                  buffer_size = 0;              }              RIL_onRequestComplete(t, result, p_buffer, buffer_size);              freeCardStatus(p_card_status);              break;          }          case RIL_REQUEST_GET_CURRENT_CALLS:              requestGetCurrentCalls(data, datalen, t);              break;          case RIL_REQUEST_DIAL:              requestDial(data, datalen, t);              break;          case RIL_REQUEST_HANGUP:              requestHangup(data, datalen, t);              break;          case RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND:              // 3GPP 22.030 6.5.5              // "Releases all held calls or sets User Determined User Busy              //  (UDUB) for a waiting call."              at_send_command("AT+CHLD=0", NULL);              /* success or failure is ignored by the upper layer here.                it will call GET_CURRENT_CALLS and determine success that way */              RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);              break;          case RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND:              // 3GPP 22.030 6.5.5              // "Releases all active calls (if any exist) and accepts              //  the other (held or waiting) call."              at_send_command("AT+CHLD=1", NULL);              /* success or failure is ignored by the upper layer here.                it will call GET_CURRENT_CALLS and determine success that way */              RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);              break;          case RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE:              // 3GPP 22.030 6.5.5              // "Places all active calls (if any exist) on hold and accepts              //  the other (held or waiting) call."              at_send_command("AT+CHLD=2", NULL);    #ifdef WORKAROUND_ERRONEOUS_ANSWER              s_expectAnswer = 1;  #endif /* WORKAROUND_ERRONEOUS_ANSWER */              /* success or failure is ignored by the upper layer here.                it will call GET_CURRENT_CALLS and determine success that way */              RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);              break;          case RIL_REQUEST_ANSWER:              at_send_command("ATA", NULL);  #ifdef WORKAROUND_ERRONEOUS_ANSWER              s_expectAnswer = 1;  #endif /* WORKAROUND_ERRONEOUS_ANSWER */              /* success or failure is ignored by the upper layer here.                it will call GET_CURRENT_CALLS and determine success that way */              RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);              break;          case RIL_REQUEST_CONFERENCE:              // 3GPP 22.030 6.5.5              // "Adds a held call to the conversation"              at_send_command("AT+CHLD=3", NULL);              /* success or failure is ignored by the upper layer here.                it will call GET_CURRENT_CALLS and determine success that way */              RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);              break;          case RIL_REQUEST_UDUB:              /* user determined user busy */              /* sometimes used: ATH */              at_send_command("ATH", NULL);              /* success or failure is ignored by the upper layer here.                it will call GET_CURRENT_CALLS and determine success that way */              RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);              break;          case RIL_REQUEST_SEPARATE_CONNECTION:              {                  char  cmd[12];                  int   party = ((int*)data)[0];                  // Make sure that party is in a valid range.                  // (Note: The Telephony middle layer imposes a range of 1 to 7.                  // It's sufficient for us to just make sure it's single digit.)                  if (party > 0 && party < 10) {                      sprintf(cmd, "AT+CHLD=2%d", party);                      at_send_command(cmd, NULL);                      RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);                  } else {                      RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);                  }              }              break;          case RIL_REQUEST_SIGNAL_STRENGTH:              requestSignalStrength(data, datalen, t);              break;          case RIL_REQUEST_REGISTRATION_STATE:          case RIL_REQUEST_GPRS_REGISTRATION_STATE:              requestRegistrationState(request, data, datalen, t);              break;          case RIL_REQUEST_OPERATOR:              requestOperator(data, datalen, t);              break;          case RIL_REQUEST_RADIO_POWER:              requestRadioPower(data, datalen, t);              break;          case RIL_REQUEST_DTMF: {              char c = ((char *)data)[0];              char *cmd;              asprintf(&cmd, "AT+VTS=%c", (int)c);              at_send_command(cmd, NULL);              free(cmd);              RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);              break;          }          case RIL_REQUEST_SEND_SMS:              requestSendSMS(data, datalen, t);              break;          case RIL_REQUEST_SETUP_DATA_CALL:              requestSetupDataCall(data, datalen, t);              break;          case RIL_REQUEST_SMS_ACKNOWLEDGE:              requestSMSAcknowledge(data, datalen, t);              break;          case RIL_REQUEST_GET_IMSI:              p_response = NULL;              err = at_send_command_numeric("AT+CIMI", &p_response);              if (err < 0 || p_response->success == 0) {                  RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);              } else {                  RIL_onRequestComplete(t, RIL_E_SUCCESS,                      p_response->p_intermediates->line, sizeof(char *));              }              at_response_free(p_response);              break;          case RIL_REQUEST_GET_IMEI:              p_response = NULL;              err = at_send_command_numeric("AT+CGSN", &p_response);                if (err < 0 || p_response->success == 0) {                  RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);              } else {                  RIL_onRequestComplete(t, RIL_E_SUCCESS,                      p_response->p_intermediates->line, sizeof(char *));              }              at_response_free(p_response);              break;          case RIL_REQUEST_SIM_IO:              requestSIM_IO(data,datalen,t);              break;          case RIL_REQUEST_SEND_USSD:              requestSendUSSD(data, datalen, t);              break;          case RIL_REQUEST_CANCEL_USSD:              p_response = NULL;              err = at_send_command_numeric("AT+CUSD=2", &p_response);              if (err < 0 || p_response->success == 0) {                  RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);              } else {                  RIL_onRequestComplete(t, RIL_E_SUCCESS,                      p_response->p_intermediates->line, sizeof(char *));              }              at_response_free(p_response);              break;          case RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC:              at_send_command("AT+COPS=0", NULL);              break;          case RIL_REQUEST_DATA_CALL_LIST:              requestDataCallList(data, datalen, t);              break;          case RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE:              requestQueryNetworkSelectionMode(data, datalen, t);              break;          case RIL_REQUEST_OEM_HOOK_RAW:              // echo back data              RIL_onRequestComplete(t, RIL_E_SUCCESS, data, datalen);              break;          case RIL_REQUEST_OEM_HOOK_STRINGS: {              int i;              const char ** cur;              LOGD("got OEM_HOOK_STRINGS: 0x%8p %lu", data, (long)datalen);              for (i = (datalen / sizeof (char *)), cur = (const char **)data ;                      i > 0 ; cur++, i --) {                  LOGD("> '%s'", *cur);              }              // echo back strings              RIL_onRequestComplete(t, RIL_E_SUCCESS, data, datalen);              break;          }          case RIL_REQUEST_WRITE_SMS_TO_SIM:              requestWriteSmsToSim(data, datalen, t);              break;          case RIL_REQUEST_DELETE_SMS_ON_SIM: {              char * cmd;              p_response = NULL;              asprintf(&cmd, "AT+CMGD=%d", ((int *)data)[0]);              err = at_send_command(cmd, &p_response);              free(cmd);              if (err < 0 || p_response->success == 0) {                  RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);              } else {                  RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);              }              at_response_free(p_response);              break;          }          case RIL_REQUEST_ENTER_SIM_PIN:          case RIL_REQUEST_ENTER_SIM_PUK:          case RIL_REQUEST_ENTER_SIM_PIN2:          case RIL_REQUEST_ENTER_SIM_PUK2:          case RIL_REQUEST_CHANGE_SIM_PIN:          case RIL_REQUEST_CHANGE_SIM_PIN2:              requestEnterSimPin(data, datalen, t);              break;          case RIL_REQUEST_GSM_SMS_BROADCAST_ACTIVATION:              requestSmsBroadcastActivation(0,data, datalen, t);              break;          case RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG:               LOGD("onRequest RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG");              requestSetSmsBroadcastConfig(0,data, datalen, t);              break;          case RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG:              requestGetSmsBroadcastConfig(0,data, datalen, t);              break;          default:              RIL_onRequestComplete(t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0);              break;      }  }  对每一个RIL_REQUEST_XXX请求转化成相应的ATcommand,发送给modem,然后睡眠等待,当收到ATcommand的最终响应后,线程被唤醒,将响应传给客户端进程。2.currentState[cpp] view plaincopystatic RIL_RadioState currentState()  {      return sState;  }  3.onSupports[cpp] view plaincopystatic int onSupports (int requestCode)  {      //@@@ todo      return 1;  }  4.onCancel[cpp] view plaincopystatic void onCancel (RIL_Token t)  {      //@@@todo  }  5.getVersion[cpp] view plaincopystatic const char * getVersion(void)  {      return "android reference-ril 1.0";

注册RIL_Env接口

 

由于各手机厂商的AT指令差异,因此与modem交互层需要各手机厂商实现,以动态库的形式提供。作为介于modem与上层的中间层,即要与底层交互也要与上层通信,因此就需要定义一个接口来衔接RILD与动态库,RIL_Env和RIL_RadioFunctions接口就是libril.so与librefrence.so通信的桥梁。是Rild架构中用于隔离通用代码和厂商代码的接口,RIL_Env由通用代码实现,而RIL_RadioFunctions则是由厂商代码实现。

RIL_Init的主要任务:

1. 向librefrence.so注册libril.so提供的接口RIL_Env;

2. 创建一个mainLoop工作线程,用于初始化AT模块,并监控AT模块的状态,一旦AT被关闭,则重新打开并初始化AT;

3. 当AT被打开后,mainLoop工作线程将向Rild提交一个定时事件,并触发eventLoop来完成对modem的初始化;

4. 创建一个readLoop工作线程,用于从AT串口中读取数据;

5.返回librefrence.so提供的接口RIL_RadioFunctions;

hardware\ril\reference-ril\reference-ril.c

hardware\ril\reference-ril\reference-ril.c

const RIL_RadioFunctions *RIL_Init(const struct RIL_Env *env, int argc, char **argv)  {      int ret;      int fd = -1;      int opt;      pthread_attr_t attr;    s_rilenv = env; //将ril.cpp中定义的RIL_Env注册到reference-ril.c中的s_rilenv      while ( -1 != (opt = getopt(argc, argv, "p:d:s:"))) {          switch (opt) {              case 'p':                  s_port = atoi(optarg);                  if (s_port == 0) {                      usage(argv[0]);                      return NULL;                  }                  LOGI("Opening loopback port %d\n", s_port);              break;              case 'd':                  s_device_path = optarg;                  LOGI("Opening tty device %s\n", s_device_path);              break;              case 's':                  s_device_path   = optarg;                  s_device_socket = 1;                  LOGI("Opening socket %s\n", s_device_path);              break;              default:                  usage(argv[0]);                  return NULL;          }      }      if (s_port < 0 && s_device_path == NULL) {          usage(argv[0]);          return NULL;      }      pthread_attr_init (&attr);    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);    //创建一个mainLoop线程    ret = pthread_create(&s_tid_mainloop, &attr, mainLoop, NULL);    //将reference-ril.c中定义的RIL_RadioFunctions返回并注册到ril.cpp中的s_callbacks      return &s_callbacks;  }

mainLoop工作线程是用来初始化并监控AT模块的,一旦AT模块被关闭,就自动打开。

static void * mainLoop(void *param)  {      int fd;      int ret;    AT_DUMP("== ", "entering mainLoop()", -1 );    //为AT模块设置回调函数      at_set_on_reader_closed(onATReaderClosed);      at_set_on_timeout(onATTimeout);      for (;;) {          fd = -1;          while  (fd < 0) { //获得串口AT模块的设备文件描述符              if (s_port > 0) {                  fd = socket_loopback_client(s_port, SOCK_STREAM);              } else if (s_device_socket) {                  if (!strcmp(s_device_path, "/dev/socket/qemud")) {                      /* Qemu-specific control socket */                      fd = socket_local_client( "qemud",                   ANDROID_SOCKET_NAMESPACE_RESERVED,SOCK_STREAM );                      if (fd >= 0 ) {                          char  answer[2];                          if ( write(fd, "gsm", 3) != 3 ||read(fd, answer, 2) != 2 ||                               memcmp(answer, "OK", 2) != 0)                          {                              close(fd);                              fd = -1;                          }                     }                  }                  else                      fd = socket_local_client( s_device_path,    ANDROID_SOCKET_NAMESPACE_FILESYSTEM,SOCK_STREAM );              } else if (s_device_path != NULL) {                  fd = open (s_device_path, O_RDWR);                  if ( fd >= 0 && !memcmp( s_device_path, "/dev/ttyS", 9 ) ) {                      /* disable echo on serial ports */                      struct termios  ios;                      tcgetattr( fd, &ios );                      ios.c_lflag = 0;  /* disable ECHO, ICANON, etc... */                      tcsetattr( fd, TCSANOW, &ios );                  }              }              if (fd < 0) {                  perror ("opening AT interface. retrying...");                  sleep(10);              }          }          s_closed = 0;          //打开AT模块,创建AT读取线程s_tid_reader,fd为modem设备文件句柄          ret = at_open(fd, onUnsolicited);          if (ret < 0) {              LOGE ("AT error %d on at_open\n", ret);              return 0;          }          //向Rild提交超时任务          RIL_requestTimedCallback(initializeCallback, NULL, &TIMEVAL_0);          sleep(1);          //如果AT模块被关闭,则waitForClose返回,重新打开AT,如果AT已打开,则阻塞          waitForClose();          LOGI("Re-opening after close");      }  }  

1.打开AT模块

通过at_open打开文件描述符为fd的AT串口设备,并注册回调函数ATUnsolHandler 

int at_open(int fd, ATUnsolHandler h)  {      int ret;      pthread_t tid;      pthread_attr_t attr;      s_fd = fd;      s_unsolHandler = h;      s_readerClosed = 0;      s_responsePrefix = NULL;      s_smsPDU = NULL;      sp_response = NULL;      /* Android power control ioctl */  #ifdef HAVE_ANDROID_OS  #ifdef OMAP_CSMI_POWER_CONTROL      ret = ioctl(fd, OMAP_CSMI_TTY_ENABLE_ACK);      if(ret == 0) {          int ack_count;          int read_count;          int old_flags;          char sync_buf[256];          old_flags = fcntl(fd, F_GETFL, 0);          fcntl(fd, F_SETFL, old_flags | O_NONBLOCK);          do {              ioctl(fd, OMAP_CSMI_TTY_READ_UNACKED, &ack_count);              read_count = 0;              do {                  ret = read(fd, sync_buf, sizeof(sync_buf));                  if(ret > 0)                      read_count += ret;              } while(ret > 0 || (ret < 0 && errno == EINTR));              ioctl(fd, OMAP_CSMI_TTY_ACK, &ack_count);           } while(ack_count > 0 || read_count > 0);          fcntl(fd, F_SETFL, old_flags);          s_readCount = 0;          s_ackPowerIoctl = 1;      }      else          s_ackPowerIoctl = 0;  #else // OMAP_CSMI_POWER_CONTROL          s_ackPowerIoctl = 0;  #endif // OMAP_CSMI_POWER_CONTROL  #endif /*HAVE_ANDROID_OS*/      pthread_attr_init (&attr);    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);    //创建readerLoop工作线程,该线程用于从串口读取数据      ret = pthread_create(&s_tid_reader, &attr, readerLoop, &attr);      if (ret < 0) {          perror ("pthread_create");          return -1;      }      return 0;  }  

2.添加定时事件RIL_requestTimedCallback

RIL_requestTimedCallback(initializeCallback, NULL, &TIMEVAL_0);    #define RIL_requestTimedCallback(a,b,c) s_rilenv->RequestTimedCallback(a,b,c)  

向定时事件队列中添加一个定时事件,该事件的处理函数为initializeCallback,用于发送一些AT指令来初始化BP的modem。

3.readLoop工作线程

Read loop 解析从Modem 发过来的回应。如果遇到URC 则通过handleUnsolicited 上报的RIL_JAVA。如果是命令的应答,则通过handleFinalResponse 通知send_at_command 有应答结果。

static void *readerLoop(void *arg)  {      for (;;) {          const char * line;          line = readline();          if (line == NULL) {              break;          }          if(isSMSUnsolicited(line)) { //判断是否是SMS 通知              char *line1;              const char *line2;              line1 = strdup(line);              line2 = readline();              if (line2 == NULL) {                  break;              }              if (s_unsolHandler != NULL) {                  s_unsolHandler (line1, line2); //回调通知SMS              }              free(line1);          } else {              processLine(line); //处理接收到的数据,根据line中的指令调用不同的回调函数          }  #ifdef HAVE_ANDROID_OS          if (s_ackPowerIoctl > 0) {              /* acknowledge that bytes have been read and processed */              ioctl(s_fd, OMAP_CSMI_TTY_ACK, &s_readCount);              s_readCount = 0;          }  #endif /*HAVE_ANDROID_OS*/      }      onReaderClosed();      return NULL;  }  

注册RIL_RadioFunctions接口

hardware\ril\libril\ril.cpp

extern "C" void RIL_register (const RIL_RadioFunctions *callbacks) {      int ret;    int flags;    //版本验证      if (callbacks == NULL || ((callbacks->version != RIL_VERSION)&& (callbacks->version < 2))) {           return;      }      if (callbacks->version < RIL_VERSION) {          LOGE ("RIL_register: upgrade RIL to version %d current version=%d",                RIL_VERSION, callbacks->version);      }      if (s_registerCalled > 0) {          LOGE("RIL_register has been called more than once. "Subsequent call ignored");          return;    }      //将reference-ril.c中定义的RIL_RadioFunctions注册到ril.cpp中      memcpy(&s_callbacks, callbacks, sizeof (RIL_RadioFunctions));      s_registerCalled = 1;      for (int i = 0; i < (int)NUM_ELEMS(s_commands); i++) {          assert(i == s_commands[i].requestNumber); //序号验证      }      for (int i = 0; i < (int)NUM_ELEMS(s_unsolResponses); i++) {          assert(i + RIL_UNSOL_RESPONSE_BASE== s_unsolResponses[i].requestNumber);      }      // old standalone impl wants it here.      if (s_started == 0) {          RIL_startEventLoop();      }    // 得到名为rild的socket句柄    s_fdListen = android_get_control_socket(SOCKET_NAME_RIL);      if (s_fdListen < 0) {          LOGE("Failed to get socket '" SOCKET_NAME_RIL "'");          exit(-1);    }    // 监听该socket      ret = listen(s_fdListen, 4);      if (ret < 0) {          LOGE("Failed to listen on control socket '%d': %s",s_fdListen, strerror(errno));          exit(-1);      }      /* 设置s_listen_event事件,一旦有客户端连接,即s_fdListen可读就会导致eventLoop工作线程中的select返回,因为该事件不是持久的,因此调用为listenCallback处理完后,将从watch_table移除该事件,所以Rild只支持一个客户端连接*/    ril_event_set (&s_listen_event, s_fdListen, false,listenCallback, NULL);      /* 添加s_listen_event事件,并触发eventLoop工作线程 */      rilEventAddWakeup (&s_listen_event);  #if 1      // 得到调试socket的句柄rild-debug      s_fdDebug = android_get_control_socket(SOCKET_NAME_RIL_DEBUG);      if (s_fdDebug < 0) {          LOGE("Failed to get socket '" SOCKET_NAME_RIL_DEBUG "' errno:%d", errno);          exit(-1);    }    //监听该socket      ret = listen(s_fdDebug, 4);      if (ret < 0) {          LOGE("Failed to listen on ril debug socket '%d': %s",s_fdDebug, strerror(errno));          exit(-1);    }      /* 设置s_debug_event事件 */      ril_event_set (&s_debug_event, s_fdDebug, true,debugCallback, NULL);      /* 添加s_debug_event事件,并触发eventLoop工作线程  */      rilEventAddWakeup (&s_debug_event);  #endif  }  

打开监听端口,接收来自客户端进程的命令请求,当与客户进程连接建立时调用listenCallback函数,创建单独线程监视并处理所有事件源。

1.客户端连接处理

s_listen_event事件用于处理上层客户端的socket连接,当得到socket连接请求时,eventLoop工作线程里的select返回并自动调用listenCallback回调函数进行处理:

static void listenCallback (int fd, short flags, void *param) {      int ret;      int err;      int is_phone_socket;      RecordStream *p_rs;      commthread_data_t *user_data = NULL;      user_data =(commthread_data_t *)malloc(sizeof(commthread_data_t));      struct sockaddr_un peeraddr;      socklen_t socklen = sizeof (peeraddr);      struct ucred creds;      socklen_t szCreds = sizeof(creds);      struct passwd *pwd = NULL;      assert (s_fdCommand < 0);    assert (fd == s_fdListen);    //接收一个客户端的连接,并将该socket连接保存在变量s_fdCommand中      s_fdCommand = accept(s_fdListen, (sockaddr *) &peeraddr, &socklen);      if (s_fdCommand < 0 ) {          LOGE("Error on accept() errno:%d", errno);          /* start listening for new connections again */          rilEventAddWakeup(&s_listen_event);            return;      }      /* 对客户端权限判断,判断是否是进程组ID为radio的进程发起的连接*/      errno = 0;      is_phone_socket = 0;      err = getsockopt(s_fdCommand, SOL_SOCKET, SO_PEERCRED, &creds, &szCreds);      if (err == 0 && szCreds > 0) {          errno = 0;          pwd = getpwuid(creds.uid);          if (pwd != NULL) {              if (strcmp(pwd->pw_name, PHONE_PROCESS) == 0) {                  is_phone_socket = 1;              } else {                  LOGE("RILD can't accept socket from process %s", pwd->pw_name);              }          } else {              LOGE("Error on getpwuid() errno: %d", errno);          }      } else {          LOGD("Error on getsockopt() errno: %d", errno);      }            if ( !is_phone_socket ) {        LOGE("RILD must accept socket from %s", PHONE_PROCESS);        close(s_fdCommand);        s_fdCommand = -1;        onCommandsSocketClosed();        /* start listening for new connections again */        rilEventAddWakeup(&s_listen_event);        return;      }  #if 0      if(s_dualSimMode) {          if(s_sim_num == 0) {              property_get(SIM_POWER_PROPERTY, prop, "0");              if(!strcmp(prop, "0")) {                  property_set(SIM_POWER_PROPERTY, "1");                  s_callbacks.powerSIM(NULL);              }          } else if(s_sim_num == 1) {              property_get(SIM_POWER_PROPERTY1, prop, "0");              if(!strcmp(prop, "0")) {                  property_set(SIM_POWER_PROPERTY1, "1");                  s_callbacks.powerSIM(NULL);              }          }      } else {          property_get(SIM_POWER_PROPERTY, prop, "0");          if(!strcmp(prop, "0")) {              property_set(SIM_POWER_PROPERTY, "1");              s_callbacks.powerSIM(NULL);          }      }  #endif      //p_rs为RecordStream类型,它内部会分配一个缓冲区来存储客户端发送过来的数据    p_rs = record_stream_new(s_fdCommand, MAX_COMMAND_BYTES);    //添加一个针对接收到的客户端连接的处理事件,从而在eventLoop工作线程中处理该客户端的各种请求      ril_event_set (&s_commands_event, s_fdCommand, 1,processCommandsCallback, p_rs);      rilEventAddWakeup (&s_commands_event);      onNewCommandConnect();  }  

2.客户端通信处理

在listenCallback中首先接收客户端的连接请求,并验证客户端的权限,同时将该客户端以事件的形式添加到eventLoop工作线程中进行监控,当该客户端有数据请求时,eventLoop工作线程从select中返回,并自动调用processCommandsCallback回调函数:

static void processCommandsCallback(int fd, short flags, void *param) {      RecordStream *p_rs;      void *p_record;      size_t recordlen;      int ret;      assert(fd == s_fdCommand);      p_rs = (RecordStream *)param;    for (;;) { //循环处理客户端发送过来的AT命令        //读取一条AT命令          ret = record_stream_get_next(p_rs, &p_record, &recordlen);          if (ret == 0 && p_record == NULL) {              break;          } else if (ret < 0) {              break;          } else if (ret == 0) { /* && p_record != NULL */              //处理客户端发送过来的AT命令              processCommandBuffer(p_record, recordlen);          }      }      if (ret == 0 || !(errno == EAGAIN || errno == EINTR)) {          if (ret != 0) {              LOGE("error on reading command socket errno:%d\n", errno);          } else {              LOGW("EOS.  Closing command socket.");          }          close(s_fdCommand);          s_fdCommand = -1;          ril_event_del(&s_commands_event);          record_stream_free(p_rs);          rilEventAddWakeup(&s_listen_event);          onCommandsSocketClosed();      }  }  

通过processCommandBuffer函数来处理每一条AT命令:

static int processCommandBuffer(void *buffer, size_t buflen) {      Parcel p;      status_t status;      int32_t request;      int32_t token;      RequestInfo *pRI;      int ret;      p.setData((uint8_t *) buffer, buflen);      // status checked at end      status = p.readInt32(&request);      status = p.readInt32 (&token);      if (status != NO_ERROR) {          LOGE("invalid request block");          return 0;      }      if (request < 1 || request >= (int32_t)NUM_ELEMS(s_commands)) {          LOGE("unsupported request code %d token %d", request, token);          return 0;      }      pRI = (RequestInfo *)calloc(1, sizeof(RequestInfo));      pRI->token = token; //AT命令标号      pRI->pCI = &(s_commands[request]); //根据request找到s_commands命令数组中的指定AT命令      ret = pthread_mutex_lock(&s_pendingRequestsMutex);      assert (ret == 0);      pRI->p_next = s_pendingRequests;      s_pendingRequests = pRI;      ret = pthread_mutex_unlock(&s_pendingRequestsMutex);    assert (ret == 0);    //调用指定AT命令的dispatch函数,根据接收来自客户进程的命令和参数,调用onRequest进行处理。      pRI->pCI->dispatchFunction(p, pRI);      return 0;  }  

打电话的AT命令:{RIL_REQUEST_DIAL, dispatchDial, responseVoid},

发短信的AT命令:{RIL_REQUEST_SEND_SMS, dispatchStrings, responseSMS},

3.电话拨打流程

static void dispatchDial (Parcel &p, RequestInfo *pRI) {    RIL_Dial dial; //RIL_Dial存储了打电话的所有信息      RIL_UUS_Info uusInfo;       int32_t sizeOfDial;      int32_t t;      .................. //初始化dial变量      s_callbacks.onRequest(pRI->pCI->requestNumber, &dial, sizeOfDial, pRI);    .................      return;  }  

s_callbacks.onRequest其实就是调用RIL_RadioFunctions中的函数,该函数在前面已介绍过了。

static void onRequest (int request, void *data, size_t datalen, RIL_Token t)  {      switch (request) {          case RIL_REQUEST_DIAL:              requestDial(data, datalen, t);              break;      }  }  
static void requestDial(void *data, size_t datalen, RIL_Token t)  {      RIL_Dial *p_dial;      char *cmd;      const char *clir;      int ret;      p_dial = (RIL_Dial *)data;      switch (p_dial->clir) {          case 1: clir = "I"; break;  /*invocation*/          case 2: clir = "i"; break;  /*suppression*/          default:          case 0: clir = ""; break;   /*subscription default*/    }    //向串口发送AT指令      ret = at_send_command(cmd, NULL);    free(cmd);    //通知请求结果      RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);  }  

向AT发送完拨号指令后,通过RIL_onRequestComplete返回处理结果,RIL_onRequestComplete实际上是RIL_Env中的函数,在前面我们也介绍过了

extern "C" void RIL_onRequestComplete(RIL_Token t, RIL_Errno e, void *response, size_t responselen) {      RequestInfo *pRI;      int ret;      size_t errorOffset;    pRI = (RequestInfo *)t;    //该请求已经处理,需要从请求队列中移除该请求      if (!checkAndDequeueRequestInfo(pRI)) {          LOGE ("RIL_onRequestComplete: invalid RIL_Token");          return;      }      if (pRI->local > 0) {          ...........          sendResponse(p);      }  done:      free(pRI);  }  
static int sendResponse (Parcel &p) {      return sendResponseRaw(p.data(), p.dataSize()); //将结果发送给JAVA RIL客户端  }

 

static int sendResponseRaw (const void *data, size_t dataSize) {      int fd = s_fdCommand;      int ret;      uint32_t header;      if (s_fdCommand < 0) {          return -1;      }      if (dataSize > MAX_COMMAND_BYTES) {          return -1;      }      pthread_mutex_lock(&s_writeMutex);      header = htonl(dataSize);      ret = blockingWrite(fd, (void *)&header, sizeof(header));      if (ret < 0) {          pthread_mutex_unlock(&s_writeMutex);          return ret;      }      ret = blockingWrite(fd, data, dataSize);      if (ret < 0) {          pthread_mutex_unlock(&s_writeMutex);          return ret;      }      pthread_mutex_unlock(&s_writeMutex);      return 0;  }  

拨打电话的时序图如下:

 

Rild通过onRequest向动态库提交一个请求,然后返回,动态库处理完请求后,处理结果通过回调接口通知客户端

转载地址:https://liwangjiang.blog.csdn.net/article/details/89228177 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:Android STK APP流程
下一篇:Android Mms:PDU介绍(协议数据单元)

发表评论

最新留言

逛到本站,mark一下
[***.202.152.39]2024年04月17日 23时49分23秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章

Boundary loss 损失函数 2019-04-30
神经网络调参实战(一)—— 训练更多次数 & tensorboard & finetune 2019-04-30
tensorflow使用tensorboard进行可视化 2019-04-30
神经网络调参实战(二)—— activation & initializer & optimizer 2019-04-30
凸优化 convex optimization 2019-04-30
数据库索引 & 为什么要对数据库建立索引 / 数据库建立索引为什么会加快查询速度 2019-04-30
IEEE与APA引用格式 2019-04-30
research gap 2019-04-30
pytorch训练cifar10数据集查看各个种类图片的准确率 2019-04-30
Python鼠标点击图片,获取点击点的像素坐标 2019-04-30
路径规划(一) —— 环境描述(Grid Map & Feature Map) & 全局路径规划(最优路径规划(Dijkstra&A*star) & 概率路径规划(PRM&RRT)) 2019-04-30
神经网络调参实战(四)—— 加深网络层次 & 批归一化 batch normalization 2019-04-30
数据挖掘与数据分析(三)—— 探索性数据分析EDA(多因子与复合分析) & 可视化(1)—— 假设检验(μ&卡方检验&方差检验(F检验))&相关系数(皮尔逊&斯皮尔曼) 2019-04-30
RRT算法(快速拓展随机树)的Python实现 2019-04-30
路径规划(二) —— 轨迹优化(样条法) & 局部规划(人工势能场法) & 智能路径规划(生物启发(蚁群&RVO) & 强化学习) 2019-04-30
D*算法 2019-04-30
强化学习(四) —— Actor-Critic演员评论家 & code 2019-04-30
RESTful API 2019-04-30
优化算法(四)——粒子群优化算法(PSO) 2019-04-30
数据挖掘与数据分析(三)—— 探索性数据分析EDA(多因子与复合分析) & 可视化(2)——回归分析(最小二乘法&决定系数&残差不相关)&主成分分析&奇异值分解 2019-04-30