主頁 > 移動端開發 > Android RIL&IMS原始碼分析

Android RIL&IMS原始碼分析

2023-06-16 08:29:53 移動端開發

一、需求

1、了解IMS相關知識體系
2、RILD 與 RILJ、IMS回呼訊息的機制

二、相關概念

2.1 IMS

        IMS全稱是IP Multimedia Subsystem,中文意義為IP多媒體子系統,IMS是一種基于IP基礎結構,能夠融合資料、話音和移動等網路技術的系統,
         IP = 基于IP 的傳輸,基于IP的會話控制,基于IP的業務實作
        Multimedia = 語音、視頻、圖片、文本等多種媒體組合,在多種接入基礎之上具有不同能力的終端組合
        Subsvstem = 依賴于現有網路技術和網路設備發展的網路,最大程度重用現有網路系統
(我個人理解IMS是一個很大的概念,它不單單特指:IMS服務、IMS PDN等,它類似GSM,WCDMA,LTE一樣,是一種體系結構,包含了好多內容)

2.2 Volte

        VoLTE是Voice over LTE的縮寫,是基于 IMS 的語音業務,VoLTE基于IP多媒體子系統(IMS)網路,在LTE上使用為控制層面和語音服務的媒體層面特制的組態檔,使語音服務作為資料流在LTE資料承載網路中進行傳輸,而不再需要維護和依賴傳統的電路交換語音網路,通俗的來講,就是語音通話建立在4G流量之上,無需再依托于2G/3G網,全部承載于4G網路中,最終實作資料與語音業務在同一網路下的統一,使4G網路不再僅僅提供流量資料業務支撐,還提供語音及視頻通話支持,讓4G網路利用最大化,
        移動用戶肯定都遇到過這個問題,在玩網路游戲時一則電話打進來,游戲就斷網了,這并非手機硬體問題,而是移動4G手機是通過2G信號進行語音通訊,所以通話程序中系統會自動將網路從4G切換到2G,

2.3 CS域與PS域

        我們了解到的資料傳輸有兩個域,分別是CS域和PS域,我們常說的CS域就是電路交換域,通常用于語音通話,在2G和3G中都有應用到;我們常說的PS域就是分組交換域,通常用于資料業務,在3G、4G和5G中都有應用到,而還有一個IMS(IP多媒體子系統),相當于是PS域上的一個子系統,IMS的存在可以讓用戶在PS域上同時使用語音通話和資料業務

2.3.1 CS域

        CS(Circuit Switched)域,即電路交換域,首先需要建立一條傳輸資料的連接,建立完成之后開始資料的傳輸,此連接不會斷開,直到資料傳輸完畢,才可以釋放掉連接,所以一條鏈路只電路交換的特點是獨占一條鏈路,一直用于資料傳輸,可靠性很高,但不高效,這就相當于是小時候玩的聽筒游戲,兩個紙杯子之間連著一條線,兩個人通話程序中,這條鏈路是不能斷開的,直到通話結束,

2.3.2 PS域

        PS域(Packet Switch)表面意思就是分組交換,PS 域不能直接進行語音業務,PS業務就是常見的資料業務,也包括流媒體業務、VOIP等等,具有高效的傳輸效率,但可靠性沒有CS域那么高,

2.4 VOIP

        VOIP是一個很寬泛的概念,VOIP(Voice over IP)的縮寫,只要是通過IP傳輸的語音電話,都可以稱為VOIP,如互聯網提供商提供(Skype、微信、teams等)、運營商提供的IMS(LTE時代公認的語音解決方案(VoLTE),因為VoLTE是運營商在LTE層上附著IMS-PDN進行傳輸的,相對于純IP網路的skype、微信網路電話,通話質量會好很多,

2.5 URC訊息

        URC 是Unsolicited Result Code,即"非請求結果碼", 一般的 AT命令 流程都是控制端發出 命令 ,被控端回應結果碼, 但當被控端有事件需要通知控制端時,就會主動發出 URC ,例如有呼叫打入、收到新短資訊、自動關機等,

2.6 HIDL

        HIDL的全稱是HAL interface definition language(硬體抽象層介面定義語言) ,是AndroidFramework 與Android HAL之間的介面,HIDL 旨在用于行程間通信(IPC),Android O(8.0) 之前系統的升級牽扯多方協作,極為麻煩,HIDL機制的推出就是將 framework 與 hal 層分開,使得框架部分可以直接被覆寫、更新,而不需要重新對 HAL 進行編譯,這樣在系統升級時,OEM 廠商 跳過 SoC廠商,先對 framework 進行升級,

三、環境

  1. 芯片:高通Qcm2290
  2. 版本:Android 11

四、設計思路

4.1 RIL結構圖

4.2 RIL相關模塊介紹

模塊 行程 介紹
Dialer com.android.dialer 負責撥號、呼叫界面顯示
TeleService com.android.phone 負責通話邏輯,如實際向RIL撥號、掛電話,及電話狀態如撥號、振鈴、接通等的變更,
TelecomService system_server 負責邏輯控制,是溝通各個行程互動的橋梁,
telephony-common(RILJ) jar,看哪個行程參考,主要是com.android.phone 主要是phone模塊,hal層對應的java層客戶端的代碼,這個模塊的代碼就是跟hal下面的C/C++服務進行通信的
RILD RILD 主要負責接發RILJ指令、Modem指令
MODEM Modem Modem是調制解調器的縮寫,它是一種用于數字信號和模擬信號之間轉換的設備,在手機中,Modem是一個硬體模塊,它負責處理與無線網路通信相關的任務,包括資料傳輸、語音通信和短信等,

4.2.1 Dialer模塊

原始碼: LINUX\android\packages\apps\Dialer

4.2.2 TeleService模塊

原始碼: LINUX\android\packages\services\Telephony

4.2.2.1 TeleService啟動

(1)設定persistent標記,此標記AMS會持續保證行程(com.android.phone)存活,意外掛掉也會自動重啟,
LINUX\android\packages\services\Telephony/AndroidManifest.xml

    <application android:name="PhoneApp"
            android:persistent="true"
            ...
            android:directBootAware="true">

(2)SystemServer啟動后,ActivityManqgerService服務初始化完成后,啟動persistent行程,即Phone模塊被啟動,
LINUX\android\frameworks\base\services\core\java\com\android\server\am\ActivityManagerService.java

 void startPersistentApps(int matchFlags) {
        ...
        synchronized (this) {
            try {
                final List<ApplicationInfo> apps = AppGlobals.getPackageManager()
                        .getPersistentApplications(STOCK_PM_FLAGS | matchFlags).getList();
                for (ApplicationInfo app : apps) {
                    if (!"android".equals(app.packageName)) {
                        addAppLocked(app, null, false, null /* ABI override */,
                                ZYGOTE_POLICY_FLAG_BATCH_LAUNCH);
                    }
                }
            } catch (RemoteException ex) {
            }
        }
    }

4.2.3 TelecomService模塊

原始碼: LINUX\android\packages\services\Telecomm

4.2.3.1 TelecomService啟動

Android設備剛開機,SystemServer行程初始化完成啟動完系統的核心服務如AMS、PMS后,就會加載系統其它服務,這其中就包含了一個與Telecom服務啟動相關的系統服務專門用于加載Telecom:
LINUX\android\frameworks\base\services\java\com\android\server\SystemServer.java

private void run() {
    ...
    startBootstrapServices(t);
    startCoreServices(t);
    startOtherServices(t);
    ...
}

private void startOtherServices(@NonNull TimingsTraceAndSlog t)
    ...
        //啟動Telecom服務的加載類
        t.traceBegin("StartTelecomLoaderService");
        mSystemServiceManager.startService(TelecomLoaderService.class);=
        t.traceEnd();

        //啟動telephony注冊服務,用于注冊監聽telephony狀態的介面
        t.traceBegin("StartTelephonyRegistry");
        telephonyRegistry = new TelephonyRegistry(context, new TelephonyRegistry.ConfigurationProvider());
        ServiceManager.addService("telephony.registry", telephonyRegistry);
        t.traceEnd();
        ...
        //AMS初始化完成,啟動Telecom服務
        mActivityManagerService.systemReady(() -> {
            ...
            mSystemServiceManager.startBootPhase(t, SystemService.PHASE_ACTIVITY_MANAGER_READY);
            ...
        }, t);
    ...
}

