android技術專題之二-telephony

第一部分 c代碼
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:
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調用。

三、目錄hardware/ril/reference-ril分析。本目錄下代碼主要負責與modem進行交互。
  • 文件reference-ril.c:此文件核心是兩個函數:onRequest和onUnsolicited
onRequest 函數:在這個函數裏,對每一個RIL_REQUEST_XXX請求,都轉化成相應的AT command,發送給modem,然後睡眠等待。當收到此AT command的最終響應後,線程被喚醒,將響應傳給客戶進程(RIL_onRequestComplete -> sendResponse)。

onUnsolicited函數:這個函數處理modem從網絡端收到的各種事件,如網絡信號變化,撥入的電話,收到短信等。然後將時間傳給客戶進程(RIL_onUnsolicitedResponse -> sendResponse)

  • 文件atchannel.c:負責向modem讀寫數據。其中,寫數據(主要是AT command)功能運行在主線程中,讀數據功能運行在一個單獨的讀線程中。
函數at_send_command_full_nolock:運行在主線程裏面。將一個AT command命令寫入modem後進入睡眠狀態(使用 pthread_cond_wait或類似函數),直到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);
發佈了13 篇原創文章 · 獲贊 2 · 訪問量 19萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章