Android Telephony包含了打电话,发短信,电话本,注网等,telephony framework各个module非常依赖于RILD和modem,framework的设置,设置的结果,网络的变化,打电话等都需要framework通过HIDL结果向底层请求,请求的结果通过message传回来。发送请求的时候,将message传入,等RILD返回结果后,再通过message将结果反馈出来,framework解析message的结果。那Message在这个过程中是如何流动的呢?request的response返回后,是如何找到request的message,将结果传入Message的呢?我们拿sendCdmaSms作为例子(会精简一些无关的code)。
在Android P 版本上看一下RIL.java中sendCdmaSms,精简之后的code如下:
@Override
public void sendCdmaSms(byte[] pdu, Message result) { //我们跟踪的message就是参数result
IRadio radioProxy = getRadioProxy(result); // getRadioProxy中没有存储result,传入result的目的是getRadioProxy可能有异常, 直接将message result send回Handler。例如proxy 还没有创建好,还是null
if (radioProxy != null) {
RILRequest rr = obtainRequest(RIL_REQUEST_CDMA_SEND_SMS, result, mRILDefaultWorkSource);//mRILDefaultWorkSource这个参数我们可以忽略掉,现在result被传入了RILRequest rr,rr的成员已经指向了result。
CdmaSmsMessage msg = new CdmaSmsMessage();
constructCdmaSendSmsRilRequest(msg, pdu); // 这部分和Message Result无关,这部分在组装pdu到结构体,通过HIDL接口传给RILD
try {
radioProxy.sendCdmaSms(rr.mSerial, msg); // 这就会通过binder call到了rild,只使用了RILRequest rr的mSerial,从这里可以推测出我们的Message result已经存储到rr,并且rr也以某种方式存储起来。等request的response的回来后,通过某种方式取出对应的rr,之后找到rr中存储的message result。
} catch (RemoteException | RuntimeException e) {
handleRadioProxyExceptionForRR(rr, "sendCdmaSms", e);
}
}
}
我们先看一下RIL.java中obtainRequest的实现
protected RILRequest obtainRequest(int request, Message result, WorkSource workSource) {
RILRequest rr = RILRequest.obtain(request, result, workSource);
addRequest(rr);
return rr;
// obtainRequest做了两件事情,通过RILRequest的obtain方法获取一个RILRequest rr,并将rr加入到某个链表中。
}
private void addRequest() {
acqureWakeLock(rr, FOR_WAKELOCK);
synchronized (mRequestList) {
mRequestList.append(rr.mSerial, rr); //从这里就开看出mRequestList想要找到某个rr,需要使用mSerial来寻找,也就是mSerial是mRequestList的key。我们在这里可以有理由猜测request的response回来的时候,一定会携带merial,因为HIDL接口调用的时候传入的mSerial(radioProxy.sendCdmaSms(rr.mSerial, msg))。之后通过response的mSerial找到mRequestList对应的rr,之后从rr取出message,发送传出去即可。
}
}
我们继续分析RILRequest和obtainRequest。
我们简化一下RILRequest(可以参考RILRequest.java),不影响解释Message的传播
public class RILRequest { //已经简化了
public int mSerial; // 这个值就是HIDL传入的值
public Message mResult; // 这个就是传入的Message result存储的位置。
static AtomicInterger sNextSerial = new AtomicInterger(0); // 用来生成mSerial的值,不断增加
private static RILRequest obtain(int request, Message result) {
RILRequest rr = null;
rr = new RILRequest();
rr.mResult = result; //存储message
rr.mSerial = sNextSerial.getAndIncrement();
return rr;
}
}
现在我们就只剩下对request的response的分析了,主要是验证我们的猜测是否正确。request的response都在RadioResponse.java中
我们看一下RadioResponse.java中sendCdmaSmsResponse(sendCdmaSms的返回结果通过这个函数返回到framework);
// 这个函数没有货,这样做只是统一GSM和CDMA的response到一个函数中
public void sendCdmaSmsResponse(RadioResponseInfo responseInfo, SendSmsResult sms) {
responseSms(responseInfo, sms);
}
继续看responseSms
private void responseSms(RadioResponseInfo responseInfo, SendSmsResult sms) {
RILRequest rr = mRil.processResponse(reesponseInfo); // processResponse通过reesponseInfo的成员serial找到mRequestList中的rr,并且将rr从mRequestList中移除掉. mRil.processResponse的实现请参考RIL.java中processResponse的实现。
// 下面就是取出rr的mResult并且将SendSmsResult sms添加到message里面,之后发送出去。
if (rr != null) {
SmsResponse ret = new SmsResponse(sms.messageRef, sms.ackPDU, sms.errorCode); //重新组装SendSmsResult
if(responseInfo.error == RadioError.NONE) {
sendMessageResponse(rr.mResult, ret); //已经取出rr中的message,也就是rr.mResult,request的response的结果变成了ret
}
mRil.processResponseDone(rr, responseInfo, ret); // 这个是做一些收尾的动作
}
}
最后一步sendMessageResponse
public static void sendMessageResponse(Message msg, object ret) {
if(msg != null) {
AsyncResult.forMessage(msg, ret, null); //封装ret到msg的成员obj
msg.sendTotarget(); // 发送msg到handler进行处理。
}
}
// 关于AsyncResult.forMessage讨论就不讲了,具体可以参考AsyncResult中的code和Message的code。
public class AsyncResult {
public static AsyncResult forMessage(Message m, Object r, Throwable ex) {
AsyncResult ret;
ret = new AsyncResult(m.obj, r, ex);
m.obj = ret;
}
}
framework的request带的message一直在framework中维护着,为了能够response能够取到正确的message,request下发的时候,将key带到rild,response回来的时候还继续将key带回来,这样通过这个key就能找到request对应的message了。