Android RIL概述


前言

Android作為一個通用的移動平台,其首要的功能就是通話、短信以及上網等通信功能。那么,從系統的角度來看,Android究竟是怎么實現與網絡的交互的了? 這篇文章里,就來看一看Android中負責通信功能的Telephony中間層,通常也被稱之為RIL(Radio Interface Layer)的具體實現原理與架構。

Android手機要實現與網絡端的通信,需要跨越兩個層:

  • RIL Java(RILJ):負責將上層APP的通信請求發送給HAL層;
  • RIL C++(RILD): 系統守護進程,負責將RILJ的請求命令發送給CP(Communication Processor)

什么是RIL

簡單的說,RIL(Radio Interface Layer),就是將應用程序的通信請求發送給CP的中間層,其包括兩個部分,一個是Java層RILJ,一個是C++層(不妨看作是CP對應的HAL層)RILD。

RILJ屬於系統Phone進程的一部分,隨Phone進程啟動而加載;而RILD守護進程是通過Android的Init進程進行加載的。

RIL結構

下圖是一個Android RIL的一個結構圖。整個通信過程有四個層:

  • 最上層的是應用程序,如通話,短信以及SIM卡管理,它們主要負責將用戶的指令發送到RIL Framework(以后統稱RILJ);
  • RILJ為上層提供了通用的API,如TelephonyManager(包括通話,網絡狀態; SubscriptionManager(卡狀態)以及SmsManager等,同時RILJ還負責維持與RILD的通信,並將上層的請求發送給RILD;
  • RILD是系統的守護進程,對於支持通話功能的移動平台是必不可少的。RILD的功能主要功能是將RILJ發送過來的請求繼續傳遞給CP,同時會及時將CP的狀態變化發送給RILJ;
  • Linux驅動層:kernel驅動層接受到數據后,將指令傳給CP,最后由CP發送給網絡端,等網絡返回結果后,CP將傳回給RILD;

RIL Architecture

RILJ與RILD(RILD與CP的通信)都是通過一個個消息進行數據傳遞。消息主要分兩種:一種是RILJ主動發送的請求(solicited),常見的有RIL_REQUEST_GET_SIM_STATUS(獲取SIM卡狀態), RIL_REQUEST_DIAL(撥打電話),RIL_REQUEST_SEND_SMS(發送短信), RIL_REQUEST_GET_CURRENT_CALLS(獲取當前通話狀態),RIL_REQUEST_VOICE_REGISTRATION_STATE(獲取網絡狀態); 另一種則是從CP主動上報給RIL的消息(unsolicited),如網絡狀態發生變化時,CP會上報RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED,有新短信時,會上報RIL_UNSOL_RESPONSE_NEW_SMS,有來電時會上報RIL_UNSOL_CALL_RING

RIL相關的請求命令與數據結構都定義在/android/hardware/ril/include/telephony/ril.h

在整個過程中,有幾個關鍵問題:

  1. 上層是如何得知RILJ狀態變化的;
  2. RILJ與RILD是怎么進行通信的?
  3. RILJD與CP又是如何進行通信的?

圍繞這三個問題點,我們來看一下具體的細節。

上層如何得知RILJ狀態變化

為方便上層實時監聽網絡狀態、通話狀態以及CP的狀態變化,RIL提供了一個專門的監聽接口IPhoneStateListener.aidl,上層需要監聽上述狀態變化時,只需要實現上述接口,並在Android系統服務TelephonyRegistry中對上述接口實現進行注冊:

public void listen(String pkgForDebug, IPhoneStateListener callback, int events, boolean notifyNow);

 

另外,也可以在TelephonyManager中對RIL狀態進行監聽:

 public void listen(PhoneStateListener listener, int events)

 

源代碼: /android/frameworks/base/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl

oneway interface IPhoneStateListener {
        void onServiceStateChanged(in ServiceState serviceState);
        void onSignalStrengthChanged(int asu);
        void onMessageWaitingIndicatorChanged(boolean mwi);
        void onCallForwardingIndicatorChanged(boolean cfi);

        // we use bundle here instead of CellLocation so it can get the right subclass
        void onCellLocationChanged(in Bundle location);
        void onCallStateChanged(int state, String incomingNumber);
        void onDataConnectionStateChanged(int state, int networkType);
        void onDataActivity(int direction);
        void onSignalStrengthsChanged(in SignalStrength signalStrength);
        void onOtaspChanged(in int otaspMode);
        void onCellInfoChanged(in List<CellInfo> cellInfo);
        void onPreciseCallStateChanged(in PreciseCallState callState);
        void onPreciseDataConnectionStateChanged(in PreciseDataConnectionState dataConnectionState);
        void onDataConnectionRealTimeInfoChanged(in DataConnectionRealTimeInfo dcRtInfo);
        void onVoLteServiceStateChanged(in VoLteServiceState lteState);
        void onOemHookRawEvent(in byte[] rawData);
        void onCarrierNetworkChange(in boolean active);
        void onFdnUpdated();

        void onVoiceRadioBearerHoStateChanged(int state);
    }

 

RILJ與RILD如何通信

RILJ在創建過程中,會啟動兩個線程:RILSender和RILReceiver,RILSender負責將指令發送給RILD,而RILReceiver則負責從讀取從RILD發送過來的數據。RILJ與RILD的通信通道就是在RILReceiver中建立起來的。

我們來看一看RILReciver的代碼:

 1  class RILReceiver implements Runnable {
 2         byte[] buffer;
 3 
 4         RILReceiver() {
 5         ...
 6         @Override
 7         public void
 8         run() {
 9             int retryCount = 0;
10             String rilSocket = "rild";
11 
12             // 嘗試與RILD建立連接
13             try {for (;;) {
14                 LocalSocket s = null;
15                 LocalSocketAddress l;
16 
17                 if (mInstanceId == null || mInstanceId == 0 ) {
18                     rilSocket = SOCKET_NAME_RIL[0];
19                 } else {
20                     rilSocket = SOCKET_NAME_RIL[mInstanceId];
21                 }
22 
23                 try {
24                     s = new LocalSocket();
25                     l = new LocalSocketAddress(rilSocket,
26                             LocalSocketAddress.Namespace.RESERVED);
27                     s.connect(l);
28                 } catch (IOException ex){
29                     ...
30                     // don't print an error message after the the first time
31                     // or after the 8th time
32 
33                     if (retryCount == 8) {
34                         Rlog.e (RILJ_LOG_TAG,
35                             "Couldn't find '" + rilSocket
36                             + "' socket after " + retryCount
37                             + " times, continuing to retry silently");
38                     } else if (retryCount >= 0 && retryCount < 8) {
39                         Rlog.i (RILJ_LOG_TAG,
40                             "Couldn't find '" + rilSocket
41                             + "' socket; retrying after timeout");
42                     }
43                     ...
44 
45                     retryCount++;
46                     continue;
47                 }
48 
49                 retryCount = 0;
50                 mSocket = s;
51 
52                 // 從socket讀取數據
53                 int length = 0;
54                 try {
55                     InputStream is = mSocket.getInputStream();
56 
57                     for (;;) {
58                         Parcel p;
59 
60                         length = readRilMessage(is, buffer);
61 
62                         if (length < 0) {
63                             // End-of-stream reached
64                             break;
65                         }
66 
67                         p = Parcel.obtain();
68                         p.unmarshall(buffer, 0, length);
69                         p.setDataPosition(0);
70 
71                         processResponse(p);
72                         p.recycle();
73                     }
74                 } catch (java.io.IOException ex) {
75                     Rlog.i(RILJ_LOG_TAG, "'" + rilSocket + "' socket closed",
76                           ex);
77                 } catch (Throwable tr) {
78                     Rlog.e(RILJ_LOG_TAG, "Uncaught exception read length=" + length +
79                         "Exception:" + tr.toString());
80                 }
81 
82                 //無法讀取數據,將CP狀態設置為不可用
83                 setRadioState (RadioState.RADIO_UNAVAILABLE);
84                 ...
85                 mSocket = null;
86                 RILRequest.resetSerial();
87 
88                 // Clear request list on close
89                 clearRequestList(RADIO_NOT_AVAILABLE, false);
90             }} catch (Throwable tr) {
91                 Rlog.e(RILJ_LOG_TAG,"Uncaught exception", tr);
92             }
93         }
94     }

 

RILReceiver啟動時,會建立一個UNIX Domain socket(LocalSocket,kernel層對應/dev/socket/rild),與RILD進行通信,然后一直從socket中讀取數據,並將數據傳給上層。連接成功后,RILD會發送一個消息給RILJ,表示連接成功了,這樣RILJ就可以將請求數據發送給RILD,進行通信了。

RILD與CP如何進行通信

RILD與CP(可以看做是兩個運行在不同CPU上的進程通信)交換數據方式一般有兩種情況。如果AP與CP集中在一個芯片上,如高通的平台就是將AP與CP集中在一塊芯片上,這時通常采用共享內存的方式實現跨進程通信;而如果不是在同一塊芯片,而是AP與CP分別采用不同廠商的平台,則一般采用字符設備(character devices) 進行通信。總的說來,共享內存的方式在速度上要優於字符設備。

接下來,主要介紹下RILJ部分的代碼結構。

RILJ代碼結構

RIL Framework (RILJ)的代碼按照功能來划分的話,主要有以下幾個組成部分:

  • 管理網絡狀態(信號強度,網絡注冊狀態等):ServiceStateTracker等;
  • 通話管理(撥號,接聽,呼叫等待等): CallManager,GsmCallTracker
  • SMS短信接收發送: InboundSMSHandler,SmsDispater
  • SIM卡管理: UiccControllerSubscriptionsController
  • 數據鏈接管理: DcTracker,DctController
  • Telephony 大管家: PhoneBase,GsmPhone,PhoneProxy

Android RIL Structure

以上代碼主要位於兩個目錄:

  • /android/frameworks/opt/telephony/ (負責與RILD交互)
  • /android/frameworks/base/telephony/ (對上層提供接口)

下面,以撥打電話的流程作為示例看一看RIL是如何發揮作用的。

示例: CALL流程

下圖是一個MO(Mobile Originated) 通話流程簡圖:

  1. APP向TelecomManager發送撥號請求(關於TelecomManager可以參考另一篇文章Android Telecom系統服務);
  2. TelecomManager將通話請求發送給GsmPhone
  3. GsmPhone繼續將指令傳遞給GsmCallTracker
  4. GsmCallTracker調用RILJ,RILJ將通話請求發送給RILD;
  5. RILD接收到通話指令時,發送給CP;
  6. CP發送給網絡,MT(Mobile Terminal)收到通話后,告知網絡,由網絡將該信息傳遞給MO已將通話信息發送給MT了(就是手機發出嘟嘟聲音的時候):通話狀態由DIALING –> ALERTING;
  7. RILD收到通話狀態變化的消息后,發送一個UNSOL_RESPONSE_CALL_STATE_CHANGED的消息給RILJ;
  8. RILJ通知GsmCallTracker通話狀態變化了;
  9. GsmCallTracker主動查詢CALL狀態:pollCallWhenSafe(),確保得到的信息是對的,沒有發生變化;
  10. RILJ給RILD發送getCurrentCalls()的請求;
  11. RILD獲取到CALL狀態后,上報給RILJ,再由RILJ返回結果給GsmCallTracker
  12. GsmCallTracker得到確定的CALL狀態后,通知GsmPhonenotifyPreciseCallStateChanged();
  13. GsmPhone將CALL狀態變化的消息告知Telecom系統服務;
  14. 最后,Telecom系統服務發送CALL狀態變化的廣播給上層APP

到這一步后,通話並沒有開始,如果MT接聽了電話,則MO會收到CALL狀態變化的信息,然后,才真正開始建立通話鏈接。

MO Call Process

版權聲明:本文為博主原創文章,未經博主允許不得轉載。 https://blog.csdn.net/wang2119/article/details/53232022


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM