事先提示,这篇文章是以AOSP为基础,基本是以RILJ的角度来看的。本人也是初学者,如果有说的不对的地方,还请指教
1、概念
- 跟底层modem交互需要RIL,RIL分成两个部分:RILJ和RILC
- RILJ负责跟上层(java)交互,他跟phone在同一进程。比如会将上层的请求通过RILJ发送给RILC,这个过程是socket通信。
- RILC在rild进程中,向上负责跟RILJ进行对接(C++),向下对接modem。
- HIDL则是RILJ和RILC之间的通信接口
为了比较好的理解HIDL这个东西,举个例子。比如PC你觉得打游戏不给力了,可能是CPU或是GPU有了瓶颈,这个时候你就换对应的模块就行了。这是因为PC都是有通用的接口,如果哪块你不满意,你单独换其中一块就行,没有必要整个都换。但是手机就不行了,打游戏不给力,不管是CPU不行了还是GPU不行了,你都要换整机,因为没有通用的接口。
2、交互
交互分为两种,一种是上层的主动查询,一种是底层的主动上报。
主动查询分为查询(request)和modem的回应(solicited response):
- 执行查询操作的代码大部分都在RIL.java里面
- 收到sol response的代码都在RadioResponse.java中
底层主动上报(unsolicited msg):
- 对应的代码都在RadioIndication.java中
HIDL:
- 代码在hardware/interfaces/radio下,区分不同版本,每个版本下都有IRadio.hal、IRadioIndication.hal、IRadioResponse.hal、types.hal这几个文件,基本上跟上面也是对应的
- RILC对应的代码可能是在hardware/ril/libril/下,他们的代码都是C++
3、举例
- 主动查询:
private void handleRadioAvailable() {
mCi.getBasebandVersion(obtainMessage(EVENT_GET_BASEBAND_VERSION_DONE));
mCi.getDeviceIdentity(obtainMessage(EVENT_GET_DEVICE_IDENTITY_DONE));
mCi.getRadioCapability(obtainMessage(EVENT_GET_RADIO_CAPABILITY));
mCi.areUiccApplicationsEnabled(obtainMessage(EVENT_GET_UICC_APPS_ENABLEMENT_DONE));
startLceAfterRadioIsAvailable();
}
1、在GsmCdmaPhone.handleRadioAvailable中,第2行,首先会调用obtainMessage创建一个Message对象。在这个地方有两个重点:
- obtainMessage是一个handler的方法,即GsmCdmaPhone就是一个handler,那也会有对应的handleMessage重写,和对应event的处理
- event就是EVENT_GET_BASEBAND_VERSION_DONE
@Override
public void getBasebandVersion(Message result) {
IRadio radioProxy = getRadioProxy(result);
if (radioProxy != null) {
RILRequest rr = obtainRequest(RIL_REQUEST_BASEBAND_VERSION, result,
mRILDefaultWorkSource);
if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
try {
radioProxy.getBasebandVersion(rr.mSerial);
} catch (RemoteException | RuntimeException e) {
handleRadioProxyExceptionForRR(rr, "getBasebandVersion", e);
}
}
}
2、调用getBasebandVersion处理生成的Message
- 在第5行使用obtainRequest将入参传入的Message生成一个RILRequest,且放入一个list中,他在list中的位置就是mSerial
- 这个RILRequest的编号就是RIL_REQUEST_BASEBAND_VERSION
- 在第11行使用HIDL接口通知RILC查询BASEBAND_VERSION,并将之前得到的mSerial传给RILC
public void getBasebandVersionResponse(RadioResponseInfo responseInfo, String version) {
responseString(responseInfo, version);
}
private void responseString(RadioResponseInfo responseInfo, String str) {
RILRequest rr = mRil.processResponse(responseInfo);
if (rr != null) {
if (responseInfo.error == RadioError.NONE) {
sendMessageResponse(rr.mResult, str);
}
mRil.processResponseDone(rr, responseInfo, str);
}
}
3、当modem查到结果后并通过RILC将结果返回给RILJ的时候,调用HIDL接口getBasebandVersionResponse通知
- 在第2行,收到的信息直接都传给了responseString进行处理
- 在第6行,通过之前传递给RILC的mSerial,取出之前创建的RILRequest
- 在第9行,rr.mResult就是最开始创建的那个Message,通过Message找到当初的Handler(GsmCdmaPhone),将消息和得到的response(String),以AsyncResult的形式返回给handler
- handler在收到消息后,使用handleMessage函数进行处理,对应的msg.what就是之前创建Message时候的EVENT_GET_BASEBAND_VERSION_DONE
- modem主动上报:
private void responseDataCallListChanged(int indicationType, List<?> dcList) {
mRil.processIndication(indicationType);
if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_DATA_CALL_LIST_CHANGED, dcList);
ArrayList<DataCallResponse> response = RIL.convertDataCallResultList(dcList);
mRil.mDataCallListChangedRegistrants.notifyRegistrants(
new AsyncResult(null, response, null));
}
1、unsol消息就能更单纯点,即不需要上层触发request,底层直接就调用HIDL接口上报
2、第6行解析出数据response之后,在第7行通过notifyRegistrants通知所有订阅者
3、具体有哪些订阅者,可以看往mDataCallListChangedRegistrants中add成员的地方,即调用registerForDataCallListChanged的地方
4、通知订阅者的方法,是遍历list,取出每个Registrant,这个数据结构也有点类似Message,它在创建的时候就保存了对应的Handler等信息,通过handler把对应的event还有modem返回回来的result发送给handler进行处理 ,就比如这个handler将要处理的事件就是EVENT_RECEIVE_NETWORK_SCAN_RESULT