Android Telephony分析(三) ---- RILJ详解

来源:互联网 发布:优斗士网络推广效果 编辑:程序博客网 时间:2024/05/01 01:03

前言

本文主要讲解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]> DIALD/RILJ    ( 2795): [5655]< DIAL 
  • 1
  • 2

“>”:是RILJ发请求给modem。 
“<”:是modem上报消息给RILJ。



原文地址:http://blog.csdn.net/linyongan/article/details/52066306

原创粉丝点击