Android ril原生代碼(C/C++)和java代碼部分分析

第一部分, c/c++代碼

Android系統源代碼目錄裏面: hardware/ril 目錄包含了所有有關於telephony的底層代碼.

1.目錄架構(20101215的git版本):
  1. ril
  2. |-- CleanSpec.mk
  3. |-- include
  4. |   `-- telephony
  5. |       |-- ril_cdma_sms.h
  6. |       `-- ril.h
  7. |-- libril
  8. |   |-- Android.mk
  9. |   |-- MODULE_LICENSE_APACHE2
  10. |   |-- NOTICE
  11. |   |-- ril_commands.h
  12. |   |-- ril.cpp
  13. |   |-- ril_event.cpp
  14. |   |-- ril_event.h
  15. |   `-- ril_unsol_commands.h
  16. |-- reference-cdma-sms
  17. |   |-- Android.mk
  18. |   |-- reference-cdma-sms.c
  19. |   `-- reference-cdma-sms.h
  20. |-- reference-ril
  21. |   |-- Android.mk
  22. |   |-- atchannel.c
  23. |   |-- atchannel.h
  24. |   |-- at_tok.c
  25. |   |-- at_tok.h
  26. |   |-- misc.c
  27. |   |-- misc.h
  28. |   |-- MODULE_LICENSE_APACHE2
  29. |   |-- NOTICE
  30. |   `-- reference-ril.c
  31. `-- rild
  32.     |-- Android.mk
  33.     |-- MODULE_LICENSE_APACHE2
  34.     |-- NOTICE
  35.     |-- radiooptions.c
  36.     `-- rild.c

  37. 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代碼主要在下列目錄中:
  1. frameworks/base/telephony/java/android/telephony
  2. frameworks/base/telephony/java/com/android/internal/telephony
  3. frameworks/base/services/java/com/android/server
  4. packages/apps/Phone
其中,目錄telephony/java/android/telephony中的代碼提供Androidtelephony的公開接口,任何具有權限的第三方應用都可使用,如接口類TelephonyManager。

目錄telephony/java/com/android/internal/telephonyservices/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/onNewIntent
InCallScreen.java, placeCall
PhoneUtils.java, placeCall
GSMPhone.java, dial
GsmCallTracker.java, dial
RIL.java, dial
RIL::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);


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章