第一部分, c/c++代碼
Android系統原始碼目錄裡面: hardware/ril 目錄包含了所有有關於telephony的底層代碼.
1.目錄架構(20101215的git版本):
- ril
- |-- CleanSpec.mk
- |-- include
- | `-- telephony
- | |-- ril_cdma_sms.h
- | `-- ril.h
- |-- libril
- | |-- Android.mk
- | |-- MODULE_LICENSE_APACHE2
- | |-- NOTICE
- | |-- ril_commands.h
- | |-- ril.cpp
- | |-- ril_event.cpp
- | |-- ril_event.h
- | `-- ril_unsol_commands.h
- |-- reference-cdma-sms
- | |-- Android.mk
- | |-- reference-cdma-sms.c
- | `-- reference-cdma-sms.h
- |-- reference-ril
- | |-- Android.mk
- | |-- atchannel.c
- | |-- atchannel.h
- | |-- at_tok.c
- | |-- at_tok.h
- | |-- misc.c
- | |-- misc.h
- | |-- MODULE_LICENSE_APACHE2
- | |-- NOTICE
- | `-- reference-ril.c
- `-- rild
- |-- Android.mk
- |-- MODULE_LICENSE_APACHE2
- |-- NOTICE
- |-- radiooptions.c
- `-- rild.c
- 6 directories, 29 files
其中include/telephony目錄下面的ril.h檔案,定義了104個如下的宏:
RIL_Request_XXX
這些宏代表客戶進程向Android telephony發送的命令,包括SIM卡相關的功能,打電話,發簡訊,網路訊號查詢等等。
2.目錄hardware/ril/libril
本目錄下代碼負責與客戶進程進行互動。在接收客戶進程命令後,調用相應函數進行處理,然後將命令響應結果傳回客戶進程。在收到來自網路端的事件後,也傳給客戶進程。
- 檔案ril_commands.h:列出了telephony可以接收的命令;每個命令對應的處理函數;以及命令響應的處理函數。
- 檔案ril_unsol_commands.h:列出了telephony可以接收的事件類型;對每個事件的處理函數;以及WAKEType.
- 檔案ril_event.h/cpp:處理與事件來源(連接埠,modem等)相關的功能。ril_event_loop監視所有註冊的事件來源,當某事件來源有資料到來時,相應事件來源的回呼函數被觸發
- (firePending-> ev->func())
- 檔案ril.cpp:
RIL_register函數:開啟監聽連接埠,接收來自客戶進程的命令請求 (s_fdListen =android_get_control_socket(SOCKET_NAME_RIL);),當與某客戶進程串連建立時,調
用 listenCallback函數;建立一單獨線程監視並處理所有事件來源(通過ril_event_loop)
listenCallback函數:當與客戶進程串連建立時,此函數被調用。此函數接著調用processCommandsCallback處理來自客戶進程的命令請求
processCommandsCallback函數:具體處理來自客戶進程的命令請求。對每一個命令,ril_commands.h中都規定了對應的命令處理函數(dispatchXXX),
processCommandsCallback會調用這個命令處理函數進行處理。
dispatch系列函數:此函數接收來自客戶進程的命令己相應參數,並調用onRequest進行處理。
RIL_onUnsolicitedResponse函數:將來自網路端的事件封裝(通過調用responseXXX)後傳給客戶進程。
RIL_onRequestComplete函數:將命令的最終響應結構封裝(通過調用responseXXX)後傳給客戶進程。
response系列函數:對每一個命令,都規定了一個對應的response函 數來處理命令的最終響應;對每一個網路端的事件,也規定了一個對應的response函數來處理此事
件。response函數可被 onUnsolicitedResponse或者onRequestComplete調用。
3. 目錄hardware/ril/reference-ril分析:
本目錄下代碼主要負責與modem進行互動。
- 檔案reference-ril.c:此檔案核心是兩個函數:onRequest和onUnsolicited
onRequest 函數:在這個函數裡,對每一個 RIL_REQUEST_XXX請求,都轉化成相應的ATcommand,發送給modem,然後睡眠等待。當收到此ATcommand的最終響應
後,線 程被喚醒,將響應傳給客戶進程(RIL_onRequestComplete-> sendResponse)。
onUnsolicited函數:這個函數處理modem從網路端收到的各種事件,如網路訊號變化,撥入的電話,收到簡訊等。然後將時間傳給客戶進程
(RIL_onUnsolicitedResponse -> sendResponse)
- 檔案atchannel.c:負責向modem讀寫資料。其中,寫資料(主要是ATcommand)功能運行在主線程中,讀資料功能運行在一個單獨的讀線程中。
at_send_command_full_nolock函數:運行在主線程裡面。將一個ATcommand命令寫入modem後進入睡眠狀態(使用pthread_cond_wait或類似函數),直到modem讀
線程將其喚醒。喚醒後此函數獲得了ATcommand的最終響應並返回。
readerLoop函數: 運行在一個單獨的讀線程裡面,負責從modem中讀取資料。讀到的資料可分為三種類型:網路端傳入的事件;modem對當前ATcommand的部分響 應;
modem對當前AT command的全部響應。對第三種類型的資料(ATcommand的全部響應),讀線程喚醒(pthread_cond_signal)睡眠狀態的主線 程。
第二部分, Java代碼
Android中,telephony相關的java代碼主要在下列目錄中:
- frameworks/base/telephony/java/android/telephony
- frameworks/base/telephony/java/com/android/internal/telephony
- frameworks/base/services/java/com/android/server
- packages/apps/Phone
其中,目錄telephony/java/android/telephony中的代碼提供Androidtelephony的公開介面,任何具有許可權的第三方應用都可使用,如介面類TelephonyManager。
目錄telephony/java/com/android/internal/telephony和services/java/com/android/server中的代碼提供一系列內部介面,目前第三方應用還不能使用。當前似乎
只有packages/apps/Phone能夠使用
目錄packages/apps/Phone是一個特殊應用,或者理解為一個平台內部進程。其他應用通過intent方式調用這個進程的服務。
TelephonyManager(telephony/java/android/telephony/TelephonyManager.java)主要使用兩個服務來訪問telephony功能:
1. ITelephony, 提供與telephony進行操作,互動的介面,在packages/apps/Phone中由PhoneInterfaceManager.java實現。
2. ITelephonyRegistry,提供登記telephony事件的介面。由frameworks/base/services/java/com/android/server/TelephonyRegistry.java實現。
interface CommandsInterface 描述了對電話的所有操作介面,如命令, 查詢狀態,以及電話事件監聽等。
classBaseCommands是CommandsInterface的直接衍生類別,實現了電話事件的處理(發送message給對應的handler)。
classRIL又派生自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還是GSMPhone時,可使用PhoneProxy。
抽象類別Call代表一個call,有兩個衍生類別CdmaCall和GsmCall。
interface PhoneNotifier定義電話事件的通知方法
DefaultPhoneNotifier從PhoneNotifier派生而來。在其方法實現中,通過調用serviceITelephonyRegistry來發布電話事件。
serviceITelephonyRegistey由frameworks/base/services/java/com/android/server/TelephonyRegistry.java實現。這個類通過廣播intent,從而觸發對應的
broadcastreceiver。
在PhoneApp建立時,
sPhoneNotifier = newDefaultPhoneNotifier(); ... sCommandsInterface = newRIL(context, networkMode, cdmaSubscription);
然後根據當前phone是cdma還是gsm,建立對應的phone,如
sProxyPhone = newPhoneProxy(new GSMPhone(context, sCommandsInterface, sPhoneNotifier));
下面我們來研究一個電話打出去的流程。
TwelveKeyDialer.java, onKeyUp()TwelveKeyDialer.java, placeCall()OutgoingCallBroadcaster.java, onCreate() sendOrderedBroadcast(broadcastIntent, PERMISSION, new OutgoingCallReceiver(), null, Activity.RESULT_OK, number,null);OutgoingCallBroadcaster.java, OutgoingCallReceiver doReceive-> context.startActivity(newIntent);InCallScreen.java, onCreate/onNewIntentInCallScreen.java, placeCallPhoneUtils.java, placeCallGSMPhone.java, dialGsmCallTracker.java, dialRIL.java, dialRIL::getCurrentCalls RILRequestrr = RILRequest.obtain(RIL_REQUEST_GET_CURRENT_CALLS,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.
RILRequest rr = RILRequest.obtain(RIL_REQUEST_DIAL, 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);