在TelecomLoaderService類實作Telecom服務的bind作業,完成Telecom的啟動
LINUX\android\frameworks\base\services\core\java\com\android\server\telecom\TelecomLoaderService.java

    private static final ComponentName SERVICE_COMPONENT = new ComponentName(
            "com.android.server.telecom",
            "com.android.server.telecom.components.TelecomService");

    private static final String SERVICE_ACTION = "com.android.ITelecomService";

    @Override
    public void onBootPhase(int phase) {
        if (phase == PHASE_ACTIVITY_MANAGER_READY) {
            ...
            connectToTelecom();
        }
    }

    //連接Telecom服務
    private void connectToTelecom() {
        synchronized (mLock) {
            ...
            TelecomServiceConnection serviceConnection = new TelecomServiceConnection();
            Intent intent = new Intent(SERVICE_ACTION);
            intent.setComponent(SERVICE_COMPONENT);
            int flags = Context.BIND_IMPORTANT | Context.BIND_FOREGROUND_SERVICE
                    | Context.BIND_AUTO_CREATE;

            // Bind to Telecom and register the service
            if (mContext.bindServiceAsUser(intent, serviceConnection, flags, UserHandle.SYSTEM)) {
                mServiceConnection = serviceConnection;
            }
        }
    }

     private class TelecomServiceConnection implements ServiceConnection {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            try {
                ITelecomLoader telecomLoader = ITelecomLoader.Stub.asInterface(service);//回傳TelecomService代理物件
                ITelecomService telecomService = telecomLoader.createTelecomService(mServiceRepo);//回傳TelecomService實作類

                SmsApplication.getDefaultMmsApplication(mContext, false);
                ServiceManager.addService(Context.TELECOM_SERVICE, telecomService.asBinder());//將TelecomService實作類注冊到serviceManager,以便后續方便參考
            ...
            }
        ...
    }

4.2.3.2 TeleComService訊息處理模型

Telecom是Android的一個系統服務,其主要作用是管理Android系統當前的通話,如來電顯示,接聽電話,掛斷電話等功能,在Telephony模塊與上層UI之間起到了一個橋梁的作用,比如,Telephony有接收到新的來電時,首先會告知Telecom,然后由Telecom服務通知上層應用來電資訊,并顯示來電界面,

4.2.4 telephony-common模塊

原始碼: LINUX\android\frameworks\opt\telephony
telephony-common模塊最終編譯會生成一個java library,主要是phone模塊在參考,hal層對應的java層客戶端的代碼RILJ,這個模塊的代碼就是跟hal下面的C/C++服務進行通信的,
LINUX\android\frameworks\opt\telephony\Android.bp

java_library {
    name: "telephony-common",
    installable: true,
    ...
}

4.2.5 Telecom_Framewrok模塊

原始碼:LINUX\android\frameworks\base\telecomm
android提供的phone的一些sdk的代碼,最終編譯完成打包進framework.jar
LINUX\android\frameworks\base\Android.bp

filegroup {
    name: "framework-telecomm-sources",
    srcs: [
        "telecomm/java/**/*.java",
        "telecomm/java/**/*.aidl",
    ],
    path: "telecomm/java",
}

framework-telecomm-sources => framework-non-updatable-sources => framework-non-updatable-sources => framework-minus-apex => framework

4.2.6 Telephony_Framewrok模塊

原始碼: LINUX\android\frameworks\base\telephony
android提供的phone的一些sdk的代碼,最終編譯完成打包進framework.jar
LINUX\android\frameworks\base\Android.bp

filegroup {
    name: "framework-telephony-sources",
    srcs: [
        "telephony/java/**/*.java",
        "telephony/java/**/*.aidl",
    ],
    path: "telephony/java",
}

framework-telephony-sources => framework-non-updatable-sources => framework-non-updatable-sources => framework-minus-apex => framework

4.2.7 RIL模塊

原始碼: LINUX\android\hardware\ril
RIL模塊由rild守護行程、libril.so、librefrence.so三部分組成:

4.2.7.1 RILD守護行程

原始碼: LINUX\android\hardware\ril\rild
RILD主要起到承上啟下的作用,作為modem和RILJ的通信的中轉站,RILD可分為兩部分,一是負責與RILJ通訊的部分,主要通過HIDL通信;另一個是負責與modem互動,主要通過AT指令,

4.2.7.1.1 RILD啟動

(1)開機時,通過RC檔案啟動RILD行程

@LINUX\android\hardware\ril\rild\rild.rc
service vendor.ril-daemon /vendor/bin/hw/rild
    class main
    user radio
    disabled
    group radio cache inet misc audio log readproc wakelock
    capabilities BLOCK_SUSPEND NET_ADMIN NET_RAW

(2)RILD啟動后,會執行main啊方法,初始化RILD相關操作

@LINUX\android\hardware\ril\rild\rild.c
int main(int argc, char **argv) {
    ...
    rilInit =
        (const RIL_RadioFunctions *(*)(const struct RIL_Env *, int, char **))
        dlsym(dlHandle, "RIL_Init");
    ...
    //初始化reference,輪詢modem指令
    funcs = rilInit(&s_rilEnv, argc, rilArgv);
    RLOGD("RIL_Init rilInit completed");

    //在rild注冊reference的回呼函式
    RIL_register(funcs);
    ...
}

4.2.7.2 libril共享庫

原始碼: LINUX\android\hardware\ril\libril
libril.so是共享庫,主要負責同上層的通信作業,接收ril的請求,并傳遞給librefrence_ril.so,同時將librefrence_ril.so回傳的訊息送給呼叫行程

4.2.7.3 librefrence共享庫

原始碼: LINUX\android\hardware\ril\reference-ril
librefrence_ril.so是共享庫,是由各手機廠商自己實作,在rild行程運行中通過dlopen方式加載,主要負責跟modem硬體通信,轉換來自libril的請求為AT命令,同時監聽Modem的反饋資訊給libril

4.3 RIL相關模塊通訊

4.3.1 通訊架構圖

五、詳細設計

5.1 Dialer撥號

5.1.1 Dialer應用撥號時序圖

5.1.2 Dialer撥號界面顯示

Dialer應用為撥號提供了界面顯示,同時也是撥號請求的觸發點

@LINUX\android\packages\apps\Dialer\java\com\android\dialer\dialpadview\DialpadFragment.java
  public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) {
    ...
    View fragmentView = inflater.inflate(R.layout.dialpad_fragment, container, false);//撥號界面布局加載
    ...
    return fragmentView;
  }

    @Override
  public void onClick(View view) {
    int resId = view.getId();
    if (resId == R.id.dialpad_floating_action_button) {
      view.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
      handleDialButtonPressed();//撥號按鈕點擊事件
    } 
    ...
  }

5.1.3 Dialer權限檢查

Dialer應用會進行權限檢查,判斷當前是否為默認撥號盤,且當前應用是否宣告CALL_PHONE權限,

  public static boolean placeCall(Context context, Intent intent) {
    if (hasCallPhonePermission(context)) {//權限檢查
      getTelecomManager(context).placeCall(intent.getData(), intent.getExtras());
      return true;
    }
    return false;
  }

  @Deprecated
  public static boolean hasCallPhonePermission(Context context) {
    return isDefaultDialer(context) || hasPermission(context, Manifest.permission.CALL_PHONE);//判斷當前是否為默認撥號盤,且當前應用是否宣告CALL_PHONE權限
  }

5.1.4 與TelecomService通信

Dialer應用通過TelecomManager物件,將撥號請求訊息,通過binder的方式,通知TelecomService行程,

