Android Telephony分析(三) ---- RILJ详解
2017-09-20 16:41
330 查看
前言
本文主要讲解RILJ工作原理,以便更好地分析代码,分析业务的流程。 这里说的RILJ指的是RIL.java (frameworks\opt\telephony\src\java\com\android\internal\telephony) ,
RILC指的是Ril.cpp (hardware\ril\libril)
1. RILJ的创建
RILJ的继承关系如下: 可以看到RILJ继承自BaseCommands并且实现了CommandsInterface接口,RILJ中有两个子线程RILSender和RILReceiver。
再看看RILJ的构造函数:
public RIL(Context context, int preferredNetworkType, int cdmaSubscription) { super(context); //发送子线程,mInstanceId就是PhoneID mSenderThread = new HandlerThread("RILSender" + mInstanceId); mSenderThread.start(); //接收子线程 mReceiver = new RILReceiver(); mReceiverThread = new Thread(mReceiver, "RILReceiver" + mInstanceId); mReceiverThread.start(); }1
2
3
4
5
6
7
8
9
10
11
在RILJ初始化的时候,启动了RILSender线程用于发送数据,启动了RILReceiver线程用于接收数据。
在《Android Telephony分析(一) — Phone详解 》的第二小节中曾经说到,在创建Phone实例之前会先创建RILJ,一个Phone实例对应一个RILJ实例。
在CallTracker.java、Phone.java、ServiceStateTracker.java我们常常看到的
public CommandsInterface mCi;1
mCi对象都是RILJ实例。
本文来自http://blog.csdn.net/linyongan ,转载请务必注明出处。
2. RILJ的工作原理
RILJ、RILC、Modem的工作流程:RILJRILJRILCRILCModemModem发送Request发送RequestModem处理solicited/unSolicited Responsesolicited/unSolicited Response
RILJ里有RILSender线程用于向RILC发送数据和RILReceiver用于接收来自RILC的数据,但是这些数据的发送和接收是一个异步的过程。
结合同步,才能更好地理解异步:
同步:发送方发出数据后,等接收方发回响应以后才发下一个数据包。
异步:发送方发出数据后,不等接收方发回响应,接着发送下个数据包。
理解这个概念之后,我们再去分析代码,我们就以打电话为例吧。
2.1 RILSender发送Request
前面的拨号流程省略,我们直接从GsmCdmaCallTracker.java的dial()方法开始分析:public synchronized Connection dial(String dialString, int clirMode, UUSInfo uusInfo, Bundle intentExtras)throws CallStateException { ... //先通过obtainCompleteMessage方法得到一个Message mCi.dial(mPendingMO.getAddress(), clirMode, uusInfo, obtainCompleteMessage()); ... } private Message obtainCompleteMessage() { //该消息类型是EVENT_OPERATION_COMPLETE return obtainCompleteMessage(EVENT_OPERATION_COMPLETE); }1
2
3
4
5
6
7
8
9
10
11
12
13
在调用RILJ的方法发起拨号请求之前,先创建一个Message对象,这个Message对象主要用于,当RILJ发起拨号请求,modem返回消息之后,RILJ再通过Message.sendToTarget,这样回调就可以通知GsmCdmaCallTracker,后文2.2.1小节会详细讲。
接着在RILJ中:
//有一个RILRequest列表 SparseArray<RILRequest> mRequestList = new SparseArray<RILRequest>(); @Override public void dial(String address, int clirMode, UUSInfo uusInfo, Message result) { //得到一个RILRequest对象,需要留意result这个Message被存储在哪里 RILRequest rr = RILRequest.obtain(RIL_REQUEST_DIAL, result); //将参数放到RILRequest对象中 rr.mParcel.writeString(address); rr.mParcel.writeInt(clirMode); if (uusInfo == null) { rr.mParcel.writeInt(0); // UUS information is absent } else { rr.mParcel.writeInt(1); // UUS information is present rr.mParcel.writeInt(uusInfo.getType()); rr.mParcel.writeInt(uusInfo.getDcs()); rr.mParcel.writeByteArray(uusInfo.getUserData()); } //输出标志性log,"> "代表RILJ向RILC发送请求。 if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); //Android N新增,作用是打印log? mEventLog.writeRilDial(rr.mSerial, clirMode, uusInfo); //发送请求 send(rr); } static RILRequest obtain(int request, Message result) { RILRequest rr = null; ...... //【重点】外面传递进来的Message对象最终赋值给了rr.mResult rr.mResult = result; ...... return rr; } send(RILRequest rr) { Message msg; if (mSocket == null) { rr.onError(RADIO_NOT_AVAILABLE, null); rr.release(); return; } msg = mSender.obtainMessage(EVENT_SEND, rr); acquireWakeLock(); msg.sendToTarget(); } @Override public void handleMessage(Message msg) { switch (msg.what) { case EVENT_SEND: ...... synchronized (mRequestList) { //把RILRequest对象也会被添加到mRequestList列表中 //等到RILC回应RILJ时,再把RILRequest对象取出来 mRequestList.append(rr.mSerial, rr); } byte[] data; //将数据转换成byte data = rr.mParcel.marshall(); ...... //向socket写入数据 s.getOutputStream().write(dataLength); s.getOutputStream().write(data); } }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
就这样,整个主动向RILC发出请求的流程就将完了。
2.2 RILReceiver接收Response
在RILReceiver线程中class RILReceiver implements Runnable { @Override public void run() { ...... processResponse(p); ...... } } private void processResponse (Parcel p) { int type; type = p.readInt(); //对上报的消息分类处理 if (type == RESPONSE_UNSOLICITED || type == RESPONSE_UNSOLICITED_ACK_EXP) { //对modem主动上报消息的处理 processUnsolicited (p, type); } else if (type == RESPONSE_SOLICITED || type == RESPONSE_SOLICITED_ACK_EXP) { //对之前RILJ发出的Request的回应消息的处理 RILRequest rr = processSolicited (p, type); if (rr != null) { if (type == RESPONSE_SOLICITED) { decrementWakeLock(rr); } rr.release(); } } }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
RILC上报给RILJ的消息可以分成两类:
1. Solicited Response—>对之前RILJ发出的Request进行回应的消息。(一个Request对应一个Response)
2. UnSolicited Response—>modem主动上报的消息。(单方向,由RILC发给RILJ)
2.2.1 处理Solicited Response
继续上面拨号的例子,在RILJ发起拨号请求后,modem处理完之后,返回消息给RILC,最后通知到RILJ。private RILRequest processSolicited (Parcel p, int type) { RILRequest rr; //把RILRequest对象从mRequestList列表中取出来 rr = findAndRemoveRequestFromList(serial); //省略对数据的处理 ..... //输出标志性log,"< "代表RILC向RILJ反馈信息。 if (RILJ_LOGD) riljLog(rr.serialString() + "< " + requestToString(rr.mRequest) + " " + retToString(rr.mRequest, ret)); if (rr.mResult != null) { AsyncResult.forMessage(rr.mResult, ret, null); //是否还记得上面2.1小节中说到rr.mResult存储的是什么对象吗? //这就是在调用RILJ的dial方法前创建的Message对象! //Message.sendToTarget,这样通过回调,流程就回到调用RILJ的dial方法的地方了。 rr.mResult.sendToTarget(); } return rr; }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2.2.2 处理Solicited Response
这里以拨打电话后,modem上报call的状态变化消息RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED为例private void processUnsolicited (Parcel p, int type) { int response; Object ret; //读取当前上报消息的号码 response = p.readInt(); //根据号码找到相应的逻辑处理 switch(response) { case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED: ret = responseVoid(p); break; ....... } //根据号码找到相应的逻辑处理 switch(response) { case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED: if (RILJ_LOGD) unsljLog(response); //【重点】通过RegistrantList机制,继续上报消息 mCallStateRegistrants .notifyRegistrants(new AsyncResult(null, null, null)); break; } } }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
关于RegistrantList机制,请看上一篇文章《Android Telephony分析(二) —- RegistrantList详解》
接着会通知到注册监听Call状态变化的人:
public GsmCdmaCallTracker (GsmCdmaPhone phone) { this.mPhone = phone; mCi = phone.mCi; //注册监听Call状态变化,GsmCdmaCallTracker本质上是Handler //所以第一个参数传递this mCi.registerForCallStateChanged(this, EVENT_CALL_STATE_CHANGE, null); } public void registerForCallStateChanged(Handler h, int what, Object obj) { Registrant r = new Registrant (h, what, obj); //加入mCallStateRegistrants这个RegistrantList中 mCallStateRegistrants.add(r); }1
2
3
4
5
6
7
8
9
10
11
12
13
最终会在GsmCdmaCallTracker的handleMessage方法中对EVENT_CALL_STATE_CHANGE进行处理。
modem主动上报消息的流程也讲解完了。
3 .学以致用
学习完本篇博客的知识,怎么去分析调用RILJ的方法主动发起Request的流程和modem主动上报消息的流程呢? 这里还是以第二小节拨号的代码为例,其他业务流程都可以举一反三。
1.主动发起Request这类代码流程,核心是谁创建Message,之后还是谁对该Message进行处理。
GsmCdmaCallTrackerGsmCdmaCallTrackerRILJRILJModemModem创建Message(EVENT_OPERATION_COMPLETE)dialdialModem处理processSolicited()rr.mResult.sendToTargethandleMessage()
2.modem主动上报消息这类代码流程,核心是谁注册监听了这个消息,那么还是谁对该消息进行处理。
GsmCdmaCallTrackerGsmCdmaCallTrackerRILJRILJModemModemregisterForCallStateChanged()Call状态变化processUnsolicited()mCallStateRegistrants.notifyRegistrants()handleMessage()
最后可以通过log中的“>”和“<”判断消息的方向。
D/RILJ ( 2795): [5655]> DIAL D/RILJ ( 2795): [5655]< DIAL1
2
“>”:是RILJ发请求给modem。
“<”:是modem上报消息给RILJ。
原文地址:http://blog.csdn.net/linyongan/article/details/52066306
相关文章推荐
- Android Telephony分析(三)--- RILJ 详解
- Android Telephony分析(一) ---- Phone详解
- Android Telephony分析(一) ---- Phone详解(Android 7.0)
- Android Telephony分析(一) ---- Phone详解
- Android Telephony分析(一) ---- Phone详解
- Android Telephony分析(五)--- TelephonyRegistry 详解
- Android Telephony分析(二) ---- RegistrantList详解
- Android Telephony分析(四)--- TelephonyManager 详解
- Android Telephony分析(一)--- Phone 详解
- Android源码分析--Handler和Looper机制详解
- Android开源框架分析0——Volley框架详解
- Android触摸屏ViewGroup事件派发机制详解与源码分析
- Android 核心分析 之八------Android 启动过程详解
- Android核心分析之十五Android输入系统之输入路径详解
- Android触摸屏事件派发机制详解与源码分析一(View篇)
- Android中View(视图)绘制不同状态背景图片原理深入分析以及StateListDrawable使用详解
- Android 4.4 KitKat NotificationManagerService使用详解与原理分析(二)__原理分析
- Android之TelephonyManager类的方法详解[转]
- [Android 测试] 压力稳定性测试之: Monkey 详解分析脚本
- Android 4.4.2 SELinux 与系统关系详解一: mac_permissions.xml 生成、编译过程分析