本文來自http://blog.csdn.net/yihongyuelan 轉載請務必註明出處
本文代碼以MTK平台Android 4.4為分析對象,與Google原生AOSP有些許差異,請讀者知悉。
前置文章:
《Android 4.4 Kitkat Phone工作流程淺析(一)__概要和學習計劃》
《Android 4.4 Kitkat Phone工作流程淺析(二)__UI結構分析》
《Android 4.4 Kitkat Phone工作流程淺析(三)__MO(去電)流程分析》
通過上一篇文章《Android 4.4 Kitkat Phone工作流程淺析(三)__MO(去電)流程分析》,我們知道在 Android 4.4 中,撥打到電話最終調用到了RIL.java中,並使用send()方法繼續向下傳遞。本文主要目的是簡單介紹RILJ工作流程,為後續MT流程分析打下基礎。
RIL概述
RIL 即 Ridio Interface Layer縮寫,無線通訊介面層,Android 中的實現分為RILJ和RILC兩部分。RILJ屬於Framework層中的Java部分( 後文使用RILJ指代RIL.java ),RILC屬於HAL層中的C/C++部分(也就是rild)。RIL負責將AP層使用者的通話控制資訊傳遞給BP層Modem端,同時Modem端也會將相關處理結果返回給AP層。另外Modem狀態有改變時也會主動上報給RIL層,再逐步向上傳遞並最終通過介面顯示出來。本文僅簡單介紹RILJ部分,詳細分析請參看其他大神的分析。
RILJ與RILC以及Modem之間關係1:
圖1
MO/MT在RILJ中執行流程:1. MO在RILJ中流程:
當使用者執行MO(去電)時,通過層層判斷之後,系統會將相關資訊傳遞到RILJ中,封裝好後使用AT指令的方式發送到Modem端,最終由Modem端發起通話請求。在通話接通後Modem端會返回相關AT指令資訊給RIL層,RIL層再向上反饋。
整個MO(去電)流程可以簡單的歸結為兩個步驟:
(1). ( Request , Response) ,即向RILC發起Request,再由RILC向Modem發送相關AT指令,等待Modem處理並反饋結果,如DIAL操作;
(2). (Response),即在對方接通之後,Modem會將狀態資訊反饋到RILJ中;
2. MT在RILJ中流程:
當Modem端收到來電資訊時,會將相關來電資訊通過AT指令發送給RILC,再通過RILC使用socket發送給RILJ,逐層向上傳遞,最終顯示來電響鈴介面。
MT(來電)與MO(去電)的第二步相同,通過( Response ),即Modem端主動上報狀態改變資訊;
我們先來看一下RILJ 的基本組成以及主要功能,圖2為RILJ核心類圖:
圖2
通過我們可以看到,RILJ繼承自BaseCommands實現了CommandsInterface介面,RILJ包含了三個內部類:RILRequest、RILReceiver、RILSender,分別對應mRequestsList、mSender、mReceiver三個對象。
RILJ中涉及通話控制和訊息處理的關鍵方法:
通話控制類:
dial(),負責建立撥號RILRequest對象;
acceptCall(),負責建立接聽RILRequest對象;
rejectCall(),負責建立拒接RILRequest對象;
以上方法最終會通過RILSender並使用socket方式向RILC發起相關請求。
訊息處理類:
processUnsolicited(),負責處理UnSolicited反饋資訊;
processSolicited(),負責處理Solicited反饋資訊;
這些訊息來自RILC的socket反饋,在上一篇MO(去電)流程分析中,dial最終會調用到RIL.java中的RILSender對象的相關方法,向RILC繼續傳遞撥號資訊,而MT(來電)時Modem會將相關資訊發送到RILC,RILC再將資訊通過socket反饋給RILJ,在RILJ中通過RILReceiver接收並開始處理。RILSender負責通過socket向RILC發送RILRequest資訊,RILReceiver負責以socket方式從RILC接收Response資訊。當RILJ從RILC接收到相關資訊時,會逐步向上反饋,這些資訊分為兩類:
1. Solicited Response
請求返回訊息,這類訊息是上層主動請求Modem再由其返回的訊息,這些訊息由RILC上報給RILJ。比如當我們執行MO(去電)時,會通過RILSender發送dial類型的Request給RILC,RILC再傳遞給Modem端,再由Modem端發起通話請求。待對方接通之後Modem將相關資訊發送到RILC,RILC將結果訊息反饋給RILJ,此時由RILReceiver來接收並處理訊息,這種訊息就是Solicited訊息。
可以簡單的理解為( Request , Response )這樣成對出現,此時RILC向RILJ返回的Respone就是Solicited訊息。
2. UnSolicited Response
主動返回訊息,這類訊息由Modem端主動上報。比如當有MT(來電)時,Modem會接收到資訊並向RILC發送來電訊息,RILC將來電資訊再發送給RILJ,這類沒有request但由Modem主動上報資訊就是UnSolicited資訊。
可以簡單的理解為Modem端主動給RILC,再由RIC上報給RILJ的( Response )訊息,這類訊息就是UnSolicited訊息。
無論是 Solicited 還是UnSolicited Respone 訊息,在RILJ中都是有RILReceiver來負責接收並處理,整個RILJ的工作可以簡單的用圖3來描述:
圖3
RILJ包含了RILSender和RILReceiver,其中RILSender負責發送Request給RILC,RILReceiver負責接收Solicited和UnSolicited的Response資訊。
RILJ工作流程
RILJ的工作內容主要是負責向RILC發起Request,以及從RILC接收Response。主要涉及三個內部類:RILRequest、RILSender、RILReceiver,主要工作包含以下三大內容:
1. RILRequest的構造;
RILRequest是RILJ的內部類,我們可以把RILRequest看成一個打包類,將相關資訊進行加工處理後打包成一個規範的RILRequest並使用RILSender發送給RILC。在RILRequest類中最重要的方法莫過於obtain了,該方法完成了打包工作。我們在MO(去電)流程分析中有看到調用RILJ中的dial方法,並在dial方法中看到了RILRequest的打包代碼,如下:
RILRequest rr = RILRequest.obtain(RIL_REQUEST_DIAL, result, mySimId);
這裡再去看一下obtain方法的實現:
static RILRequest obtain(int request, Message result, int simId) { RILRequest rr = null; synchronized(sPoolSync) { if (sPool != null) { rr = sPool; sPool = rr.mNext; rr.mNext = null; sPoolSize--; } } if (rr == null) { rr = new RILRequest(); } //這裡跟Android原生不同,這裡多了一個參數simId用於MTK雙卡手機標識哪一張SIM卡 //static int[] sNextSerial = {0, 0, 0, 0};這裡後面會從log中看到如"[233]"的編號 //serial是Request的編號並且是唯一的 synchronized(sSerialMonitor) { rr.mSerial = sNextSerial[simId]++; } //請求類型 rr.mRequest = request; rr.mResult = result;//請求結果 Message對象 rr.mParcel = Parcel.obtain(); if (result != null && result.getTarget() == null) { throw new NullPointerException("Message target must not be null"); } // first elements in any RIL Parcel rr.mParcel.writeInt(request); rr.mParcel.writeInt(rr.mSerial); return rr; }
2. RILSender發送Request;
在Request構造完成之後我們在dial方法中看到最終調用了send(rr)方法,這裡就用到了RILSender,RILSender也是RILJ中的內部類,通過查看send方法可以知道:
private void send(RILRequest rr) { Message msg; if (mSocket == null) { rr.onError(RADIO_NOT_AVAILABLE, null); rr.release(); return; } //RILSender整合Handler因此會跳轉到相應的handleMessage方法中 msg = mSender.obtainMessage(EVENT_SEND, rr); acquireWakeLock(); msg.sendToTarget(); }
通過前面的核心類圖我們可以知道,RILSender整合自Handler,因此這裡會跳轉到RILSender的handleMessage方法中,並執行case EVENT_SEND,代碼如下:
case EVENT_SEND: boolean alreadySubtracted = false; try { LocalSocket s; //擷取LocalSocket,並對socket進行判斷是否正常 s = mSocket; //... ...省略部分代碼 //將Request添加到鏈表中 synchronized (mRequestList) { mRequestList.add(rr); } //... ...省略部分代碼 //定義socket發送需要的byte數組 byte[] data; //擷取資料 data = rr.mParcel.marshall(); //... ...省略部分代碼 //向socket寫入資料 s.getOutputStream().write(dataLength); s.getOutputStream().write(data); } //... ...省略部分代碼break;
這裡使用了socket的方式將撥號請求發送給了RILC,最後又RILC向Modem端傳遞。在完成以上步驟之後dial流程就走到了RILC中,再由RILC向Modem端發出dial的AT指令。
3. RILReceiver接收Response;
當MO(去電)接聽以及MT(來電)時,Modem端會將相關資訊通過RILC發送給RILJ,負責接收的正式RILReceiver,RILReceiver也是RILJ的內部類,該類實現了Runnable介面,因此實際啟動是以Thread的方式啟動的。RILReceiver在PhoneProxy的構造方法中通過調用startRilReceiver啟動,這裡是MTK改動過,原生是直接在RIL.java的構造方法中啟動線程。
RILReceiver主要完成兩項工作:
(1). 維護local socket的串連;
(2). 阻塞local socket並處理RILC的Response ( Solicited 和 UnSolicited );
RILReceiver啟動之後會建立local socket並阻塞,代碼如下:
@Override public void run() { //... ...省略部分代碼 try { for (;;) { //... ...省略部分代碼 //建立並維護 Local Socket try { s = new LocalSocket(); l = new LocalSocketAddress(socketRil, LocalSocketAddress.Namespace.RESERVED); s.connect(l); } catch (IOException ex){ //... ...省略部分代碼 //當串連失敗後休眠4s並繼續嘗試串連 } //... ...省略部分代碼 try { InputStream is = mSocket.getInputStream(); for (;;) {//阻塞 Parcel p; length = readRilMessage(is, buffer); if (length < 0) { // End-of-stream reached break; } p = Parcel.obtain(); p.unmarshall(buffer, 0, length); p.setDataPosition(0); //處理Respone訊息(Solicited和UnSolicited) processResponse(p); p.recycle(); } } //... ...省略部分代碼 }
那麼通過以上分析我們可以簡單的將RILJ的工作流程總結為:打包,發送,接收三個步驟。在RILReceiver中接收到RILC的socket資訊之後,使用processResponse進行處理,進而分為processUnsolicited()和processSolicited()方法。
processSolicited()方法主要完成以下三件事:
(1). 根據Response中的request serial編號找到RequestList中的對象並移除;
因為Solicited的Request是一一對應的,當處理完本次Response之後不再需要改Request對象,因此這裡會移除,使用方法findAndRemoveRequestFromList()。
(2). 根據request的類型使用responseXXX方法處擷取從RILC中返回的資訊;
這裡會有很多request類型,對應的responseXXX方法也有很多,比如responseInts()、responseVoid()、responseString()、responseOperator()等等,通過這些方法取出Parcel對象中的內容,該對象中包含了Request需要查詢的資訊。
(3). 將第2步擷取到的資訊儲存到Message中並觸發回調;
執行代碼如下:
if (rr.mResult != null) { AsyncResult.forMessage(rr.mResult, ret, null); rr.mResult.sendToTarget();}我們知道RILRequest類中有定義mResult為Message類型,在obtain方法執行的時候已經對mResult進行了賦值,這裡的Message就是從GSMCallTracker中傳遞過來的,有興趣的童鞋自己追蹤一下吧,注意看清楚dial中的參與即可。也就是說通過分析我們知道processSolicited()處理完成會攜帶相關資訊跳轉到GSMCallTracker中繼續執行。
processUnsolicited()方法主要以下兩件事:
(1). 根據response訊息的類型使用responseXXX方法處擷取從RILC中返回的資訊;
這一步和processSolicited()方法的第2步類似,並將從Parcel對象中擷取到的資料儲存到局部變數Object類型的對象ret中。
(2). 使用notifyRegistrants()方法將相關語音總機到訂閱者( Subscribe );
因為這裡使用的是觀察者模式( Publisher-Subscribe ),相關訂閱者會根據擷取到不同的資訊作出與之對應的反應。
對於MO(去電)而言,整個過程既包含了processSolicited()也包含了processUnsolicited()。為什麼這麼說呢?當我們執行dial操作後,會將相關資訊發送到Modem端,此時執行的步驟是DIAL,Modem端發起DIAL成功後返回給RILJ,這個步驟就是( Request , Respone )。之後如果對方接通了那麼Modem會將相關資訊反饋給RILJ,這個步驟即( Respone ),通過Radio Log可以看到:
(a). 撥號Request和Respone
D/RILJ ( 966): RIL(1) :[0253]> DIAL
D/RILJ ( 966): RIL(1) :[0253]< DIAL
(b). 返回MO接通的Respone
V/RILJ ( 966): RIL(1) :[UNSL RIL]< UNSOL_CALL_PROGRESS_INFO {1, 6, 0, 1, 0, 0, 13800138000, 145, }
至於MO接通後返回資訊裡面的參數這裡不詳細解釋,主要是AT指令中攜帶的資訊,不同硬體平台會有一些自己的定製。對於Request和Respone並不一定是連續出現在Log中的,我們只需要查看其唯一的serial編號即可找到Request對應的Respone。另外,在RILJ的Log中我們可以根據大於(>)符號和小於(<)符號來判斷是Request還是Response,即:
(I). 大於符號(>)對應Request,表示RILJ向RILC發送請求;
(II). 小於符號(<)對應Response,表示RILC向RILJ反饋資訊;
前面我們說過Solicited資訊是成對出現的,通過log也能證明這一點,平時查看Log可以根據request的serial編號來找到對應的response。在完成以上撥號操作之後Solicited資訊就執行完畢了,接下來是等待對方接通,若對方接通則Modem會收到相應的指令並向RILC傳遞接通訊息。該資訊由Modem主動上報,因此屬於UnSolicited資訊,由processUnsolicited()方法來處理。
總結
RILJ的主要作用是將通話控制資訊使用socket傳遞給RILC,RILC再使用AT指令傳遞給Modem端;RILC通過socket返回的Modem處理結果給RILJ並通知上層應用;可以說RILJ在Android Telephony結構中有著承上啟下的作用。
RILJ的主要工作內容可以概括為以下三點:
1. 構造打包RILRequest;
2. RILSender通過socket向RILC發起request;
3. RILReceiver通過socket結構RILC反饋response;
RILReceiver接收到的訊息分為兩類:
1. Solicited Response,與之對應的處理方法是processSolicited();
2. UnSolicited Response,與之對應的處理方法是processUnsolicited();