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了。