资源描述
坚持做总结 进步多点点
Android软件流程之App&&Framework&&Ril
(待续)
前 言
本人主要负责Android的Phone模块的bug修改,经过几个月的学习,熟悉了Phone模块ARM11(App、Framework与Ril)的整体框架。本文我将带领大家熟悉Android的App层与Framework层与Ril层如何进行交互,让大家了解具体代码流程,了解体系的整体框架。下面我将首先介绍App层、Framework层的详细流程,之后是Ril层。
在看本文之前希望读者能对一下知识有所了解,特别是Android的Handler机制,当然在文章中我也会对下面知识加以简单介绍。
Ø 面向对象编程思想
Ø 设计模式
Ø Android的Handle ,Message ,Looper 机制
第一部分
Android软件流程之App&&Framework
一. 简述
1. Ril概述
RIL(Radio Interface Layer)工作在Android的Framework层之下,主要有c语言编写,还有一部分c++,它主要负责数据的可靠传输、上层命令的发送以及response的解析。当然,除了对网络的支持,RIL也支持SMS、Call等功能。当然这么说还是很抽象,下面我们就来看看Ril和上层进行交互的所有“消息”。
2. Ril和上层进行交互的 “信息”
这里我所谓的“消息”,其实可以概括为二种:
ü Request:
上层,也就是App层和Framework层下发给Ril层的一些请求(如打电话RIL_REQUEST_DIAL, 获取SIM卡的状态RIL_REQUEST_GET_SIM_STATUS等),最终由Ril层把这些请求下发给ARM9侧。
ü Response:
Response代表ARM9侧向ARM11侧上报的一些信息,它又可以分为两种
² UNSOL_RESPONSE:主动上报的一些信息,如来短信,
² SOL_RESPONSE:上层下发的一些请求,是需要有应答的,也可以说是响应的,如我下发了RIL_REQUEST_GET_SIM_STATUS,需要Ril上报回来SIM_STATUS,我们把这些上报信息称为命令的响应。
这些“消息”分别在framework层和ril层,都有定义,framework层定义在com.android.internal.telephony包中的Rilcommands.java中,ril层在ril_commands.h中定义,这两处的定义是完全一致的,每条“信息”都是一一对应的。
下面我把所有的这些“信息”,都汇总在下面,并进行的简单的描述,来让大家知道Ril到底在和App和Framework进行哪些“交互”:
下面我将根据具体“消息”的讲述其功能、流程,以这些“消息”为出发点,开始我们的“流程之旅”
二. 具体的流程
1、/*取得SIM卡的状态*/
ü RIL_REQUEST_GET_SIM_STATUS
ü RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED
Android手机中,上层(注:本文中所说的“上层”如不做特别说明,代表App层和Framework层)不会主动下发RIL_REQUEST_GET_SIM_STATUS获取SIM卡请求,而会在Ril层主动上报RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED后,才会发送RIL_REQUEST_GET_SIM_STATUS
下面让我们来看具体流程
1)Ril层主动上报RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED
在上层中最终与Ril层进行对话的最后一道门是Ril.java,这个文件的非常重要,以至于你如果能把Ril.java中的类和方法全部搞懂,你就不用看这篇文章了,你已经了解了上层的基本流程。
下面我先介绍下Ril.java这个文件,这个文件定义了两个类RILRequest类和Ril类,其中Ril类有定义了两个内部类RILReceiver和RILSender,各个类的关系与作用见下图:
在Ril构造函数中,我们会开启RILReceiver线程,
之后RILReceiver线程就开始监听Ril层是否有上报信息,具体的就是监听上层与Ril层的socket通道
Ril层上报的信息是以Parcel类型传上来的,通过监听Socket通道,一旦有信息上报,就进入了信息的处理函数processResponse (Parcel p):
在processResponse (Parcel p)中通过读取P的“第一位”信息,判断上报信息的类型,对主动上报和命令的响应两种信息分别处理,由于RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED是主动上报的所以进入processUnsolicited (Parcel p):
protected void processUnsolicited (Parcel p){
……
Response=p.readInt()
//读取P中的“第二位”信息,注意与第一次p.readInt()的值并不一样
……
……
……
……
上面的process函数通过读取Ril上报的p的“第二位”信息判断出来是上报的具体信息是RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED,最后调用setRadioStateFromRILInt(p.readInt())函数,并读取p中的“第三位”信息并作为参数.
通过p中打包的第三位数值。判断出来,具体的上报信息,并把这个具体的无线状态赋值给一个枚举类型newstate,并最后调用setRadioState(RadioState newState)。上面所说的newstate是了枚举类型,它定义在Basecomands中:
enum RadioState {
RADIO_OFF, /* Radio explictly powered off (eg CFUN=0) */
RADIO_UNAVAILABLE, /* Radio unavailable (eg, resetting or not booted) */ SIM_NOT_READY, /* Radio is on, but the SIM interface is not ready */
SIM_LOCKED_OR_ABSENT, /* SIM PIN locked, PUK required, network
personalization, or SIM absent */
SIM_READY, /* Radio is on and SIM interface is available */
RUIM_NOT_READY, /* Radio is on, but the RUIM interface is not ready */
RUIM_READY, /* Radio is on and the RUIM interface is available */
RUIM_LOCKED_OR_ABSENT, /* RUIM PIN locked, PUK required, network
personalization locked, or RUIM absent */
NV_NOT_READY, /* Radio is on, but the NV interface is not available */
NV_READY; /* Radio is on and the NV interface is available */
public boolean isOn() /* and available...*/ {
return this == SIM_NOT_READY
|| this == SIM_LOCKED_OR_ABSENT
|| this == SIM_READY
|| this == RUIM_NOT_READY
|| this == RUIM_READY
|| this == RUIM_LOCKED_OR_ABSENT
|| this == NV_NOT_READY
|| this == NV_READY;
}
public boolean isAvailable() {
return this != RADIO_UNAVAILABLE;
}
public boolean isSIMReady() {
return this == SIM_READY;
}
public boolean isRUIMReady() {
return this == RUIM_READY;
}
……
……
它其中不仅含有上报具体信息的定义,还提供了一些方法,如isNVReady(),这些方法都是通过上报的具体信息做的一些简单逻辑判断。
下面是setRadioState的定义:
com.android.internal.telephony - frameworks/base/telephony/java– BaseCommand.java
/**
*All Registers:
*CdmaDataConnectionTracker:调用虚函数onRadioAvailable()
*CDMAPhone:调用getBasebandVersion()发送RIL_REQUEST_BASEBAND_VERSIO请求获取基带版本
getDeviceIdentity()发送RIL_REQUEST_DEVICE_IDENTITY请求
*CdmaServiceStateTracker:Do Nothing
*/
if (mState.isAvailable() && !oldState.isAvailable()) {
Log.d(LOG_TAG,"Notifying: radio available");
mAvailRegistrants.notifyRegistrants();
onRadioAvailable();
}
/**
*All Registers:
*CdmaCallTracker: 调用handleRadioNotAvailable()
* ->pollCallsWhenSafe()
* ->RIL_REQUEST_GET_CURRENT_CALLS请求
*/
if (!mState.isAvailable() && oldState.isAvailable()) {
Log.d(LOG_TAG,"Notifying: radio not available");
mNotAvailRegistrants.notifyRegistrants();
}
if (mState.isSIMReady() && !oldState.isSIMReady()) {
Log.d(LOG_TAG,"Notifying: SIM ready");
mSIMReadyRegistrants.notifyRegistrants();
}
if (mState == RadioState.SIM_LOCKED_OR_ABSENT) {
Log.d(LOG_TAG,"Notifying: SIM locked or absent");
mSIMLockedRegistrants.notifyRegistrants();
}
/**
*All Registers:
* CdmaServiceStateTracker: 调用getCDMASubscription
* ->发送RIL_REQUEST_CDMA_SUBSCRIPTION请求
* RuimCard:调用getIccCardStatus
* ->发送RIL_REQUEST_GET_SIM_STATUS请求
* RuimRecords:调用onRuimReady()
* ->发送广播broadcastIccStateChangedIntent
* ->调用getIccCardStatus
* ->发送RIL_REQUEST_GET_SIM_STATUS请求
*/
if (mState.isRUIMReady() && !oldState.isRUIMReady()) {
Log.d(LOG_TAG,"Notifying: RUIM ready");
mRUIMReadyRegistrants.notifyRegistrants();
}
/**
*All Registers:
* RuimCard: 调用getIccCardStatus()
* ->发送RIL_REQUEST_GET_CURRENT_CALLS请求
*/
if (mState == RadioState.RUIM_LOCKED_OR_ABSENT) {
Log.d(LOG_TAG,"Notifying: RUIM locked or absent");
mRUIMLockedRegistrants.notifyRegistrants();
}
/**
*All Registers:
* CdmaDataConnectionTracker: 调用onNVReady()
* —>onTrySetupData
* CDMAPhone: 调用mNvLoadedRegistrants.notifyRegistrants()
* ->通知它并的Registers
* CdmaServiceStateTracker:
* 调用cm.getCDMASubscription()
* ->发送RIL_REQUEST_CDMA_SUBSCRIPTION请求
* pollState()
*/
if (mState.isNVReady() && !oldState.isNVReady()) {
Log.d(LOG_TAG,"Notifying: NV ready");
mNVReadyRegistrants.notifyRegistrants();
}
/**
*All Registers:
* SMSDispatcher: 调用reportSmsMemoryStatus
* —>RIL_REQUEST_REPORT_SMS_MEMORY_STATUS请求
* CdmaCallTracker: 调用handleRadioAvailable()
* -> pollCallsWhenSafe()
* ->发送RIL_REQUEST_GET_CURRENT_CALLS请求
* CdmaPhone: Do Nothing
*/
if (mState.isOn() && !oldState.isOn()) {
Log.d(LOG_TAG,"Notifying: Radio On");
mOnRegistrants.notifyRegistrants();
}
/**
*All Registers:
* CdmaDataConnectionTracker: 调用虚函数onRadioOffOrNotAvailable()
* RuimCard: 发送广播 broadcastIccStateChangedIntent *
* RuimRecords: 调用RuimRecords中onRadioOffOrNotAvailable()
*/
if ((!mState.isOn() || !mState.isAvailable())
&& !((!oldState.isOn() || !oldState.isAvailable()))
) {
Log.d(LOG_TAG,"Notifying: radio off or not available");
mOffOrNotAvailRegistrants.notifyRegistrants();
}
if (mState.isGsm() && oldState.isCdma()) {
mRadioTechnologyChangedRegistrants.notifyRegistrants();
}
if (mState.isGsm() && !oldState.isOn() && (mPhoneType == Phone.PHONE_TYPE_CDMA)) {
mRadioTechnologyChangedRegistrants.notifyRegistrants();
}
/**
*All Registers:
* PhoneProxy: 根据上报信息,进行GSM和CDMA两者切换
*/
if (mState.isCdma() && oldState.isGsm()) {
mRadioTechnologyChangedRegistrants.notifyRegistrants();
}
/**
*All Registers:
* PhoneProxy: 根据上报信息,进行GSM和CDMA两者切换
*/
if (mState.isCdma() && !oldState.isOn() && (mPhoneType == Phone.PHONE_TYPE_GSM)) {
mRadioTechnologyChangedRegistrants.notifyRegistrants();
}
前面代码中我对每个上报信息的“注册者”,做了简单的介绍。这里所谓的注册者其实就是,Ril上报的信息,都会有哪些地方、哪些类响应此信息。比如,如果我们需要在某个类中响应RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED信息,我们只需要在这个类中调用注册函数,那么他就成为了这个信息的注册者也可以叫做监听者,注册者会被存储在Registantlist中,每个信息都对应一个Registantlist实例。当有上报信息时,它会通过调用notifyRegistrants函数,通知这个list中的所有注册者。
下面我们来选取一个具体的上报信息RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED-> RUIM_READY,跟踪一下它的具体流程,其它的上报信息走的流程大同小异。读者有兴趣的可以自己跟一下。
上图是我对上报RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED-> RUIM_READY信息的函数,做了简单的介绍。下面我们来针对每个部分做已详细的介绍:
上图大概说明了如何成为一个注册者,如果我们需要监听某一个上报信息,只需要调用相应接口函数,本例中我们需要在RuimCard类中监听RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED-> RUIM_READY信息,所以调用了CommandsInterface接口中的registerForRUIMReady注册函数,其具体定义是在实现CommandsInterface接口的BaseCommands类中。
上面的讲解大家肯定会很迷惑,下面我们就来进入上面那个注册函数的具体定义来加深对上图的理解:
首先有必要先讲一下这个注册函数的参数
Handler:在注册者中定义,当有消息上报时,会在其中的handlemessage中响应。
(这里用到了Android的Handler机制,建议先阅读附录)
What:在注册中定义,当消息上报时,注册者会被通知的what这个信息。
下面是调用的注册函数的定义,在BaseCommands类中:
到此,我们把这个注册者加入到了mRUIMReadyRegistrants中,一旦上报RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED-> RUIM_READY信息就会执行
……
if (mState.isRUIMReady() && !oldState.isRUIMReady()) {
Log.d(LOG_TAG,"Notifying: RUIM ready");
mRUIMReadyRegistrants.notifyRegistrants();
……
通过mRUIMReadyRegistrants.notifyRegistrants()通知mRUIMReadyRegistrants中的所有注册者。
现在我们假设Ril层上报给我们了RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED-> RUIM_READY消息,那么根据前面所讲,注册者会在注册时候传入的mHandler中响应到该消息,并做相应的处理,让我们来回到注册者,当然,现在他的身份其实是一个被通知者,
到此我们的ril上报信息、上层注册者的注册与响应的整个流程已经全部讲解完毕。
下面我们来讲一下上层下发请求的流程:
让我们回到刚才RuimCard这个注册者接收到RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED-> RUIM_READY信息的响应处理函数:
mPhone.mCM.getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE))
其中obtainMessage(EVENT_GET_ICC_STATUS_DONE)函数很重要,函数作用是把RuimCard中定义的mHandler和EVENT_GET_ICC_STATUS_DONE存储在一个Message实例里面,并返回这个Message实例。并把这个实例作为参数传进getIccCardStatus(Message result),下面我们来重点讲一下这个传下去Message实例的作用。
当我们发送一个请求后,我们会等待ril层给我们上报这个请求的响应(当然有的请求是不需要响应的,我们这里面谈论的是需要响应的请求),这个响应就是我最开始定义的SOL_RESPONSE,前面对于主动上报的消息UNSOL_RESPONSE,已经做了详细的介绍是通过注册-通知机制完成的,那么这个SOL_RESPONSE也就是请求的响应消息,是如何上报的呢?上报给谁的呢?这其实完全决定于下发请求时候,传下来的这个Message实例,以getIccCardStatus为例,它传下去的Message实例(通过obtainMessage函数获得)里面包含RuimCard中定义的mHandler,那么当请求的响应到来的时候这个mHandler中的handleMessage会响应到,并调用相应的处理函数。
上面的响应函数调用的是mCM接口中的getIccCardStatus函数,其具体实现是在Ril.java中:
在getIccCardStatus中把具体的请求号和上层传下来的Message实例构造成为一个RILRequest类型实例rr,其中上层传下来的Message实例被赋值给rr.mResult,,并最后调用send函数:
下面就让我们来进入mSender中的handleMessage中看看它到底最后做了什么,
上图中mRequestsList就是一个ArrayList类型的链表,里面存储的“元素”是RILRequest,每个RILRequest实例rr以serial进行索引。其中add方法就是向mRequestsList链表中添加成员。其具体定义如下:
ArrayList<RILRequest> mRequestsList = new ArrayList<RILRequest>();
synchronized (mRequestsList) {
mRequestsList.add(rr);
}
到此为止,我们主动下发请求的流程我们也跟了一遍。终于可以歇口气了,发送完请求后轮到ril和ARM9去做具体的动作了,我们要做的就是开始等待这个请求的SOL_RESPONSE了。
前面详细介绍的下发命令时候传下来的那个message也要派上用场了。
至于RILReceiver线程就监听Ril层上报信息,一旦有信息上报,就会调用processResponse (Parcel p),这一部分和ril主动上报信息UNSOL_RESPONSE的流程是一样的,前面我们已经介绍过了,这里就不做介绍。和主动上报不同的是我们根据p中存取的“第一位”信息判断这个上报的消息是UNSOL_RESPONSE后,调用的是processSolicited (Parcel p):
上面最后调用rr.mResult.sendToTarget(),函数后,就会进入到下发请求时候传下来那个Message中的Handler,在其中的handleMessage进行处理,由以上分析我们知道其实rr.mResult就是这个传下来的Message,只不过在其中我们通过调用forMessage把上报的一些信息添加到了这个Message中的obj成员变量中。
下面让我们回到发送请求的IccCard中的mHandler:
在getIccCardStatusDone中handleIccCardStatus((IccCardStatus) ar.result),最终根据电话卡的不同状态信息分发给“想要知道它们的地方”:
通过这个例子我们了解到,如何收到广播,也可以说如何收到下层上报的消息。
- 17 -
Dut.Android.Lee
展开阅读全文