@LINUX\android\frameworks\base\telecomm\java\android\telecom\TelecomManager.java
    @RequiresPermission(anyOf = {android.Manifest.permission.CALL_PHONE,
            android.Manifest.permission.MANAGE_OWN_CALLS})
    public void placeCall(Uri address, Bundle extras) {
        ITelecomService service = getTelecomService();//獲取服務端代理物件
        if (service != null) {
            if (address == null) {
                Log.w(TAG, "Cannot place call to empty address.");
            }
            try {
                service.placeCall(address, extras == null ? new Bundle() : extras,
                        mContext.getOpPackageName(), mContext.getAttributionTag());//通過binder實作跨行程通信,將撥號請求發給TelecomService行程
            } catch (RemoteException e) {
                Log.e(TAG, "Error calling ITelecomService#placeCall", e);
            }
        }
    }

5.2 TelecomService處理撥號流程

5.2.1 TelecomService處理撥號時序圖

5.2.2 往InCallService發送請求

(1)startOutgoingCall開始呼叫請求
Dialer行程的撥號請求傳遞到TelecomService行程后,通過startOutgoingCall方法開始請求打開呼叫界面

@LINUX\android\packages\services\Telecomm\src\com\android\server\telecom\CallIntentProcessor.java
static void processOutgoingCallIntent(
            Context context,
            CallsManager callsManager,
            Intent intent,
            String callingPackage,
            DefaultDialerCache defaultDialerCache) {
        ...
        // Send to CallsManager to ensure the InCallUI gets kicked off before the broadcast returns
        CompletableFuture<Call> callFuture = callsManager
                .startOutgoingCall(handle, phoneAccountHandle, clientExtras, initiatingUser,
                        intent, callingPackage);//開始呼叫請求

        final Session logSubsession = Log.createSubsession();
        callFuture.thenAccept((call) -> {
            if (call != null) {
                Log.continueSession(logSubsession, "CIP.sNOCI");
                try {
                    broadcaster.processCall(call, disposition);//發送廣播,切換成異步請求
                } finally {
                    Log.endSession();
                }
            }
        });
    }

(2)系結InCallService
InCallServiceImpl是InCallService的子類,在Dialer行程,而TelecomService行程與InCallServiceImpl也是通過bind實作跨行程通信,

@LINUX\android\packages\services\Telecomm\src\com\android\server\telecom\InCallController.java
public static final String SERVICE_INTERFACE = "android.telecom.InCallService";
public int connect(Call call) {
            ...
            Intent intent = new Intent(InCallService.SERVICE_INTERFACE);
            intent.setComponent(mInCallServiceInfo.getComponentName());
            ...
            //系結InCallService型別服務,最終系結InCallServiceImpl
            if (!mContext.bindServiceAsUser(intent, mServiceConnection,
                        Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE |
                        Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS |
                        Context.BIND_ABOVE_CLIENT,
                        UserHandle.CURRENT)) {
                Log.w(this, "Failed to connect.");
                mIsConnected = false;
            }
            ...
        }

(3)啟動InCallActivity呼叫界面
當InCallServiceImpl被TelecomService行程系結后,會呼叫onBind函式,接著啟動InCallActivity呼叫界面

@LINUX\android\packages\apps\Dialer\java\com\android\incallui\InCallServiceImpl.java
  public IBinder onBind(Intent intent) {
    ...
    InCallPresenter.getInstance().onServiceBind();
    InCallPresenter.getInstance().maybeStartRevealAnimation(intent);//開啟顯示影片
    TelecomAdapter.getInstance().setInCallService(this);
    ...
    return iBinder;
  }

@LINUX\android\packages\apps\Dialer\java\com\android\incallui\InCallPresenter.java
   public void maybeStartRevealAnimation(Intent intent) {
    ...
    //啟動InCallActivity呼叫界面
    final Intent activityIntent =
        InCallActivity.getIntent(context, false, true, false /* forFullScreen */);
    activityIntent.putExtra(TouchPointManager.TOUCH_POINT, touchPoint);
    context.startActivity(activityIntent);
  }

5.2.3 廣播下發訊息

TelecomService行程發出一個定向廣播,由TelecomService行程中的NewOutgoingCallBroadcastIntentReceiver物件接收,
(1)TelecomService行程發送廣播

@LINUX\android\packages\services\Telecomm\src\com\android\server\telecom\NewOutgoingCallIntentBroadcaster.java
    private void broadcastIntent(
            Intent originalCallIntent,
            String number,
            boolean receiverRequired,
            UserHandle targetUser) {
        Intent broadcastIntent = new Intent(Intent.ACTION_NEW_OUTGOING_CALL);
        ...
        //發送廣播
        mContext.sendOrderedBroadcastAsUser(
                broadcastIntent,
                targetUser,
                android.Manifest.permission.PROCESS_OUTGOING_CALLS,
                AppOpsManager.OP_PROCESS_OUTGOING_CALLS,
                options.toBundle(),
                receiverRequired ? new NewOutgoingCallBroadcastIntentReceiver() : null,
                null,  // scheduler
                Activity.RESULT_OK,  // initialCode
                number,  // initialData: initial value for the result data (number to be modified)
                null);  // initialExtras
    }

(2)TelecomService行程接收廣播

@LINUX\android\packages\services\Telecomm\src\com\android\server\telecom\NewOutgoingCallIntentBroadcaster.java
public class NewOutgoingCallBroadcastIntentReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            ...
                    placeOutgoingCallImmediately(mCall, resultHandleUri, gatewayInfo,
                            mIntent.getBooleanExtra(
                                    TelecomManager.EXTRA_START_CALL_WITH_SPEAKERPHONE, false),
                            mIntent.getIntExtra(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE,
                                    VideoProfile.STATE_AUDIO_ONLY));//繼續下發呼叫請求
            ...
        }
    }

同一個應用中為什么要使用廣播來傳遞訊息呢?因為Dialer行程發起撥號請求后,會將訊息發給TelecomService行程,通過該行程的placeCall方法層層呼叫,此時方法是同步呼叫,直到呼叫了broadcastIntent,通過廣播方式將同步方法轉換成異步處理,即當前的呼叫請求下發給TelecomService行程處理,同Dialer行程的呼叫請求結束,

5.2.4 往TeleService下發請求

(1)placeOutgoingCall 下發呼叫請求
接收廣播后,通過placeOutgoingCall方法繼續下發撥號請求

    private void placeOutgoingCallImmediately(Call call, Uri handle, GatewayInfo gatewayInfo,
            boolean speakerphoneOn, int videoState) {
        ...
        mCall.setNewOutgoingCallIntentBroadcastIsDone();
        mCallsManager.placeOutgoingCall(call, handle, gatewayInfo, speakerphoneOn, videoState);
    }

(2)系結TeleService
binder系結TeleService服務,實作跨行程通信,同時將將撥號請求分發給TeleService行程,由TeleService行程繼續處理

@LINUX\android\packages\services\Telecomm\src\com\android\server\telecom\ConnectionServiceWrapper.java
public void createConnection(final Call call, final CreateConnectionResponse response) {
        BindCallback callback = new BindCallback() {
            @Override
            public void onSuccess() {
                ...
                    mServiceInterface.createConnection(...);//與TeleService系結成功后,發起創建通話連接請求
                ...
            }

            @Override
            public void onFailure() {
                ...
            }
        };
        mBinder.bind(callback, call);//系結TeleService
    }
}

@LINUX\android\packages\services\Telecomm\src\com\android\server\telecom\ServiceBinder.java
public static final String SERVICE_INTERFACE = "android.telecom.ConnectionService";
void bind(BindCallback callback, Call call) {
            ...
            if (mServiceConnection == null) {
                Intent serviceIntent = new Intent(mServiceAction).setComponent(mComponentName);//該物件為SERVICE_INTERFACE
                ...
                if (mUserHandle != null) {
                    isBound = mContext.bindServiceAsUser(serviceIntent, connection, bindingFlags,
                            mUserHandle);//系結TeleService
                }
                ... 
            } 
        }

5.3 TeleService下發撥號請求

5.3.1 TeleService下發撥號請求時序圖

5.3.2 TeleService類圖

5.3.3 TelephonyConnectionService啟動

@LINUX\android\packages\services\Telephony\AndroidManifest.xml
        <service
                android:singleUser="true"
                android:name="com.android.services.telephony.TelephonyConnectionService"
                android:label="@string/pstn_connection_service_label"
                android:permission="android.permission.BIND_TELECOM_CONNECTION_SERVICE" >
            <intent-filter>
                <action android:name="android.telecom.ConnectionService" />
            </intent-filter>
        </service>

5.3.4 TeleService撥號請求下發(GsmCdmaPhone)

在teleService會獲取當前呼叫的phone物件,如GsmCdmaPhone、ImsPhone、SipPhone,來決定要從用哪一種通訊方式進行呼叫,

@LINUX\android\packages\services\Telephony\src\com\android\services\telephony\TelephonyConnectionService.java
    public Connection onCreateOutgoingConnection(
            PhoneAccountHandle connectionManagerPhoneAccount,
            final ConnectionRequest request) {
        ...
        if (PhoneAccount.SCHEME_VOICEMAIL.equals(scheme)) {
            // TODO: We don't check for SecurityException here (requires
            // CALL_PRIVILEGED permission).
            final Phone phone = getPhoneForAccount(request.getAccountHandle(),
                    false /* isEmergencyCall */, null /* not an emergency call */);//獲取Phone物件,決定采用的通訊方式
            ...
        } 
        ...
        if (!isEmergencyNumber) {
            ...
                return placeOutgoingConnection(request, resultConnection, phone);//往RILD繼續下發訊息
        } 
         ...
    }

5.3.5 TeleService撥號請求下發(ImsPhone)

Android 9 引入了一個名為 ImsService 的新 SystemApi 介面,可以幫助實作IP多媒體子系統,ImsService API 是在 Android 平臺與供應商或運營商提供的 IMS 實作之間明確定義的介面,即IMS的具體實作是由供應商或運營商實作, android提供了相關的系統SystemApi介面,

5.3.5.1 時序圖

5.3.5.2 IMS與CDMA、GSM時序切換

與普通的CS通話一致,由Dialer撥號應用,到Telecom,TeleService,區別在于,在GsmCdmaPhone#diale()中,判斷是否支持ims通話,

    public Connection dial(String dialString, @NonNull DialArgs dialArgs)
            throws CallStateException {
        ...
        boolean useImsForCall = useImsForCall(dialArgs)
                && !shallDialOnCircuitSwitch(dialArgs.intentExtras)
                && (isWpsCall ? allowWpsOverIms : true);//是否使用IMS通訊方式
        ...
        if ((useImsForCall && (!isMmiCode || isPotentialUssdCode))
                || (isMmiCode && useImsForUt)
                || useImsForEmergency) {
            try {
                if (DBG) logd("Trying IMS PS call");
                return imsPhone.dial(dialString, dialArgs);//使用IMS通話
            } ...
        }
        ...
        if (isPhoneTypeGsm()) {
            return dialInternal(dialString, new DialArgs.Builder<>()
                    .setIntentExtras(dialArgs.intentExtras)
                    .build());//使用GSM通話
        } else {
            return dialInternal(dialString, dialArgs);//其他通話方式
        }
    }

5.4 RILD處理撥號請求

5.4.1 RILD撥號請求訊息下發時序圖

5.4.2 RILJ往RILD發送指令

RILJ往RILD發送指令,請求撥號的訊息下發如下:

@LINUX\android\frameworks\opt\telephony\src\java\com\android\internal\telephony\RIL.java
    @Override
    public void dial(String address, boolean isEmergencyCall, EmergencyNumber emergencyNumberInfo,
                     boolean hasKnownUserIntentEmergency, int clirMode, UUSInfo uusInfo,
                     Message result) {
        ...
        IRadio radioProxy = getRadioProxy(result);
        if (radioProxy != null) {
            RILRequest rr = obtainRequest(RIL_REQUEST_DIAL, result,
                    mRILDefaultWorkSource);
            ...
            try {
                radioProxy.dial(rr.mSerial, dialInfo);//請求撥號
            } catch (RemoteException | RuntimeException e) {
                handleRadioProxyExceptionForRR(rr, "dial", e);
            }
        }
    }

5.4.3 RILD接收到RILJ指令

RILD接收到RILJ指令,JAVA層與HAL層通過HIDL方式系結,即HAL也會有對應的dial映射方法,

@LINUX\android\hardware\ril\libril\ril_service.cpp
#define CALL_ONREQUEST(a, b, c, d, e) \
        s_vendorFunctions->onRequest((a), (b), (c), (d), ((RIL_SOCKET_ID)(e)))

Return<void> RadioImpl::dial(int32_t serial, const Dial& dialInfo) {
    ...
    CALL_ONREQUEST(RIL_REQUEST_DIAL, &dial, sizeOfDial, pRI, mSlotId);
    memsetAndFreeStrings(2, dial.address, uusInfo.uusData);
    return Void();
}

5.4.4 RILD和reference側訊息傳遞

onRequest方法是在哪里被實作的?我們需要關注下s_vendorFunctions是在哪個地方賦值的,關于s_vendorFunctions全域變數,當我們呼叫reference中的RIL_Init完成初始化時,就會得到reference回傳當前鏈接庫提供的介面函式,通過該介面函式我們便可實作rild側與reference側的通訊(reference側也是跑在rild行程,但是考慮到reference一般由modem廠商客制化,不清楚其內部實作,故以下將其稱為reference側,以便更好地區分該模塊),

@LINUX\android\hardware\ril\libril\ril.cpp
extern "C" void
RIL_register (const RIL_RadioFunctions *callbacks) {
    ...
    memcpy(&s_callbacks, callbacks, sizeof (RIL_RadioFunctions));//物件拷貝
    ...
    radio::registerService(&s_callbacks, s_commands);//注冊回呼函式
    ...
}

@LINUX\android\hardware\ril\libril\ril_service.cpp
void radio::registerService(RIL_RadioFunctions *callbacks, CommandInfo *commands) {
    ...
    s_vendorFunctions = callbacks;//將回呼函式物件賦值,以實作rild側與reference側的參考
    s_commands = commands;
    ...
}

5.4.5 reference側接收到訊息

reference層接收到訊息, 從onRequest可以看出,reference中對所有的命令請求進行判別,然后選擇不同的處理方式,

@LINUX\android\hardware\ril\reference-ril\reference-ril.c
static void onRequest (int request, void *data, size_t datalen, RIL_Token t)
{
    ...
    switch (request) {
        ...
        case RIL_REQUEST_DIAL:
            requestDial(data, datalen, t);//撥號請求
            break;
        case RIL_REQUEST_HANGUP://掛斷電話請求
            requestHangup(data, datalen, t);
            break;
        ...       
    }
}

static void requestDial(void *data, size_t datalen __unused, RIL_Token t)
{
    ...
    ret = at_send_command(cmd, NULL);//往modem層發送指令
    ...
    /* success or failure is ignored by the upper layer here.
       it will call GET_CURRENT_CALLS and determine success that way */
    RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
}

5.4.6 reference側將訊息發送至modem側

reference側將訊息發送至modem側,at_send_command() -> at_send_command_full() -> at_send_command_full_nolock(),經過上面的操作,就將一條命令通過串口方式傳輸到了Modem側,其間,完成了兩個重要動作:1、通過writeline發送資料到Modem;2、阻塞當前執行緒,等待Modem回應,

@LINUX\android\hardware\ril\reference-ril\atchannel.c
static int at_send_command_full_nolock (const char *command, ATCommandType type,
                    const char *responsePrefix, const char *smspdu,
                    long long timeoutMsec, ATResponse **pp_outResponse)
{
    ...
    err = writeline (command);//將命令通過AT指令方式寫入modem側
    if (err < 0) {
        goto error;
    }
    ...
    while (sp_response->finalResponse == NULL && s_readerClosed == 0) {
        if (timeoutMsec != 0) {
            err = pthread_cond_timedwait(&s_commandcond, &s_commandmutex, &ts);//阻塞執行緒,直到modem側訊息回傳
        } 
        ...
    }
    ...
    return err;
}

5.4.7 modem側發送訊息至reference側

