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

前言

本文主要讲解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(); 
}  

在RILJ初始化的时候,启动了RILSender线程用于发送数据,启动了RILReceiver线程用于接收数据。
《Android Telephony分析(一) — Phone详解 》的第二小节中曾经说到,在创建Phone实例之前会先创建RILJ,一个Phone实例对应一个RILJ实例。
在CallTracker.java、Phone.java、ServiceStateTracker.java我们常常看到的

    public CommandsInterface mCi;

mCi对象都是RILJ实例。


http://blog.csdn.net/linyongan


2. RILJ的工作原理

RILJ、RILC、Modem的工作流程:

Created with Raphaël 2.1.0 RILJ RILJ RILC RILC Modem Modem 发送Request 发送Request Modem处理 solicited/unSolicited Response solicited/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);
    }

在调用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);
          }
     }            

就这样,整个主动向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();
            }
        }
    }

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;  
} 

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;
            }
        }  
    }  

关于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);
   }

最终会在GsmCdmaCallTracker的handleMessage方法中对EVENT_CALL_STATE_CHANGE进行处理。
modem主动上报消息的流程也讲解完了。


3 .学以致用

学习完本篇博客的知识,怎么去分析调用RILJ的方法主动发起Request的流程和modem主动上报消息的流程呢?
这里还是以第二小节拨号的代码为例,其他业务流程都可以举一反三。
1.主动发起Request这类代码流程,核心是谁创建Message,之后还是谁对该Message进行处理。

Created with Raphaël 2.1.0 GsmCdmaCallTracker GsmCdmaCallTracker RILJ RILJ Modem Modem 创建Message(EVENT_OPERATION_COMPLETE) dial dial Modem处理 processSolicited() rr.mResult.sendToTarget handleMessage()

2.modem主动上报消息这类代码流程,核心是谁注册监听了这个消息,那么还是谁对该消息进行处理。

Created with Raphaël 2.1.0 GsmCdmaCallTracker GsmCdmaCallTracker RILJ RILJ Modem Modem registerForCallStateChanged() Call状态变化 processUnsolicited() mCallStateRegistrants.notifyRegistrants() handleMessage()

最后可以通过log中的“>”和“<”判断消息的方向。

D/RILJ    ( 2795): [5655]> DIAL
D/RILJ    ( 2795): [5655]< DIAL 

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

  • 18
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
《深入理解Android:Telephony原理剖析与最佳实践》为经典畅销书“深入理解Android”系列新作,从源码角度深入解析Telephony的架构设计与实现原理,深刻揭示Android系统的通信机制! 本书是“深入理解Android”系列的第3本,前两本书的内容和质量在Android开发者社群内得到了高度认可,已经树立起该系列图书的品牌。在写作思路和方式上,本书与前两本书一脉相承,对它们的优点进行了继承和发扬;在内容上,本书从从源代码角度深入解析了Android Telephony的架构设计与实现原理,深刻揭示了Android系统的通信机制。对于Android应用开发工程师和系统工程师而言,本书都是难得的研究和学习资料。 全书共13章,分为五部分:第一部分(1~3章),首先介绍了智能手机的系统结构、Android系统的架构、Telephony框架的结构,然后详细介绍了Android源代码编译环境和阅读环境的搭建方法,以及阅读本书要做的技术准备;第二部分(4~6章),对Android的通话功能进行了深入的分析,包括对通话流程的分析、对主动拨号和来电流程的分析、对通话应用机制的分析,以及对手机通信功能在框架层和应用层中的实现机制的分析;第部分(7~9章),对Android的通信功能进行了深入的分析,包括对网络服务状态的运行机制的分析、对Android手机上网的实现机制的分析,以及对短息发送和接收流程的分析;第四部分(10~12章),对Android RIL的工作机制进行了深入的分析,包括对框架层中的RILJ运行机制的分析、对RILC系统结构及LibRIL运行机制的分析,以及对Reference-RIL框架的原理的分析;第五部分(13章),分析了Tele
android telephony原理解析与开发指南》是杨青平编写的一本关于Android手机通讯系统的原理和开发指南的书籍。本书主要介绍了Android手机通讯系统的工作原理、架构和相关开发技术。 首先,本书对Android手机通讯系统的工作原理进行了深入解析。Android手机通讯系统是由Android操作系统及其上层应用程序组成的,通过多个模块协同工作实现电话通信功能。本书从系统启动过程、应用层协议、信令流程等方面详细介绍了Android手机通讯系统的运行原理。 其次,本书介绍了Android手机通讯系统的架构。Android手机通讯系统的架构主要包括RIL、Telephony Service和Phone App等重要组件。作者详细解释了各个组件的功能和相互之间的关系,帮助读者理解Android手机通讯系统的整体架构。 同时,本书还提供了Android手机通讯系统开发的指南。作者从配置环境、开发工具和开发步骤等方面详细介绍了Android手机通讯系统的开发过程。读者可以学习到如何使用Android SDK进行开发,如何编写Telephony Service和Phone App等应用程序。 《android telephony原理解析与开发指南》是一本系统而实用的Android手机通讯系统开发指南。通过阅读本书,读者可以全面了解Android手机通讯系统的原理和架构,掌握Android手机通讯系统开发的技巧和方法。作为一名Android开发者,这本书将成为您在Android手机通讯系统开发中的实用指南。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值