Android源碼中,hardware/ril目錄中包含着Android的telephony底層源碼。這個目錄下包含着三個子目錄,下面是對三個子目錄的具體分析。
一、目錄hardware/ril/include分析:
只有一個頭文件ril.h包含在此目錄下。ril.h中定義了76個如下類型的宏:
RIL_REQUEST_XXX ,
這些宏代表着客戶進程可以向Android telephony發送的命令,包括SIM卡相關的功能,打電話,發短信,網絡信號查詢等。好像沒有操作地址本的功能?
二、目錄hardware/ril/libril分析。本目錄下代碼負責與客戶進程進行交互。在接收客戶進程命令後,調用相應函數進行處理,然後將命令響應結果傳回客戶進程。在收到來自網絡端的事件後,也傳給客戶進程。
- 文件ril_commands.h:列出了telephony可以接收的命令;每個命令對應的處理函數;以及命令響應的處理函數。
- 文件ril_unsol_commands.h:列出了telephony可以接收的事件類型;對每個事件的處理函數;以及WAKE Type???
- 文件ril_event.h/cpp:處理與事件源(端口,modem等)相關的功能。ril_event_loop監視所有註冊的事件源,當某事件源有數據到來時,相應事件源的回調函數被觸發(firePending -> ev->func())
- 文件ril.cpp:
listenCallback函數:當與客戶進程連接建立時,此函數被調用。此函數接着調用processCommandsCallback處理來自客戶進程的命令請求
processCommandsCallback函數:具體處理來自客戶進程的命令請求。對每一個命令,ril_commands.h中都規定了對應的命令處理函數(dispatchXXX),processCommandsCallback會調用這個命令處理函數進行處理。
dispatch系列函數:此函數接收來自客戶進程的命令己相應參數,並調用onRequest進行處理。
RIL_onUnsolicitedResponse函數:將來自網絡端的事件封裝(通過調用responseXXX)後傳給客戶進程。
RIL_onRequestComplete函數:將命令的最終響應結構封裝(通過調用responseXXX)後傳給客戶進程。
response系列函數:對每一個命令,都規定了一個對應的response函數來處理命令的最終響應;對每一個網絡端的事件,也規定了一個對應的response函數來處理此事件。response函數可被onUnsolicitedResponse或者onRequestComplete調用。
三、目錄hardware/ril/reference-ril分析。本目錄下代碼主要負責與modem進行交互。
- 文件reference-ril.c:此文件核心是兩個函數:onRequest和onUnsolicited
onUnsolicited函數:這個函數處理modem從網絡端收到的各種事件,如網絡信號變化,撥入的電話,收到短信等。然後將時間傳給客戶進程(RIL_onUnsolicitedResponse -> sendResponse)
- 文件atchannel.c:負責向modem讀寫數據。其中,寫數據(主要是AT command)功能運行在主線程中,讀數據功能運行在一個單獨的讀線程中。
函數readerLoop運行在一個單獨的讀線程裏面,負責從modem中讀取數據。讀到的數據可分爲三種類型:網絡端傳入的事件;modem對當前AT command的部分響應;modem對當前AT command的全部響應。對第三種類型的數據(AT command的全部響應),讀線程喚醒(pthread_cond_signal)睡眠狀態的主線程。
第二部分 Java代碼
Android中,telephony相關的java代碼主要在下列目錄中:
1. frameworks/base/telephony/java/android/telephony
2. frameworks/base/telephony/java/com/android/internal/telephony
3. frameworks/base/services/java/com/android/server/TelephonyRegistry.java
4. packages/apps/Phone
其中,目錄1中的代碼提供Android telephony的公開接口,任何具有權限的第三方應用都可使用,如接口類TelephonyManager。
目錄2/3中的代碼提供一系列內部接口,目前第三方應用還不能使用。當前似乎只有packages/apps/Phone能夠使用
目錄4是一個特殊應用,或者理解爲一個平臺內部進程。其他應用通過intent方式調用這個進程的服務。
TelephonyManager主要使用兩個服務來訪問telephony功能:
1. ITelephony, 提供與telephony 進行操作,交互的接口,在packages/apps/Phone中由PhoneInterfaceManager.java實現。
2. ITelephonyRegistry, 提供登記telephony事件的接口。由frameworks/base/services/java/com/android/server/TelephonyRegistry.java實現。
interface CommandsInterface 描述了對電話的所有操作接口,如命令, 查詢狀態,以及電話事件監聽等
class BaseCommands是CommandsInterface的直接派生類,實現了電話事件的處理(發送message給對應的handler)。
而class RIL又派生自BaseCommands。RIL負責實際實現CommandsInterface中的接口方法。RIL通過Socket和rild守護進程進行通訊。對於每一個命令接口方法,如acceptCall,或者狀態查詢,將它轉換成對應的RIL_REQUEST_XXX,發送給rild。線程RILReceiver監聽socket,當有數據上報時,讀取該數據並處理。讀取的數據有兩種,
1. 電話事件,RIL_UNSOL_xxx, RIL讀取相應數據後,發送message給對應的handler (詳見函數processUnsolicited)
2. 命令的異步響應。(詳見函數processSolicited)
interface Phone描述了對電話的所有操作接口。 PhoneBase直接從Phone 派生而來。而另外兩個類,CDMAPhone和GSMPhone,又從PhoneBase派生而來,分別代表對CDMA 和GSM的操作。
PhoneProxy也從Phone直接派生而來。噹噹前不需要區分具體是CDMA Phone還是GSM Phone時,可使用PhoneProxy。
抽象類Call代表一個call,有兩個派生類CdmaCall和GsmCall。
interface PhoneNotifier定義電話事件的通知方法
DefaultPhoneNotifier從PhoneNotifier派生而來。在其方法實現中,通過調用service ITelephonyRegistry來發布電話事件。
service ITelephonyRegistey由frameworks/base/services/java/com/android/server/TelephonyRegistry.java實現。這個類通過廣播intent,從而觸發對應的broadcast receiver。
在PhoneApp創建時,
sPhoneNotifier = new DefaultPhoneNotifier();
...
sCommandsInterface = new RIL(context, networkMode, cdmaSubscription);
然後根據當前phone是cdma還是gsm,創建對應的phone,如
sProxyPhone = new PhoneProxy(new GSMPhone(context,
sCommandsInterface, sPhoneNotifier));
下面我們來研究一個電話打出去的流程。
1. TwelveKeyDialer.java, onKeyUp()
2. TwelveKeyDialer.java, placeCall()
3. OutgoingCallBroadcaster.java, onCreate()
sendOrderedBroadcast(broadcastIntent, PERMISSION,
new OutgoingCallReceiver(), null, Activity.RESULT_OK, number, null);
4. OutgoingCallBroadcaster.java, OutgoingCallReceiver
doReceive -> context.startActivity(newIntent);
5. InCallScreen.java, onCreate/onNewIntent
6. InCallScreen.java, placeCall
7. PhoneUtils.java, placeCall
8. GSMPhone.java, dial
9. GsmCallTracker.java, dial
10. RIL.java, dial
RILRequest rr = RILRequest.obtain(RIL_REQUEST_DIAL, result);
...
send(rr);
下面來研究一個incoming call的流程:
1. 創建GsmPhone時,mCT = new GsmCallTracker(this);
2. 創建GsmCallTracker時:
cm.registerForCallStateChanged(this, EVENT_CALL_STATE_CHANGE, null); -->
mCallStateRegistrants.add(r);
3. RIL中的RILReceiver線程首先讀取從rild中傳來的數據:processResponse -> processUnsolicited
4. 對應於incoming call,RIL收到RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED 消息,觸發mCallStateRegistrants中的所有記錄。
5. GsmCallTracker處理EVENT_CALL_STATE_CHANGE,調用pollCallsWhenSafe
6. 函數pllCallsWhenSafe 處理:
lastRelevantPoll = obtainMessage(EVENT_POLL_CALLS_RESULT);
cm.getCurrentCalls(lastRelevantPoll);
7. RIL::getCurrentCalls
RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_CURRENT_CALLS, result);
...
send(rr);
8. 接着RIL調用processSolicited處理RIL_REQUEST_GET_CURRENT_CALLS的返回結果
9. GsmCallTracker的handleMessage被觸發,處理事件EVENT_POLL_CALLS_RESULT,調用函數
handlePollCalls
10. handlPollCalls 調用
phone.notifyNewRingingConnection(newRinging);
11. PhoneApp中創建CallNotifier
12. CallNotifier註冊:
registerForNewRingingConnection -> mNewRingingConnectionRegistrants.addUnique(h, what, obj);