modem側發送訊息至reference側,我們需要如何喚醒阻塞的執行緒呢?當我們發送資料或命令給Modem的時候,阻塞了當前的執行緒,阻塞的目的就是等待Modem的回應,而如果Modem有資料上來,那么肯定是先被reference的ReaderLoop檢測到并處理,因此,也應該是在ReaderLoop的訊息處理中去喚醒當前阻塞的執行緒,而且應該把Modem的反饋傳輸給阻塞執行緒,

@LINUX\android\hardware\ril\reference-ril\atchannel.c
static void *readerLoop(void *arg __unused)
{
    for (;;) {
        ...
        line = readline();//讀取modem回傳資料
        ...
        if(isSMSUnsolicited(line)) {
            ...
        } else {
            processLine(line);//決議訊息
        }
    }
    ...
    return NULL;
}

static void processLine(const char *line)
{
    ...
    if (sp_response == NULL) {
        /* no command pending */
        handleUnsolicited(line);//處理URC訊息
    } else if (isFinalResponseSuccess(line)) {
        sp_response->success = 1;
        handleFinalResponse(line);//發送回應訊息
    }
    ...
}

static void handleFinalResponse(const char *line)
{
    sp_response->finalResponse = strdup(line);
    pthread_cond_signal(&s_commandcond);//發送一個信號給另外一個正在處于阻塞等待狀態的執行緒,使其脫離阻塞狀態
}

5.4.8 reference側輪詢modem指令

reference側輪詢modem指令,ReaderLoop輪詢modem訊息又是在哪里實作的呢?RILD行程被創建后,會通過RIL_Init初始化相關的reference相關準備作業,其中涉及到打開與modem側的AT通道,監聽modem上報訊息,

@LINUX\android\hardware\ril\reference-ril\atchannel.c
const RIL_RadioFunctions *RIL_Init(const struct RIL_Env *env, int argc, char **argv)
{
    ...
    ret = pthread_create(&s_tid_mainloop, &attr, mainLoop, NULL);//創建mainLoop執行緒
    ...
}

static void *
mainLoop(void *param __unused)
{
    ...
    for (;;) {
        ...
        ret = at_open(fd, onUnsolicited);//打開AT通道并把處理URC訊息的方法onUnsolicited傳進去 
        ...
    }
}

@LINUX\android\hardware\ril\reference-ril\atchannel.c
int at_open(int fd, ATUnsolHandler h)
{
    ...
    ret = pthread_create(&s_tid_reader, &attr, readerLoop, &attr);//創建readerLooper執行緒,讀取AT指令并處理modem側訊息
    ...
}

六、RIL指令

6.1 RILJ主動發送指令

原始碼: android\hardware\ril\libril\ril_commands.h

