Android telephony整体结构
1.整體介紹
1.1 基礎概念
1、通信整體構成
首先從硬件層面上來說,手機的設計都是手機芯片+信號處理模塊,信號處理模塊可以處理modem(調制解調器)+RF(射頻)+UICC(通用集成電路卡,即電話卡) 。
2、AP和BP
其中Android系統、UI和應用程序運行在手機芯片上,我們稱之為AP端
手機視頻通訊控制運行在信號處理模塊上的芯片上,我們稱之為BP端
這么設計核心優勢主要是不管操作系統怎么變,通信模塊都是相同的。數據都不會出錯,增加穩定性
1.2 相關代碼
1、大部分源碼aosp都有,由于各個廠商定制的不同,在芯片廠商提供給手機廠商的原始代碼和aosp的路徑還是有部分差異和定制。以下代碼路徑以MTK方案舉例。MTK部分型號芯片也在vendor路徑下單獨提供了實現的代碼。但這不影響我們學習通信模塊。這部分表格中我就沒有列出來了。
| Apps | /packages/apps/Dialer | Dialer.apk |
| /packages/apps/Messaging | Messaging.apk | |
| /packages/apps/Contacts | Contacts.apk | |
| Providers | /packages/providers/TelephonyProvider | TelephonyProvider.apk |
| /packages/providers/ContactsProvider | ContactsProvider.apk | |
| Service | /packages/services/Telecomm | Telecomm.apk |
| /packages/services/Telephony | TeleService.apk | |
| /packages/services/Mms | MmsService.apk | |
| vendor/mediatek/proprietary/packages/services/Ims | ImsService.apk | |
| Framework | frameworks/base/telecomm | framework.jar |
| frameworks/base/telephony | framework.jar | |
| frameworks/opt/telephony | framework.jar | |
| frameworks/opt/net/ims | ims-common.jar | |
| vendor/mediatek/proprietary/frameworks/opt/telecomm | mediatek-telephony-common.jar | |
| vendor/mediatek/proprietary/frameworks/opt/telephony | mediatek-telephony-common.jar | |
| vendor/mediatek/proprietary/frameworks/opt/telephonybase | mediatek-telephony-base.jar | |
| HAL | vendor/mediatek/proprietary//hardware/ril/fusion | librilfusion.so、libmtk-ril.so、mtkfusionrild.bin |
| vendor/mediatek/proprietary/hardware/c2kril/fusion | libvia-ril.so | |
| vendor/mediatek/proprietary/hardware/gsm0710muxd | gsm0710muxd.bin | |
| vendor/mediatek/proprietary/external/ccci_mdinit_src | ccci_mdinit.bin | |
| vendor/mediatek/proprietary/external/ccci_fsd | ccci_fsd.bin | |
| Drivers | kernel-4.9/drivers/misc/mediatek/eccci | kernel img |
1.3 軟件結構
1、功能說明
由于BP的設計都是這樣,于是不管你是ios還是安卓或是塞班還是老人機,通信模塊提供給我們的功能就這么五個部分:UICC、ServiceState、DataConnect、Call、SMS
| UICC | SIM卡:存儲號碼、短信、PIN、PUK、駐網鑒權、STK工具包、2G、3G、4G |
| ServiceState | 網絡服務:網絡制式、運營商名字、信號格數、時區、漫游、注冊情況 |
| DataConnect | 上網服務:2G/3G/4G/5G |
| Call | 通話:撥號、接聽、掛斷、保持、恢復、多方通話 |
| SMS | 短信:普通短信、長短信 |
2、簡單的畫了一張Android通信模塊的架構圖,功能設計完全按照Android分層而來
?通信模塊架構圖
軟件架構圖中其他幾個功能點簡單介紹
| 應用內 | Dialer撥號、Contacts聯系人、Mms短信、settings設置、browser瀏覽器 |
| TeleService | Telephony應用框架:數據連接、MMS業務邏輯、Call控制、RILD通信 |
| Telecom | 管理通話、和TeleService交互對應用層提供接口 |
| 通話 | GSMCdmaPhone:2G、3G通話 ImsPhone:4G通話(Volte) |
| RILD | RILD是RILJ和Modem中間層:1、RILJ下發請求->RILD將Request轉換為Modem的AT指令發送2、Modem上報或者返回的消息->RILD處理傳給RILJ |
| Gsm0710muxd | 1、Gsm0710muxd是AT指令通道進行復用的守護進程2、Gsm0710是開源多路復用協議,提高Modem和AP間AT指令的通信效率 |
| CCCI_FSD | 1、Modem不能直接操作文件系統、CCCI_FSD是AP提供給Modem文件守護進程2、通過FSDmodem就可以操作文件系統 |
| CCCI_MDINIT | Modem狀態守護進程:啟動、停止、重啟、飛行模式、reset重置 |
| ECCCI driver | 驅動框架:復用不同modem驅動、減少中斷內存開支、AT指令轉換modem數據、網卡驅動、文件系統、Audio通話數據 |
2.RIL詳細介紹
2.1 phone進程
packages\services\Telephony
phone進程是各個功能詳細模塊framework開始的地方
1、自啟動
在elephony#AndroidManifest.xml中有persistent標記。有此標記AMS會持續保證進程(com.android.phone)存活,意外掛掉也會自動重啟。所以PhoneApp(telephony的Application)就是最初的代碼入口
public class PhoneApp extends Application {public void onCreate() {mPhoneGlobals = new PhoneGlobals(this);mPhoneGlobals.onCreate();mTelephonyGlobals = new TelephonyGlobals(this);mTelephonyGlobals.onCreate();2、PhoneGlobals#onCreate
在PhoneGlobals的構造函數里,開始了Phone對象的創建(makeDefaultPhones).
2.2 RIL
| RILJ | java層,運行在telephony的phone進程,它為上層提供訪問modem的入口和消息接收 |
| RILD | HAL層,系統守護進程。RILJ和Modem中間層:1、RILJ下發請求->RILD將Request轉換為Modem的AT指令發送2、Modem上報或者返回的消息->RILD處理傳給RILJ |
在Android8.0之前,RILJ和modem通信時通過socket連接發送AT指令來進行通信。現在的版本已經改用HIDL通信的方式。HIDL和AIDL很類似。可以簡單的理解為綁定底層的服務來作用到對應的功能上。
2.2.1 RILJ
基本代碼結構
public class RIL extends BaseCommands implements CommandsInterface public abstract class BaseCommands implements CommandsInterface public interface CommandsInterface這里的RIL類就是我們口中的RILJ,采用依賴倒轉原則,定義功能。
<1>、 CommandsInterface接口中定義一些常量表示狀態,再抽象一些方法。
<2>、抽象類實現方法,觀察者模式 register、unregister注冊監聽。留空一些方法具體實現在RIL類中實現
<3>、RIL類則是具體的功能實現。
<4>、在BaseCommands中定義了大量RegistrantList和Registrant對象,這兩個對象是對handler消息的封裝,結合register注冊的監聽,就能把從RILD發送上來的消息傳遞給監聽的對象
<5>、RILJ消息的下發和接收都是通過HIDL拿到radio service,間接通過hidl service來操作和modem之間消息的上傳和下發。
獲得radio hidl service
RIL.java中RIL#getRadioProxy
下發
@Overridepublic void getIccCardStatus(Message result) {IRadio radioProxy = getRadioProxy(result);if (radioProxy != null) {// 封裝要發送的數據RILRequest rr = obtainRequest(RIL_REQUEST_GET_SIM_STATUS, result,mRILDefaultWorkSource);if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));try {// 調用到HIDL 提供的radioserviceradioProxy.getIccCardStatus(rr.mSerial);} catch (RemoteException | RuntimeException e) {handleRadioProxyExceptionForRR(rr, "getIccCardStatus", e);}}}上傳
在獲得hw aodio service的時候,setResponseFunctions(mRadioResponse, mRadioIndication)傳入了兩個對象,他們負責消息的接收和監聽。
這里隨便復制了一個狀態改變的回調:RadioIndication#radioStateChanged
2.2.2 RILD
RILD程序架構圖清晰的表示了RILD的一個初始化過程。歸納為如下四點
1、ril.cpp來統管功能,具體實現在ril_event,reference_ril,atchanel,ril_service里
2、第一個流程:startEventLoop開啟loop循環
3、第二個流程:rilInit初始化,打開AT通道流程
4、第三個流程: 注冊回調函數,ril管理
2.2.2.1、loop循環簡要說明
第一個流程開啟loop循環后,按流程圖走到ril_event#ril_event_loop方法,這里和handler原理中loop循環類似,無限循環查找處理三個鏈表中的event,下面截取最后循環的代碼和鏈表結構體
static struct ril_event * watch_table[MAX_FD_EVENTS]; static struct ril_event timer_list; static struct ril_event pending_list;struct ril_event {struct ril_event *next;struct ril_event *prev;int fd;int index;bool persist;struct timeval timeout;ril_event_cb func;void *param; };void ril_event_loop() {for (;;) {// Check for timeoutsprocessTimeouts();// Check for read-readyprocessReadReadies(&rfds, n);// Fire awayfirePending();} }2.2.2.2、打開AT通道簡要說明
打開AT通道,按代碼流程rilInit走到at_open時,主要執行了readerLoop,在readerLoop中,此時AT通道有消息就會被處理。分別由s_unsolHandler 處理主動上報的消息(比如有短消息),processLine經過上層請求過后的需要回復到上層的消息,比如請求sim卡信息
static void *readerLoop(void *arg __unused) {for (;;) {line1 = strdup(line);line2 = readline();if (s_unsolHandler != NULL) {s_unsolHandler (line1, line2);}} else {processLine(line);} }s_unsolHandler上報到RILJ
// ril.cpp void RIL_onUnsolicitedResponse(int unsolResponse, const void *data,size_t datalen) {ret = s_unsolResponses[unsolResponseIndex].responseFunction((int) soc_id, responseType, 0, RIL_E_SUCCESS, const_cast<void*>(data),datalen);static UnsolResponseInfo s_unsolResponses[] = { #include "ril_unsol_commands.h" };//ril_unsol_commands.h{RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED, radio::radioStateChangedInd, WAKE_PARTIAL},{RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED, radio::callStateChangedInd, WAKE_PARTIAL},{RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED, radio::networkStateChangedInd, WAKE_PARTIAL},...// ril_service.cpp int radio::radioStateChangedInd(int slotId,Return<void> retStatus = radioService[slotId]->mRadioIndication->radioStateChanged(convertIntToRadioIndicationType(indicationType), radioState);radioService[slotId]->checkReturnStatus(retStatus);}return 0; }sp<RadioImpl> radioService[SIM_COUNT];struct RadioImpl : public V1_1::IRadio {int32_t mSlotId;sp<IRadioResponse> mRadioResponse;sp<IRadioIndication> mRadioIndication;<1>處理先也是流程化傳遞,先是ril.cpp的RIL_onUnsolicitedResponse然后通過結構體傳遞到ril_unsol_commands.h里聲明的radio::radioStateChangedInd等方法
<2>radio::radioStateChangedInd等方法的具體實現在ril_service.cpp中
<3>ril_service在實現的時候,上報就交給了ril_service中RadioImpl結構體里的mRadioResponse和mRadioIndication。這兩個對象就是2.2.1、RILJ小結獲得hw radio service的時候傳進來的兩個對象。
<4>總結一下就是rild初始化打開AT通道后,從AT通道中讀到要上報的消息時,交給mRadioResponse和mRadioIndication來上報。RILJ拿到的hw radio service 就是ril_service
<5>RadioImpl 這個將在第三部分講,可以簡單理解它為ril_service的代理。
processLine上報
這種上報也有幾種類型
<1>processLine處理也有5種類型,流程上都類似。以handleFinalResponse普通流程舉例
<2>從handleFinalResponse線程鎖跟蹤到at_send_command_full_nolock,線程解鎖被再次喚醒過后把結果傳給了函數參數*pp_outResponse。
<3>再跟蹤at_send_command_full_nolock方法的調用流程,來自at_send_command 方法。而這個pp_outResponse就是這樣傳過來的。
<4>最后截取了ril_service.cpp中一次包含response的請求代碼片段
<5>所以AT請求下發也是ril_service.cpp中眾多方法間接調用at_send_command傳遞即可。
2.2.2.3、注冊回調函數,ril管理說明
RIL_register (const RIL_RadioFunctions *callbacks) {radio::registerService(&s_callbacks, s_commands); } //ril_service.cpp void radio::registerService(RIL_RadioFunctions *callbacks, CommandInfo *commands) {s_vendorFunctions = callbacks;s_commands = commands;for (int i = 0; i < simCount; i++) {radioService[i] = new RadioImpl; }<1>注冊函數就簡單了,注冊時把callback傳進來還為每一張SIM卡創建了一個RadioImpl對象
<2>radioService這里就對RIL進行收發管理。
2.2.2.4、RILD小結
<1>RILJ層通過HIDL拿到reference-ril.c提供的radio service,通過service來下發和上傳回調
<2>ril.cpp通過三大流程調用,來實現rild的功能。
<3>radio service下發是調用atchannel.c中at_send_command來給modem發送at指令
<4>radio service上傳是通過set的兩個回調接口向RILJ傳遞信息。或者通過at_send_command傳遞的response回傳消息
三、寫在最后
對于Android通信模塊來說,主要學習的是流程跟蹤。從調用棧來講,不管是讀取SIM卡信息or狀態,還是上網、撥號、發短信。都是通過RIL層來轉發AT指令。通過對RIL的了解以達到了解整個通信模塊咋個工作的目的。如果要具體的去修改或者維護telephony模塊,還需要對具體功能的流程進行分析掌握,才能游刃有余。
read the fucking source code!
總結
以上是生活随笔為你收集整理的Android telephony整体结构的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: POJ 3505
- 下一篇: android sina oauth2.