指令 功能
RIL_REQUEST_GET_SIM_STATUS 獲取SIM卡狀態
RIL_REQUEST_ENTER_SIM_PIN 請求輸入SIM的PIN碼(PIN碼是用來保護SIM卡安全的密碼,PIN碼的初始值一般是1234,可以進行更改)
RIL_REQUEST_ENTER_SIM_PUK 請求PUK碼和新的PIN碼的輸入(PUK碼是用來解PIN碼的解鎖碼,共8位長)
RIL_REQUEST_ENTER_SIM_PIN2 請求輸入SIM的PIN2碼(進入某種特殊功能時,如設定固定號碼、設定通話計費等,所要輸入的個人識別碼)
RIL_REQUEST_ENTER_SIM_PUK2 請求PUK2碼和新的PIN2碼的輸入(PUK2碼就是專門用來為被鎖上的PIN2碼解鎖的)
RIL_REQUEST_CHANGE_SIM_PIN 請求更改PIN碼
RIL_REQUEST_CHANGE_SIM_PIN2 請求更改PIN2碼
RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION 請求輸入網路個人碼以便去激活
RIL_REQUEST_GET_CURRENT_CALLS 請求獲取當前呼叫串列
RIL_REQUEST_DIAL 初始化一個語音呼叫
RIL_REQUEST_GET_IMSI 取SIM卡中的國際移動用戶識別碼IMSI(區別移動用戶的標志,儲存在SIM卡中,可用于區別移動用戶的有效資訊)
RIL_REQUEST_HANGUP 掛斷某一激活的通話
RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND 掛斷所有等待的或者保持的通話
RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND 釋放所有激活的通話并激活保持的或者等待的通話
RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE 話連接狀態的轉換,將所有激活的通話轉為保持或等待狀態(通話狀態:IDLE、ACTIVE、HOLDING、WAITING等)
RIL__CONFERENCE 請求加入電話會議
RIL_REQUEST_UDUB 發送用戶確定用戶忙UDUB(user determined user busy)信號
RIL_REQUEST_LAST_CALL_FAIL_CAUSE 請求最近一次通話中斷的錯誤碼
RIL_REQUEST_SIGNAL_STRENGTH 請求當前的信號強度等相關資訊
RIL_REQUEST_VOICE_REGISTRATION_STATE 請求當前注冊狀態(描述的是信號柱的顯示)
RIL_REQUEST_DATA_REGISTRATION_STATE 請求當前注冊狀態(描述的是3G、4G的顯示)
RIL_REQUEST_OPERATOR 請求運營商名稱
RIL_REQUEST_RADIO_POWER 請求打開無線電通訊
RIL_REQUEST_DTMF 發起DTMF請求(在手機中,常用的DTMF場景是使用手機撥打一些服務臺電話,比如客服熱線10086、10000之類;電話接入之后,有對應的語音提示輸入不同的數字進入不同的選單,或者要修改資料,對方要驗證我們的賬號和密碼,這時打開手機撥號盤,輸入數字資訊,對方就知道我們輸入的內容是什么,)
RIL_REQUEST_SEND_SMS 發送短信
RIL_REQUEST_SEND_SMS_EXPECT_MORE 發送短信,且支持串聯短信
RIL_REQUEST_SETUP_DATA_CALL 請求打開資料流量
RIL_REQUEST_SIM_IO 獲取SIM卡號
RIL_REQUEST_SEND_USSD 請求一個USSD業務(ussd即非結構化補充資料業務,是一種全球移動通信系統 (GSM) 協議,用于發送訊息和文本檔案,USSD代碼一般以*開頭,以#結尾,可用于執行一些隱藏功能,)
RIL_REQUEST_CANCEL_USSD 撤銷一個USSD業務
RIL_REQUEST_GET_CLIR 查詢當前呼叫號碼是否隱藏請求
RIL_REQUEST_SET_CLIR 設定呼叫號碼是否隱藏
RIL_REQUEST_QUERY_CALL_FORWARD_STATUS 查詢呼叫轉移的狀態
RIL_REQUEST_SET_CALL_FORWARD 設定呼叫轉移
RIL_REQUEST_QUERY_CALL_WAITING 查詢呼叫等待資訊
RIL_REQUEST_SET_CALL_WAITING 設定呼叫等待狀態(當移動電話用戶正在進行通話時,又有呼叫向您發來,這時發起新呼叫的一方被置于等待,待原通話結束后再將新呼叫接入,)
RIL_REQUEST_SMS_ACKNOWLEDGE 用于短信訊息的傳送應答
RIL_REQUEST_GET_IMEI 獲取IMEI號
RIL_REQUEST_GET_IMEISV 獲取IMEISV號(MEI有15位,最后一位是Check digit,即檢驗位;IMEISV有16位,是去掉了Check digit,加上了兩位SVN,即software version number,)
RIL_REQUEST_ANSWER 接聽電話請求
RIL_REQUEST_DEACTIVATE_DATA_CALL 斷開資料流量業務
RIL_REQUEST_QUERY_FACILITY_LOCK 查詢設備鎖定狀態
RIL_REQUEST_SET_FACILITY_LOCK 設定設備鎖定狀態
RIL_REQUEST_CHANGE_BARRING_PASSWORD 修改呼叫限制密碼
RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE 查詢網路選擇
RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC 設定網路選擇為自動
RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL 設定網路選擇為手動
RIL_REQUEST_QUERY_AVAILABLE_NETWORKS 查詢可用網路串列
RIL_REQUEST_DTMF_START 啟動DTMF功能
RIL_REQUEST_DTMF_STOP 關閉DTMF功能
RIL_REQUEST_BASEBAND_VERSION 獲取基帶版本
RIL_REQUEST_SEPARATE_CONNECTION 將所有激活的呼叫掛起
RIL_REQUEST_SET_MUTE 設定靜音
RIL_REQUEST_ALLOW_DATA 設定雙卡資料切換
RIL_REQUEST_GET_MUTE 獲取靜音狀態
RIL_REQUEST_QUERY_CLIP 查詢主叫號碼(主叫號碼識別顯示補充業務,CLIP是指被叫移動用戶的補充業務,移動用戶接收呼叫時,網路向用戶提示主叫用戶的號碼,)
RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE 查詢上一次資料連接失敗原因
RIL_REQUEST_DATA_CALL_LIST 查詢資料連接資訊
RIL_REQUEST_RESET_RADIO 復位模塊
RIL_REQUEST_OEM_HOOK_RAW ???
RIL_REQUEST_OEM_HOOK_STRINGS ???
RIL_REQUEST_SCREEN_STATE 查詢螢屏狀態
RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION 啟用/禁用來自網路的補充服務相關通知
RIL_REQUEST_WRITE_SMS_TO_SIM 復制短信到SIM卡中
RIL_REQUEST_DELETE_SMS_ON_SIM 洗掉SIM卡短信
RIL_REQUEST_SET_BAND_MODE 設定頻段模式
RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE 查詢可用頻段模式
RIL_REQUEST_STK_GET_PROFILE 查詢STK的配置資訊
RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND 請求打開STK子選單
RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE 獲取STK子選單資訊
RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM 接受或拒絕來自SIM卡的呼叫設定請求,
RIL_REQUEST_EXPLICIT_CALL_TRANSFER 請求呼叫轉接業務
RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE 設定偏好的網路型別
RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE 獲取偏好的網路型別
RIL_REQUEST_GET_NEIGHBORING_CELL_IDS 獲取此設備上的相鄰單元串列
RIL_REQUEST_SET_LOCATION_UPDATES 位置更新
RIL_REQUEST_CDMA_SET_SUBSCRIPTION_SOURCE 請求設定CDMA訂閱模式
RIL_REQUEST_CDMA_SET_ROAMING_PREFERENCE 設定偏好漫游型別
RIL_REQUEST_CDMA_QUERY_ROAMING_PREFERENCE 查詢偏好漫游型別
RIL_REQUEST_SET_TTY_MODE 設定為聾啞模式
RIL_REQUEST_QUERY_TTY_MODE 查詢聾啞模式狀態
RIL_REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE 設定首選語音隱私(VP)
RIL_REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE 獲取當前設定的首選語音隱私(VP)模式,
RIL_REQUEST_CDMA_FLASH ???
RIL_REQUEST_CDMA_BURST_DTMF 發起DTMS請求
RIL_REQUEST_CDMA_VALIDATE_AND_WRITE_AKEY ???
RIL_REQUEST_CDMA_SEND_SMS CDMA發送短信
RIL_REQUEST_CDMA_SMS_ACKNOWLEDGE CDMA短信訊息的傳送應答
RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG 獲取小區廣播配置,通過小區廣播信道(CBCH)將資訊(如地理位置、天氣狀況等資訊)傳到手機,再由用戶選擇接收的一種功能,通過此功能可向用戶提供位置資訊,天氣預報等服務;是向中國移動的手機客戶按區域、按頻道發送各種實時、動態的分類資訊的業務,
RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG 設定小區廣播配置
RIL_REQUEST_GSM_SMS_BROADCAST_ACTIVATION 小區廣播功能開關
RIL_REQUEST_CDMA_GET_BROADCAST_SMS_CONFIG CDMA獲取小區廣播配置
RIL_REQUEST_CDMA_SET_BROADCAST_SMS_CONFIG CDMA設定小區廣播配置
RIL_REQUEST_CDMA_SMS_BROADCAST_ACTIVATION CDMA小區廣播開關
RIL_REQUEST_CDMA_SUBSCRIPTION 查詢CDMA的實作模式(CDMA手機兩實作模式:
機卡分離式:用戶信息寫在單獨的UIM
卡機卡一體式:用戶資訊寫在手機中的)
RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM CDMA復制短息到uim卡,RUIM是應用在CDMA2000手機的一種智能卡
RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM CDMA洗掉RUIM卡上短信
RIL_REQUEST_DEVICE_IDENTITY 請求設備標識
RIL_REQUEST_EXIT_EMERGENCY_CALLBACK_MODE 離開緊急回撥模式
RIL_REQUEST_GET_SMSC_ADDRESS 獲取SMSC地址,網路短資訊服務中心地址
RIL_REQUEST_SET_SMSC_ADDRESS 設定SMSC地址
RIL_REQUEST_REPORT_SMS_MEMORY_STATUS 通知modem,SMS的存盤情況
RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING 通知modem,StkService已經啟動
RIL_REQUEST_CDMA_GET_SUBSCRIPTION_SOURCE 設定CDMA的實作模式
RIL_REQUEST_ISIM_AUTHENTICATION ISIM認證
RIL_REQUEST_ACKNOWLEDGE_INCOMING_GSM_SMS_WITH_PDU 確認收到成功或失敗的最后一條傳入短信,包括確認TPDU作為RP-ACK或RP-ERROR PDU的RP-User-Data元素發送,
RIL_REQUEST_STK_SEND_ENVELOPE_WITH_STATUS ???
RIL_REQUEST_VOICE_RADIO_TECH 獲取當前的語音無線電技術,
RIL_REQUEST_GET_CELL_INFO_LIST 獲取當前的信元資訊
RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE 設定信元資訊的呼叫時間,即onCellInfoChanged的回應時間
RIL_REQUEST_SET_INITIAL_ATTACH_APN 初始化APN
RIL_REQUEST_IMS_REGISTRATION_STATE 查詢IMS的注冊狀態
RIL_REQUEST_IMS_SEND_SMS 請求IMS發送短信
RIL_REQUEST_SIM_TRANSMIT_APDU_BASIC 在基本頻道上與SIM交換apdu
RIL_REQUEST_SIM_OPEN_CHANNEL 打開SIM無線信道
RIL_REQUEST_SIM_CLOSE_CHANNEL 關閉SIM無線信道
RIL_REQUEST_SIM_TRANSMIT_APDU_CHANNEL 在邏輯信道上與SIM交換APDU,
RIL_REQUEST_NV_READ_ITEM 讀取{@link RadioNVItems} / {@code ril_nv_items.h}中定義的NV項之一,用于部分CDMA運營商的設備配置,
RIL_REQUEST_NV_WRITE_ITEM 寫一個定義在{@link RadioNVItems} / {@code ril_nv_items.h}的NV項,用于部分CDMA運營商的設備配置,
RIL_REQUEST_NV_WRITE_CDMA_PRL 更新無線電NV存盤中的CDMA首選漫游串列(PRL),用于部分CDMA運營商的設備配置,
RIL_REQUEST_NV_RESET_CONFIG 執行modem配置復位,用于部分CDMA運營商的設備配置,
RIL_REQUEST_SET_UICC_SUBSCRIPTION ???
RIL_REQUEST_ALLOW_DATA 雙卡資料切換
RIL_REQUEST_GET_HARDWARE_CONFIG 獲取RIL的硬體配置
RIL_REQUEST_SIM_AUTHENTICATION SIM卡身份認證
RIL_REQUEST_GET_DC_RT_INFO ???
RIL_REQUEST_SET_DC_RT_INFO_RATE ???
RIL_REQUEST_SET_DATA_PROFILE 發送當前運營商的資料組態檔到資料服務進行資料呼叫設定,這是僅適用于CDMA運營商,可通過OTA更改組態檔,資料服務應該總是使用最新的資料組態檔發送的框架,
RIL_REQUEST_SHUTDOWN 關機
RIL_REQUEST_GET_RADIO_CAPABILITY 獲取電話無線電功能
RIL_REQUEST_SET_RADIO_CAPABILITY 設定電話無線電型別和接入技術,
RIL_REQUEST_START_LCE 啟動LCE(鏈路容量估計)服務,并設定所需的報告間隔,
RIL_REQUEST_STOP_LCE 停止LCE服務,
RIL_REQUEST_PULL_LCEDATA 獲取LCE服務獲取容量資料,
RIL_REQUEST_GET_ACTIVITY_INFO 請求modem的活動資訊
RIL_REQUEST_SET_CARRIER_RESTRICTIONS ???
RIL_REQUEST_GET_CARRIER_RESTRICTIONS ???
RIL_REQUEST_SEND_DEVICE_STATE 發送設備狀態到Modem
RIL_REQUEST_SET_UNSOLICITED_RESPONSE_FILTER 打開/關閉調制解調器的主動回應
RIL_REQUEST_SET_SIM_CARD_POWER 設定SIM卡上電狀態, @param state SIM卡狀態(斷電、上電、通過)
RIL_REQUEST_SET_CARRIER_INFO_IMSI_ENCRYPTION 設定加密IMSI和IMPI所需的運營商資訊,
RIL_REQUEST_START_NETWORK_SCAN 掃描網路
RIL_REQUEST_STOP_NETWORK_SCAN 停止掃描網路
RIL_REQUEST_START_KEEPALIVE 啟動長連接
RIL_REQUEST_STOP_KEEPALIVE 停止長連接

6.2 RILJ被動接收指令

原始碼: android\hardware\ril\libril\ril_unsol_commands.h

指令 功能
RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED 無線通信模塊狀態改變
RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED 來電狀態改變
RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED 信號狀態改變
RIL_UNSOL_RESPONSE_NEW_SMS 收到短信
RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT 短信發送狀態報告
RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM ???
RIL_UNSOL_ON_USSD ???
RIL_UNSOL_ON_USSD_REQUEST ???
RIL_UNSOL_NITZ_TIME_RECEIVED 通知更新終端系統的時間及時區
RIL_UNSOL_DATA_CALL_LIST_CHANGED 資料連接狀態改變
RIL_UNSOL_SUPP_SVC_NOTIFICATION ???
RIL_UNSOL_STK_SESSION_END 通知會話結束
RIL_UNSOL_STK_PROACTIVE_COMMAND 插卡開機,Modem檢測到有卡插入,這時候Modem會讀取SIM中的相關資訊,并把訊息上報給RIL層,顯示STK主選單
RIL_UNSOL_STK_EVENT_NOTIFY 用于STK事件分發
RIL_UNSOL_STK_CALL_SETUP 發送來自modem的撥打電話的主動上報訊息
RIL_UNSOL_SIM_SMS_STORAGE_FULL 通知空間滿了
RIL_UNSOL_SIM_REFRESH modem請求更新卡對應的檔案資訊
RIL_UNSOL_CALL_RING 有來電時上報
RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED SIM卡狀態改變
RIL_UNSOL_RESPONSE_CDMA_NEW_SMS 接收到CDMA短信
RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS ???
RIL_UNSOL_CDMA_RUIM_SMS_STORAGE_FULL ???
RIL_UNSOL_RESTRICTED_STATE_CHANGED 受限策略改變通知
RIL_UNSOL_ENTER_EMERGENCY_CALLBACK_MODE 進入緊急回撥模式通知
RIL_UNSOL_CDMA_CALL_WAITING 呼叫等待通知
RIL_UNSOL_CDMA_OTA_PROVISION_STATUS ???
RIL_UNSOL_CDMA_INFO_REC ???
RIL_UNSOL_OEM_HOOK_RAW ???
RIL_UNSOL_RINGBACK_TONE 電話鈴聲
RIL_UNSOL_RESEND_INCALL_MUTE ???
RIL_UNSOL_CDMA_SUBSCRIPTION_SOURCE_CHANGED 管理 機卡分離 Or 機卡一體的訊息
RIL_UNSOL_CDMA_PRL_CHANGED 優選漫游串列更新通知
RIL_UNSOL_EXIT_EMERGENCY_CALLBACK_MODE 離開緊急回撥模式通知
RIL_UNSOL_RIL_CONNECTED RIL連接成功通知
RIL_UNSOL_VOICE_RADIO_TECH_CHANGED ???
RIL_UNSOL_CELL_INFO_LIST ???
RIL_UNSOL_RESPONSE_IMS_NETWORK_STATE_CHANGED ???
RIL_UNSOL_UICC_SUBSCRIPTION_STATUS_CHANGED ???
RIL_UNSOL_SRVCC_STATE_NOTIFY ???
RIL_UNSOL_HARDWARE_CONFIG_CHANGED ???
RIL_UNSOL_DC_RT_INFO_CHANGED ???
RIL_UNSOL_RADIO_CAPABILITY ???
RIL_UNSOL_ON_SS ???
RIL_UNSOL_STK_CC_ALPHA_NOTIFY ???
RIL_UNSOL_LCEDATA_RECV ???
RIL_UNSOL_PCO_DATA ???
RIL_UNSOL_MODEM_RESTART modem重啟通知
RIL_UNSOL_CARRIER_INFO_IMSI_ENCRYPTION ???
RIL_UNSOL_NETWORK_SCAN_RESULT 通知網路掃描結果
RIL_UNSOL_KEEPALIVE_STATUS 通知心跳狀態

七、參考資料

https://source.android.google.cn/docs/core/connect/ims?hl=zh-cn
http://www.taodudu.cc/news/show-3144813.html?action=onClick
http://baike.jld5.cn/news/51009.html
https://wiki.mbalib.com/wiki/IMS
https://blog.csdn.net/guyuewangyue/article/details/122866358
電路交換和分組交換區別:
https://www.elecfans.com/d/1308634.html
TeleComService介紹:
https://blog.csdn.net/qq_40587575/article/details/113753895
TeleService介紹:
https://www.jianshu.com/p/ff51295b84a1
Rild介紹:
https://www.freesion.com/article/21011164222/
https://blog.csdn.net/u014386544/article/details/52594400
RIL指令:
https://www.mianshigee.com/note/detail/23890yjg/
https://blog.csdn.net/iteye_6233/article/details/82230745
https://blog.csdn.net/u010961631/article/details/9446377/
https://blog.csdn.net/sjz4860402/article/details/51182078
http://www.2sim.cn/article/13
https://zhuanlan.zhihu.com/p/117218424
https://blog.csdn.net/u014386544/article/details/56851616

轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/555310.html

標籤:其他

上一篇:WWDC2023 Session系列:探索XCode15新特性

下一篇:返回列表

標籤雲
其他(161089) Python(38230) JavaScript(25498) Java(18240) C(15237) 區塊鏈(8271) C#(7972) AI(7469) 爪哇(7425) MySQL(7254) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5875) 数组(5741) R(5409) Linux(5347) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4598) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2436) ASP.NET(2404) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) .NET技术(1984) 功能(1967) HtmlCss(1967) Web開發(1951) C++(1940) python-3.x(1918) 弹簧靴(1913) xml(1889) PostgreSQL(1881) .NETCore(1863) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【從零開始擼一個App】Dagger2

    Dagger2是一個IOC框架,一般用于Android平臺,第一次接觸的朋友,一定會被搞得暈頭轉向。它延續了Java平臺Spring框架代碼碎片化,注解滿天飛的傳統。嘗試將各處代碼片段串聯起來,理清思緒,真不是件容易的事。更不用說還有各版本細微的差別。 與Spring不同的是,Spring是通過反射 ......

    uj5u.com 2020-09-10 06:57:59 more
  • Flutter Weekly Issue 66

    新聞 Flutter 季度調研結果分享 教程 Flutter+FaaS一體化任務編排的思考與設計 詳解Dart中如何通過注解生成代碼 GitHub 用對了嗎?Flutter 團隊分享如何管理大型開源專案 插件 flutter-bubble-tab-indicator A Flutter librar ......

    uj5u.com 2020-09-10 06:58:52 more
  • Proguard 常用規則

    介紹 Proguard 入口,如何查看輸出,如何使用 keep 設定入口以及使用實體,如何配置壓縮,混淆,校驗等規則。

    ......

    uj5u.com 2020-09-10 06:59:00 more
  • Android 開發技術周報 Issue#292

    新聞 Android即將獲得類AirDrop功能:可向附近設備快速分享檔案 谷歌為安卓檔案管理應用引入可安全隱藏資料的Safe Folder功能 Android TV新主界面將顯示電影、電視節目和應用推薦內容 泄露的Android檔案暗示了傳說中的谷歌Pixel 5a與折疊屏新機 谷歌發布Andro ......

    uj5u.com 2020-09-10 07:00:37 more
  • AutoFitTextureView Error inflating class

    報錯: Binary XML file line #0: Binary XML file line #0: Error inflating class xxx.AutoFitTextureView 解決: <com.example.testy2.AutoFitTextureView android: ......

    uj5u.com 2020-09-10 07:00:41 more
  • 根據Uri,Cursor沒有獲取到對應的屬性

    Android: 背景:呼叫攝像頭,拍攝視頻,指定保存的地址,但是回傳的Cursor檔案,只有名稱和大小的屬性,沒有其他諸如時長,連ID屬性都沒有 使用 cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATIO ......

    uj5u.com 2020-09-10 07:00:44 more
  • Android連載29-持久化技術

    一、持久化技術 我們平時所使用的APP產生的資料,在記憶體中都是瞬時的,會隨著斷電、關機等丟失資料,因此android系統采用了持久化技術,用于存盤這些“瞬時”資料 持久化技術包括:檔案存盤、SharedPreference存盤以及資料庫存盤,還有更復雜的SD卡記憶體儲。 二、檔案存盤 最基本存盤方式, ......

    uj5u.com 2020-09-10 07:00:47 more
  • Android Camera2Video整合到自己專案里

    背景: Android專案里呼叫攝像頭拍攝視頻,原本使用的 MediaStore.ACTION_VIDEO_CAPTURE, 后來因專案需要,改成了camera2 1.Camera2Video 官方demo有點問題,下載后,不能直接整合到專案 問題1.多次拍攝視頻崩潰 問題2.雙擊record按鈕, ......

    uj5u.com 2020-09-10 07:00:50 more
  • Android 開發技術周報 Issue#293

    新聞 谷歌為Android TV開發者提供多種新功能 Android 11將自動填表功能整合到鍵盤輸入建議中 谷歌宣布Android Auto即將支持更多的導航和數字停車應用 谷歌Pixel 5只有XL版本 搭載驍龍765G且將比Pixel 4更便宜 [圖]Wear OS將迎來重磅更新:應用啟動時間 ......

    uj5u.com 2020-09-10 07:01:38 more
  • 海豚星空掃碼投屏 Android 接收端 SDK 集成 六步驟

    掃碼投屏,開放網路,獨占設備,不需要額外下載軟體,微信掃碼,發現設備。支持標準DLNA協議,支持倍速播放。視頻,音頻,圖片投屏。好點意思。還支持自定義基于 DLNA 擴展的操作動作。好像要收費,沒體驗。 這里簡單記錄一下集成程序。 一 跟目錄的build.gradle添加私有mevan倉庫 mave ......

    uj5u.com 2020-09-10 07:01:43 more
最新发布
  • Android RIL&IMS原始碼分析

    # 一、需求 1、了解IMS相關知識體系 2、RILD 與 RILJ、IMS回呼訊息的機制 # 二、相關概念 ## 2.1 IMS IMS全稱是IP Multimedia Subsystem,中文意義為IP多媒體子系統。IMS是一種基于IP基礎結構,能夠融合資料、話音和移動等網路技術的系統。 **I ......

    uj5u.com 2023-06-16 08:29:53 more
  • WWDC2023 Session系列:探索XCode15新特性

    ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/44a0e0fd567c4421bc94be83e84f6dce~tplv-k3u1fbpfcp-zoom-1.image) ## 一、版本說明 XCode 15 beta 發布于 2023 ......

    uj5u.com 2023-06-16 08:29:31 more
  • 推送服務接入指導(HarmonyOS篇)

    訊息推送作為App運營日常使用的用戶促活和召回手段,是與用戶建立持續互動和連接的良好方式。[推送服務](https://developer.huawei.com/consumer/cn/hms/huawei-pushkit?ha_source=hms1)(Push Kit)是華為提供的訊息推送平臺, ......

    uj5u.com 2023-06-16 08:29:18 more
  • Kotlin協程-那些理不清亂不明的關系

    > Kotlin的協程自推出以來,受到了越來越多Android開發者的追捧。另一方面由于它龐大的API,也將相當一部分開發者拒之門外。本篇試圖從協程的幾個重要概念入手,在復雜API中還原出它本來的面目,以全新的角度帶讀者走進Kotlin協程世界。 ### 什么是協程 在很多有關協程的文章中,描述協程 ......

    uj5u.com 2023-06-16 08:29:14 more
  • 社交直播語聊場景解決方案(一)商業化探索

    在過去幾年的直播行業創業風口期中,直播的用戶關注度瘋狂增長,但用戶質量卻參差不齊。隨著用戶新鮮感一過,流失率變得相當嚴重,各大平臺都在竭盡全力防御。然而,留住“湊熱鬧”的非直播受眾用戶并不是最關鍵的問題,而是要找到適合真實直播受眾用戶的商業化道路,才能保證行業的穩定繁榮。因此,我們需要探索有效的商業... ......

    uj5u.com 2023-06-16 08:29:10 more
  • Android RIL&IMS原始碼分析

    # 一、需求 1、了解IMS相關知識體系 2、RILD 與 RILJ、IMS回呼訊息的機制 # 二、相關概念 ## 2.1 IMS IMS全稱是IP Multimedia Subsystem,中文意義為IP多媒體子系統。IMS是一種基于IP基礎結構,能夠融合資料、話音和移動等網路技術的系統。 **I ......

    uj5u.com 2023-06-16 08:28:52 more
  • 還在為618電商推送方案煩惱?我們幫你做好了!

    618是每年重要的電商大促活動,熱度高流量大,是電商App吸引新用戶,提高用戶轉化率(購買率)的最好時機。對電商App運營來說,訊息推送是不可忽略的流量來源之一,適當的訊息推送可以召回用戶,提高用戶復購率。如何利用訊息推送功能在618電商節幫助App獲取流量并提高轉化率是運營需要關注的問題。 在回答 ......

    uj5u.com 2023-06-15 08:45:16 more
  • 還在為618電商推送方案煩惱?我們幫你做好了!

    618是每年重要的電商大促活動,熱度高流量大,是電商App吸引新用戶,提高用戶轉化率(購買率)的最好時機。對電商App運營來說,訊息推送是不可忽略的流量來源之一,適當的訊息推送可以召回用戶,提高用戶復購率。如何利用訊息推送功能在618電商節幫助App獲取流量并提高轉化率是運營需要關注的問題。 在回答 ......

    uj5u.com 2023-06-15 08:43:32 more
  • 沉思篇-剖析Jetpack的ViewModel

    > ViewModel做為架構組件的三元老之一,是實作MVVM的有力武器。 ### ViewModel的設計目標 ViewModel的基本功能就是管理UI的資料。其實,從職責上來說,這又是對Activity和Fragment的一次功能拆分。以前存盤在它們內部的資料,需要它們自己處理創建,更新,存盤, ......

    uj5u.com 2023-06-14 10:17:31 more
  • 插件化工程R檔案瘦身技術方案 | 京東云技術團隊

    隨著業務的發展及版本迭代,客戶端工程中不斷增加新的業務邏輯、引入新的資源,隨之而來的問題就是安裝包體積變大,前期各個業務模塊通過無用資源刪減、大圖壓碩訓轉上云、AB實驗業務邏輯下線或其他手段在降低包體積上取得了一定的成果。 ......

    uj5u.com 2023-06-14 10:17:13 more