MTK IMS框架簡析(2)——IMS注冊過程


本文鏈接:https://blog.csdn.net/meiliqiang/article/details/78501947, 感謝作者

MTK IMS框架簡析(2)——IMS注冊過程

標簽: Phone  IMS

 
 

之前在《MTK IMS框架簡析(1)——代碼架構及模塊初始化》 中已經分析了ims代碼的構成和重點類的初始化,接下來以啟用VOLTE子功能為例,具體分析AP側IMS服務的注冊過程。


概要

IMS注冊前提是系統啟用了volte或wifi calling等功能,Volte開關一般在網絡設置界面會提供(如下圖),用戶切換開關狀態將觸發ims的注冊或注銷。 
這里寫圖片描述

啟用Volte后的消息傳遞序列(這里時序圖避免復雜化,只表現消息的正向傳遞,忽略消息的返回)

frameworkframeworkims appims apprild imsrild imsvolte_imsmvolte_imsmrildrildTurn on IMS feature打開IMS子功能RIL_REQUEST_SET_VOLTE_ENABLERIL_REQUEST_SET_IMS_VOICE_ENABLERIL_REQUEST_SET_IMS_ENABLERIL_UNSOL_IMS_ENABLE_STARTIMS_SERVICE_UPMSG_ID_IMS_ENABLE_INDMSG_ID_WRAP_IMSM_IMSPA_PDN_ACT_REQRequest Network建立IMS承載SETUP_DATA_CALL(ims apn)MSG_ID_WRAP_IMSPA_IMSM_PDN_ACT_ACK_RESP成功建立承載RIL_UNSOL_IMS_REGISTRATION_INFO上報IMS注冊狀態

整個過程大致分為3步: 
1. 設置並啟用ims 
2. 建立ims承載 
3. 注冊ims服務 
接下來結合代碼詳細分析。


IMS注冊過程

從界面啟用IMS

此過程會向rild-ims下發3個消息,通知rild需要打開哪些ims業務,然后開啟ims服務:

  1.  
    //啟用volte語音服務
  2.  
    RIL_REQUEST_SET_VOLTE_ENABLE
  3.  
    RIL_REQUEST_SET_IMS_VOICE_ENABLE
  4.  
    //啟動ims功能
  5.  
    RIL_REQUEST_SET_IMS_ENABLE
  • 1
  • 2
  • 3
  • 4
  • 5

這里就從用戶打開界面開關開始分析。 
ImsManager::setAdvanced4GMode方法為volte功能的開關,設置界面即通過此接口實現volte開關。 
1. 向ImsConfig設置了feature(ImsConfig::setFeatureValue) 
2. 打開ims (turnOnIms)。

  1.  
    //ImsManager.java
  2.  
    private void setAdvanced4GMode(boolean turnOn) throws ImsException {
  3.  
    checkAndThrowExceptionIfServiceUnavailable();
  4.  
    try {
  5.  
    ImsConfig config = getConfigInterface();
  6.  
    if (config != null) {
  7.  
    //設置啟用volte語音
  8.  
    config.setFeatureValue(ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_LTE,
  9.  
    TelephonyManager.NETWORK_TYPE_LTE, turnOn ? 1 : 0, null);
  10.  
    }
  11.  
    } catch (ImsException e) {
  12.  
    }
  13.  
    //啟用ims服務
  14.  
    if (turnOn) {
  15.  
    turnOnIms();
  16.  
    } else if (isImsTurnOffAllowed()) {
  17.  
    turnOffIms();
  18.  
    }
  19.  
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

ImsConfig::setFeatureValue 作用是告訴ril目前要啟用ims的哪些功能. 
當前討論的例子是打開volte,因此參數為”FEATURE_TYPE_VOICE_OVER_LTE”。 
其他業務的定義在ImsConfig.java中:

  1.  
    //ImsConfig.java
  2.  
    public static class FeatureConstants {
  3.  
    public static final int FEATURE_TYPE_UNKNOWN = -1;
  4.  
     
  5.  
    /**
  6.  
    * FEATURE_TYPE_VOLTE supports features defined in 3GPP and
  7.  
    * GSMA IR.92 over LTE.
  8.  
    */
  9.  
    public static final int FEATURE_TYPE_VOICE_OVER_LTE = 0;
  10.  
     
  11.  
    /**
  12.  
    * FEATURE_TYPE_LVC supports features defined in 3GPP and
  13.  
    * GSMA IR.94 over LTE.
  14.  
    */
  15.  
    public static final int FEATURE_TYPE_VIDEO_OVER_LTE = 1;
  16.  
     
  17.  
    /**
  18.  
    * FEATURE_TYPE_VOICE_OVER_WIFI supports features defined in 3GPP and
  19.  
    * GSMA IR.92 over WiFi.
  20.  
    */
  21.  
    public static final int FEATURE_TYPE_VOICE_OVER_WIFI = 2;
  22.  
     
  23.  
    /**
  24.  
    * FEATURE_TYPE_VIDEO_OVER_WIFI supports features defined in 3GPP and
  25.  
    * GSMA IR.94 over WiFi.
  26.  
    */
  27.  
    public static final int FEATURE_TYPE_VIDEO_OVER_WIFI = 3;
  28.  
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

ImsConfig實際上是ims app/ImsConfigImpl的代理,setFeatureValue方法具體邏輯在ImsConfigImpl中。 
這里傳入的feature為FEATURE_TYPE_VOICE_OVER_LTE,因此會向rild-ims下發2個消息:RIL_REQUEST_SET_VOLTE_ENABLE及RIL_REQUEST_SET_IMS_VOICE_ENABLE。

  1.  
    //ImsConfigImpl.java
  2.  
    public void setFeatureValue(int feature, int network, int value, ImsConfigListener listener) {
  3.  
    try {
  4.  
    try {
  5.  
    //將設置值保存到數據庫
  6.  
    mStorage.setFeatureValue(feature, network, value);
  7.  
    //不同的feature需要不同的設置,這里只分析volte的處理
  8.  
    switch(feature) {
  9.  
    case ImsConfig.FeatureConstants.FEATURE_TYPE_VIDEO_OVER_LTE:
  10.  
    case ImsConfig.FeatureConstants.FEATURE_TYPE_VIDEO_OVER_WIFI:
  11.  
    ...
  12.  
    break;
  13.  
    case ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_WIFI:
  14.  
    ...
  15.  
    break;
  16.  
    case ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_LTE:
  17.  
    int oldVoLTEValue = SystemProperties.getInt(PROPERTY_VOLTE_ENALBE, 0);
  18.  
    int wfcEnable = SystemProperties.getInt(PROPERTY_WFC_ENALBE, 0);
  19.  
    if (value != oldVoLTEValue) {
  20.  
    //打開
  21.  
    if (value == ImsConfig.FeatureValueConstants.ON) {
  22.  
    //設置property
  23.  
    SystemProperties. set(PROPERTY_VOLTE_ENALBE,"1");
  24.  
    //向rild-ims下發RIL_REQUEST_SET_VOLTE_ENABLE
  25.  
    mRilAdapter.turnOnVolte( null);
  26.  
    if (wfcEnable == 0){
  27.  
    //向rild-ims下發RIL_REQUEST_SET_IMS_VOICE_ENABLE
  28.  
    mRilAdapter.turnOnImsVoice( null);
  29.  
    }
  30.  
    } else {//關閉
  31.  
    SystemProperties. set(PROPERTY_VOLTE_ENALBE,"0");
  32.  
    mRilAdapter.turnOffVolte( null);
  33.  
    if (wfcEnable == 0){
  34.  
    mRilAdapter.turnOffImsVoice( null);
  35.  
    }
  36.  
    }
  37.  
    }
  38.  
    break;
  39.  
    default:
  40.  
    break;
  41.  
    }
  42.  
    ...
  43.  
    } catch (ImsException e) {
  44.  
    ...
  45.  
    }
  46.  
    } catch (RemoteException e) {
  47.  
    throw new RuntimeException(e);
  48.  
    }
  49.  
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49

ImsConfig處理完成,繼續執行ImsManager::turnOnIms,這同樣是aidl調用,實際操作由ImsService.turnOnIms執行。

  1.  
    //ImsManager.java
  2.  
    private void turnOnIms() throws ImsException {
  3.  
    checkAndThrowExceptionIfServiceUnavailable();
  4.  
     
  5.  
    try {
  6.  
    mImsService.turnOnIms(mPhoneId);
  7.  
    } catch (RemoteException e) {
  8.  
    throw new ImsException("turnOnIms() ", e, ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
  9.  
    }
  10.  
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

turnOnIms同樣是向rild-ims下發消息:RIL_REQUEST_SET_IMS_ENABLE。

  1.  
    //ImsService.java
  2.  
    @Override
  3.  
    public void turnOnIms(int phoneId) {
  4.  
    if (mActivePhoneId != phoneId) {
  5.  
    mActivePhoneId = phoneId;
  6.  
    }
  7.  
     
  8.  
    if (mImsState != PhoneConstants.IMS_STATE_ENABLE) {
  9.  
    mImsRILAdapter.turnOnIms(mHandler.obtainMessage(EVENT_SET_IMS_ENABLED_DONE));
  10.  
    mImsState = PhoneConstants.IMS_STATE_ENABLING;
  11.  
    } else {
  12.  
    }
  13.  
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

下發了這3條消息后,等待ImsRilAdapter上報RIL_UNSOL_IMS_ENABLE_START來確認IMS服務已經啟用。 
這里寫圖片描述

ImsService在構造方法中注冊了RIL_UNSOL_IMS_ENABLE_START消息的監聽,消息上報后便會由它處理。

  1.  
    //ImsService.java
  2.  
    mImsRILAdapter.registerForImsEnableStart(mHandler, EVENT_IMS_ENABLING_URC, null);
  • 1
  • 2

ImsService中對RIL_UNSOL_IMS_ENABLE_START的處理如下: 
1. 發送ACTION_IMS_SERVICE_UP廣播; 
2. 調用enableImsAdapter()

  1.  
    //ImsService.java
  2.  
    case EVENT_IMS_ENABLING_URC:
  3.  
    //+EIMS: 1
  4.  
    if (mActivePhoneId != phoneId) {
  5.  
    mActivePhoneId = phoneId;
  6.  
    }
  7.  
    // notify AP Ims Service is up
  8.  
    intent = new Intent(ImsManager.ACTION_IMS_SERVICE_UP);
  9.  
    intent.putExtra(ImsManager.EXTRA_PHONE_ID, mActivePhoneId);
  10.  
    mContext.sendBroadcast(intent);
  11.  
    // enable ImsAdapter
  12.  
    enableImsAdapter();
  13.  
    mImsState = PhoneConstants.IMS_STATE_ENABLE;
  14.  
    break;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

《MTK IMS框架簡析(1)——代碼架構及模塊初始化》 中提到過,ACTION_IMS_SERVICE_UP會觸發ImsPhone和相關telephony類的初始化,因此這里跳過。 
而ImsAdatper的流程涉及到建立ims承載,在第二節中繼續分析。

以流程圖小結這部分: 
這里寫圖片描述


建立IMS PDN連接

在ims注冊之前,需要建立專用的數據連接。連接的建立由volte_imsm.so來觸發,與普通數據連接一樣,通過ConnectivityManager請求網絡,並由telephony發起SETUP_DATA_CALL。

先了解下volte_imsm.so的作用。根據readme文件的描述,volte_imsm.so庫用於建立承載,P-CSCF,鑒權等過程,MTK並沒有開源:

  1.  
    #README
  2.  
    IMS relay module, handling NAS bearer, P-CSCF address discovery, IMS AKA and relay message among IMCB/IMSA/MAL modules
  3.  
     
  4.  
    WHAT IT DOES?
  5.  
    =============
  6.  
    handle the request from IMCB/IMSA/MAL module
  7.  
    Send the event to IMCB/IMSA/MAL module, and receive the Response
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

ims app負責與volte_imsm.so對接,一張圖來表示相關的工作過程。 
這里寫圖片描述

VaSocketIO運作在線程中,負責維護socket和輸入輸出,循環從socket中讀取消息交由ImsEventDispatcher。 
ImsEventDispatcher根據消息的類型分發給對應的VaEventDispatcher處理。 
實現了VaEventDispatcher的類共有4個,分別負責:通話,數據,補充業務還有Timer(具體作用尚需研究)。 
ImsAdapter負責控制功能的總開關。

大概清楚這塊流程后,下面接着第一節的思路,繼續分析ImsAdapter:enableImsAdapter()方法。

  1.  
    ImsAdapter. java
  2.  
    public void enableImsAdapter() {
  3.  
    synchronized (ImsEnabledThreadLock) {
  4.  
    if (!misImsAdapterEnabled) {
  5.  
    if (mIO.connectSocket() == true) {
  6.  
    //調用所有VaEventDispatcher的enableRequest方法
  7.  
    mImsEventDispatcher.enableRequest();
  8.  
    misImsAdapterEnabled = true;
  9.  
    synchronized (mIO.VaSocketIOThreadLock) {
  10.  
    mIO.VaSocketIOThreadLock.notify();
  11.  
    }
  12.  
    //啟用ims棧(向volte_imsm下發一條消息)
  13.  
    enableImsStack();
  14.  
    } else {
  15.  
    sendMessageDelayed(
  16.  
    obtainMessage(MSG_IMSA_RETRY_IMS_ENABLE),
  17.  
    IMSA_RETRY_SOCKET_TIME);
  18.  
    }
  19.  
    }
  20.  
    }
  21.  
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

DataDispatcher負責建立承載相關處理,直接看DataDispatcher.enableRequest()方法的處理: 
注冊DATA_CONNECTION_STATE_CHANGED和SIM_STATE_CHANGED的監聽。監聽這2個消息是為了維護ims的連接,響應Data和SIM卡的變動。

  1.  
    DataDispatcher. java
  2.  
    public void enableRequest() {
  3.  
    synchronized (mHandler) {
  4.  
    Arrays.fill(mSimStatus, false);
  5.  
    IntentFilter filter = new IntentFilter();
  6.  
    filter.addAction(TelephonyManager.ACTION_PRECISE_DATA_CONNECTION_STATE_CHANGED);
  7.  
    filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
  8.  
    mContext.registerReceiver(mBroadcastReceiver, filter);
  9.  
    mIsEnable = true;
  10.  
    }
  11.  
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

返回到ImsAdapter繼續看enableImsStack()方法。從方法的命名上看,作用是啟用ims棧, 
向volte_imsm發送MSG_ID_IMS_ENABLE_IND消息:

  1.  
    private void enableImsStack() {
  2.  
    // Send IMS Enable to IMSM
  3.  
    VaEvent event = new VaEvent(Util.getDefaultVoltePhoneId(), MSG_ID_IMS_ENABLE_IND);
  4.  
    mIO.writeEvent( event);
  5.  
     
  6.  
    return;
  7.  
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

消息的定義如下:

  1.  
    int MSG_ID_IMS_ENABLE_IND = 900003; // MSG_ID_WRAP_IMSPA_IMSM_ENABLE_IND
  2.  
    int MSG_ID_IMS_DISABLE_IND = 900004; // MSG_ID_WRAP_IMSPA_IMSM_DISABLE_IND,
  • 1
  • 2

從Log看,MSG_ID_WRAP_IMSPA_IMSM_ENABLE_IND消息的作用應該是初始化volte_imsm相關模塊,VoLTE Stack/UA/REG等模塊被初始化: 
這里寫圖片描述

volte_imsm隨后會上報MSG_ID_WRAP_IMSM_IMSPA_PDN_ACT_REQ,通知上層發起IMS PDN連接,消息由DataDispatcher處理。 
這里寫圖片描述

消息分發到DataDispatcher::handleDefaultBearerActivationRequest方法: 
將請求數據封裝成TransactionParam,設置超時處理,最后調用requestNwRequest方法。這里能看到請求的apn類型是IMS。

  1.  
    DataDispatcher. java
  2.  
    private void handleDefaultBearerActivationRequest(VaEvent event) {
  3.  
    //apn type為IMS
  4.  
    String apnType = PhoneConstants.APN_TYPE_IMS;
  5.  
    int phoneId = event.getPhoneId();
  6.  
    //請求數據封裝成TransactionParam
  7.  
    DataDispatcherUtil.PdnActivationInd actInd = mDataDispatcherUtil
  8.  
    .extractDefaultPdnActInd( event);
  9.  
    TransactionParam param = new TransactionParam(actInd.transactionId,
  10.  
    event.getRequestID(), phoneId, apnType);
  11.  
    ...
  12.  
    putTransaction(param);
  13.  
    if (apnType == PhoneConstants.APN_TYPE_IMS) {
  14.  
    int subId = SubscriptionManager.getSubIdUsingPhoneId(phoneId);
  15.  
    if (mSimStatus[phoneId] || subId > 0) {
  16.  
    mSimStatus[phoneId] = true;
  17.  
    //判斷是否有合法的ims apn
  18.  
    if (!isImsApnExists(phoneId)) {
  19.  
    rejectDefaultBearerDataConnActivation(param, FAILCAUSE_UNKNOWN, 500);
  20.  
    return;
  21.  
    }
  22.  
    //設置超時,如果超過10秒沒有進入開始連接的狀態即觸發
  23.  
    mHandler.removeMessages(MSG_ON_NOTIFY_ACTIVE_DATA_TIMEOUT);
  24.  
    mHandler.sendMessageDelayed(mHandler.obtainMessage(
  25.  
    MSG_ON_NOTIFY_ACTIVE_DATA_TIMEOUT, param),
  26.  
    MAX_NETWORK_ACTIVE_TIMEOUT_MS);
  27.  
    } else {
  28.  
    return;
  29.  
    }
  30.  
    }
  31.  
    //發起IMS連接請求
  32.  
    if (requestNwRequest(apnType, phoneId) < 0) {
  33.  
    rejectDefaultBearerDataConnActivation(param, FAILCAUSE_UNKNOWN, 0);
  34.  
    }
  35.  
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

requestNwRequest方法實例化NetworkRequest並填充數據后,通過ConnectivityManager.requestNetwork發起連接請求。

  1.  
    private int requestNwRequest(String requestApnType, int phoneId) {
  2.  
    ...
  3.  
    NetworkCallback nwCb = mDataNetworkRequests[pos].nwCb;
  4.  
    Builder builder = new NetworkRequest.Builder();
  5.  
    //IMS & EIMS
  6.  
    builder.addCapability(APN_CAP_LIST[pos]);
  7.  
    builder.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
  8.  
    //指定為當前subId
  9.  
    builder.setNetworkSpecifier(String.valueOf(subId));
  10.  
    mDataNetworkRequests[pos].nwRequest = builder.build();
  11.  
    NetworkRequest nwRequest = mDataNetworkRequests[pos].nwRequest;
  12.  
    releaseNwRequest(requestApnType);
  13.  
    synchronized (mAPNStatuses) {
  14.  
    ApnStatus apnStatus = mAPNStatuses.get(requestApnType);
  15.  
    apnStatus.mName = requestApnType; //IMS
  16.  
    apnStatus.mStatus = TelephonyManager.DATA_DISCONNECTED;
  17.  
    apnStatus.isSendReq = true;
  18.  
    apnStatus.ifaceName = "";
  19.  
    //發起request
  20.  
    getConnectivityManager().requestNetwork(nwRequest, nwCb,
  21.  
    ConnectivityManager.MAX_NETWORK_REQUEST_TIMEOUT_MS);
  22.  
    }
  23.  
    ...
  24.  
     
  25.  
    return nRet;
  26.  
    }
  27.  
    private static final int[] APN_CAP_LIST = new int[] {
  28.  
    NetworkCapabilities.NET_CAPABILITY_IMS,
  29.  
    NetworkCapabilities.NET_CAPABILITY_EIMS
  30.  
    };
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

接下來SETUP_DATA_CALL的工作由ConnectivityService和telephony數據模塊完成。返回成功后,檢查手機的網絡接口發現新建了一個Interface——ccmni4

  1.  
    root @x6:/ # ifconfig
  2.  
    lo Link encap:Local Loopback
  3.  
    inet addr:127.0.0.1 Mask:255.0.0.0
  4.  
    inet6 addr: ::1/128 Scope: Host
  5.  
    UP LOOPBACK RUNNING MTU:65536 Metric:1
  6.  
    RX packets:46 errors:0 dropped:0 overruns:0 frame:0
  7.  
    TX packets:46 errors:0 dropped:0 overruns:0 carrier:0
  8.  
    collisions:0 txqueuelen:0
  9.  
    RX bytes:3992 TX bytes:3992
  10.  
     
  11.  
    ccmni4 Link encap:Ethernet HWaddr 12:7A:92:06:07:BE
  12.  
    inet6 addr: 2409:8809:8590:da21:279:6506:7e0d:afdc/64 Scope: Global
  13.  
    inet6 addr: fe80::279:6506:7e0d:afdc/64 Scope: Link
  14.  
    UP RUNNING NOARP MTU:1410 Metric:1
  15.  
    RX packets:26 errors:0 dropped:0 overruns:0 frame:0
  16.  
    TX packets:29 errors:0 dropped:0 overruns:0 carrier:0
  17.  
    collisions:0 txqueuelen:1000
  18.  
    RX bytes:17494 TX bytes:18434
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

ccmni4是mtk在底層指定的ims默認承載接口的名稱,連接建立后DataDispatcher還需要檢查這個Interface的名字是否正確,最后發送ACT消息通知volte_imsm連接已經建立

  1.  
    //DataDispatcher.java
  2.  
    private static final String IMS_INTERFACE_NAME = "ccmni4";
  3.  
     
  4.  
    private void handleDefaultBearerActivationResponse(Network network, String type) {
  5.  
     
  6.  
    TransactionParam deacTrans = findTransaction
  7.  
    (VaConstants.MSG_ID_WRAP_IMSM_IMSPA_PDN_DEACT_REQ, type);
  8.  
    synchronized (mAPNStatuses) {
  9.  
    ApnStatus apnStatus = mAPNStatuses. get(type);
  10.  
    if (deacTrans == null) {
  11.  
    apnStatus.mStatus = TelephonyManager.DATA_CONNECTED;
  12.  
    ConnectivityManager cm = (ConnectivityManager) mContext
  13.  
    .getSystemService(Context.CONNECTIVITY_SERVICE);
  14.  
    LinkProperties mLink = cm.getLinkProperties(network);
  15.  
    ...
  16.  
    apnStatus.ifaceName = mLink.getInterfaceName();
  17.  
    //檢查iface名字是否為"ccmni4"
  18.  
    if (IMS_INTERFACE_NAME.equals(apnStatus.ifaceName)
  19.  
    || EMERGENCY_INTERFACE_NAME. equals(apnStatus.ifaceName)) {
  20.  
    //發送MSG_ID_WRAP_IMSM_IMSPA_PDN_ACT_REQ通知volte_imsm
  21.  
    responseDefaultBearerDataConnActivated(
  22.  
    findTransaction(VaConstants.MSG_ID_WRAP_IMSM_IMSPA_PDN_ACT_REQ, type),
  23.  
    network.netId, apnStatus.ifaceName);
  24.  
    }
  25.  
    ...
  26.  
    }
  27.  
    ...
  28.  
    }
  29.  
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

這里寫圖片描述

這部分的代碼量較多,理解了設計意圖后其實結構和流程都比較簡單,同樣以流程圖總結: 
這里寫圖片描述


注冊IMS服務

完成注冊

IMS注冊基於SIP,這部分由ims核心模塊處理,需要分析協議和模塊設計,這里先不作深入探討。 
轉載自網絡

注冊成功后,返回200 OK。 
這里寫圖片描述

rild_ims將注冊狀態及capability通過RIL_UNSOL_IMS_REGISTRATION_INFO消息上報: 
這里寫圖片描述 
ImsService在構造方法中注冊過對RIL_UNSOL_IMS_REGISTRATION_INFO的監聽,因此處理方法就在ImsService的handler中能找到。

 mImsRILAdapter.registerForImsRegistrationInfo(mHandler, EVENT_IMS_REGISTRATION_INFO, null);
  • 1

ImsService 處理: 
從EVENT_IMS_REGISTRATION_INFO中讀取到ims注冊狀態和Capability,並通知監聽者。

  1.  
    //ImsService.java
  2.  
    //IMS所支持的capability
  3.  
    private static final int IMS_VOICE_OVER_LTE = 1;
  4.  
    private static final int IMS_RCS_OVER_LTE = 2;
  5.  
    private static final int IMS_SMS_OVER_LTE = 4;
  6.  
    private static final int IMS_VIDEO_OVER_LTE = 8;
  7.  
    private static final int IMS_VOICE_OVER_WIFI = 16;
  8.  
     
  9.  
    public void handleMessage(Message msg) {
  10.  
    AsyncResult ar;
  11.  
    Intent intent;
  12.  
    int phoneId = getMainCapabilityPhoneId();
  13.  
    switch (msg.what) {
  14.  
    case EVENT_IMS_REGISTRATION_INFO:
  15.  
    ar = (AsyncResult) msg.obj;
  16.  
    //根據協議的規定,CIREGU返回消息的第一字段表示注冊狀態,第二個表示capability
  17.  
    /**
  18.  
    * According to 3GPP TS 27.007 +CIREGU format
  19.  
    *
  20.  
    * AsyncResult.result is an Object[]
  21.  
    * ((Object[])AsyncResult.result)[0] is integer type to indicate the IMS regiration status.
  22.  
    * 0: not registered
  23.  
    * 1: registered
  24.  
    * ((Object[])AsyncResult.result)[1] is numeric value in hexadecimal format to indicate the IMS capability.
  25.  
    * 1: RTP-based transfer of voice according to MMTEL (see 3GPP TS 24.173 [87])
  26.  
    * 2: RTP-based transfer of text according to MMTEL (see 3GPP TS 24.173 [87])
  27.  
    * 4: SMS using IMS functionality (see 3GPP TS 24.341[101])
  28.  
    * 8: RTP-based transfer of video according to MMTEL (see 3GPP TS 24.183 [87])
  29.  
    *
  30.  
    */
  31.  
     
  32.  
    //對比socketId是否當前的active phoneId
  33.  
    int socketId = ((int[]) ar.result)[2];
  34.  
    if (socketId != mActivePhoneId) {
  35.  
    break;
  36.  
    }
  37.  
     
  38.  
    int newImsRegInfo = ServiceState.STATE_POWER_OFF;
  39.  
    //讀取Ims的注冊狀態
  40.  
    if (((int[]) ar.result)[0] == 1) {
  41.  
    newImsRegInfo = ServiceState.STATE_IN_SERVICE;
  42.  
    } else {
  43.  
    newImsRegInfo = ServiceState.STATE_OUT_OF_SERVICE;
  44.  
    }
  45.  
    //讀取當前支持的capability
  46.  
    int newImsExtInfo = ((int[]) ar.result)[1];
  47.  
    mImsRegInfo = newImsRegInfo;
  48.  
     
  49.  
    //通知ims注冊狀態更新
  50.  
    notifyRegistrationStateChange(mImsRegInfo);
  51.  
     
  52.  
    if ((mImsRegInfo == ServiceState.STATE_IN_SERVICE)) {
  53.  
    mImsExtInfo = newImsExtInfo;
  54.  
    } else {
  55.  
    mImsExtInfo = 0;
  56.  
    }
  57.  
    //通知ims capability更新
  58.  
    notifyRegistrationCapabilityChange(mImsExtInfo);
  59.  
    break;
  60.  
    ...
  61.  
    }
  62.  
    ...
  63.  
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63

從LOG來看,此次CIREGU指令返回的結果是“1,5”,按照定義,1表示已注冊,5代表同時支持IMS_VOICE_OVER_LTE和IMS_SMS_OVER_LTE,即語音和短信業務。

AT< +CIREGU: 1,5
  • 1

注冊狀態的同步

ImsManager獲得注冊狀態和capability后,回調ImsPhoneCallTracker中實例化的ImsConnectionStateListener,數據最終將傳遞到ImsPhone。 
ImsPhone中有ServiceState實例來標記data和ims voice服務狀態,並有布爾值mImsRegistered來標記ims注冊情況。

  1.  
    //ImsManager.java
  2.  
    private class ImsRegistrationListenerProxy extends IImsRegistrationListener.Stub {
  3.  
    private int mServiceClass;
  4.  
    private ImsConnectionStateListener mListener;
  5.  
     
  6.  
    public ImsRegistrationListenerProxy(int serviceClass,
  7.  
    ImsConnectionStateListener listener) {
  8.  
    mServiceClass = serviceClass;
  9.  
    mListener = listener;
  10.  
    }
  11.  
     
  12.  
    ...
  13.  
     
  14.  
    @Override
  15.  
    public void registrationConnected() {
  16.  
    if (mListener != null) {
  17.  
    mListener.onImsConnected();
  18.  
    }
  19.  
    }
  20.  
     
  21.  
    @Override
  22.  
    public void registrationProgressing() {
  23.  
    if (mListener != null) {
  24.  
    mListener.onImsProgressing();
  25.  
    }
  26.  
    }
  27.  
     
  28.  
    @Override
  29.  
    public void registrationDisconnected(ImsReasonInfo imsReasonInfo) {
  30.  
    if (mListener != null) {
  31.  
    mListener.onImsDisconnected(imsReasonInfo);
  32.  
    }
  33.  
    }
  34.  
     
  35.  
    @Override
  36.  
    public void registrationResumed() {
  37.  
    if (mListener != null) {
  38.  
    mListener.onImsResumed();
  39.  
    }
  40.  
    }
  41.  
     
  42.  
    @Override
  43.  
    public void registrationSuspended() {
  44.  
    if (mListener != null) {
  45.  
    mListener.onImsSuspended();
  46.  
    }
  47.  
    }
  48.  
     
  49.  
    @Override
  50.  
    public void registrationFeatureCapabilityChanged(int serviceClass,
  51.  
    int[] enabledFeatures, int[] disabledFeatures) {
  52.  
    if (mListener != null) {
  53.  
    mListener.onFeatureCapabilityChanged(serviceClass,
  54.  
    enabledFeatures, disabledFeatures);
  55.  
    }
  56.  
    }
  57.  
     
  58.  
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58

ImsPhoneCallTracker如何處理注冊信息和capability的上報: 
1. 注冊狀態同步到ImsPhone; 
2. Capability同步到mImsFeatureEnabled數組中,標記可用的ims業務; 
3. 最后發出ACTION_IMS_STATE_CHANGED廣播。

  1.  
    ImsPhoneCallTracker.java
  2.  
    /**
  3.  
    * Listen to the IMS service state change
  4.  
    *
  5.  
    */
  6.  
    private ImsConnectionStateListener mImsConnectionStateListener =
  7.  
    new ImsConnectionStateListener() {
  8.  
    @Override
  9.  
    public void onImsConnected() {
  10.  
    mPhone.setServiceState(ServiceState.STATE_IN_SERVICE);
  11.  
    mPhone.setImsRegistered( true);
  12.  
    }
  13.  
     
  14.  
    @Override
  15.  
    public void onImsDisconnected(ImsReasonInfo imsReasonInfo) {
  16.  
    mPhone.setServiceState(ServiceState.STATE_OUT_OF_SERVICE);
  17.  
    mPhone.setImsRegistered( false);
  18.  
    mPhone.processDisconnectReason(imsReasonInfo);
  19.  
    if (imsReasonInfo != null && imsReasonInfo.getExtraMessage() != null
  20.  
    && !imsReasonInfo.getExtraMessage().equals( "")) {
  21.  
    mImsRegistrationErrorCode = Integer.parseInt(imsReasonInfo.getExtraMessage());
  22.  
    }
  23.  
    }
  24.  
     
  25.  
    @Override
  26.  
    public void onImsProgressing() {
  27.  
    }
  28.  
     
  29.  
    @Override
  30.  
    public void onImsResumed() {
  31.  
    mPhone.setServiceState(ServiceState.STATE_IN_SERVICE);
  32.  
    }
  33.  
     
  34.  
    @Override
  35.  
    public void onImsSuspended() {
  36.  
    mPhone.setServiceState(ServiceState.STATE_OUT_OF_SERVICE);
  37.  
    }
  38.  
     
  39.  
    @Override
  40.  
    public void onFeatureCapabilityChanged(int serviceClass,
  41.  
    int[] enabledFeatures, int[] disabledFeatures) {
  42.  
    if (serviceClass == ImsServiceClass.MMTEL) {
  43.  
    boolean tmpIsVideoCallEnabled = isVideoCallEnabled();
  44.  
    // Check enabledFeatures to determine capabilities. We ignore disabledFeatures.
  45.  
    for (int i = ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_LTE;
  46.  
    i <= ImsConfig.FeatureConstants.FEATURE_TYPE_VIDEO_OVER_WIFI; i++) {
  47.  
    if (enabledFeatures[i] == i) {
  48.  
    mImsFeatureEnabled[i] = true;
  49.  
    } else if (enabledFeatures[i]
  50.  
    == ImsConfig.FeatureConstants.FEATURE_TYPE_UNKNOWN) {
  51.  
    mImsFeatureEnabled[i] = false;
  52.  
    } else {
  53.  
    }
  54.  
    }
  55.  
    if (tmpIsVideoCallEnabled != isVideoCallEnabled()) {
  56.  
    mPhone.notifyForVideoCapabilityChanged(isVideoCallEnabled());
  57.  
    }
  58.  
     
  59.  
    for (ImsPhoneConnection connection : mConnections) {
  60.  
    connection.updateWifiState();
  61.  
    }
  62.  
     
  63.  
    mPhone.onFeatureCapabilityChanged();
  64.  
    broadcastImsStatusChange();
  65.  
    }
  66.  
    }
  67.  
    };
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67

ImsPhone更新ServiceState的Log:

  1.  
    06-02 16:47:44.925 D/ImsPhone( 2170): updateDataServiceState:
  2.  
    defSs = 0 0 voice home data home 中國移動 中國移動 46000 中國移動 中國移動 46000 LTE LTE_CA CSS not supported 0 0 RoamInd=-1 DefRoamInd=-1 EmergOnly=false Ril Voice Regist state: 1 Ril Data Regist state: 1 mProprietaryDataRadioTechnology: 0 VoiceRejectCause: 0 DataRejectCause: -1 IsDataRoamingFromRegistration=false
  3.  
    //imsServiceState
  4.  
    imsSs = 0 0 voice home data home null null null null null null Unknown LTE_CA CSS not supported -1 -1 RoamInd=-1 DefRoamInd=-1 EmergOnly=false Ril Voice Regist state: 0 Ril Data Regist state: 0 mProprietaryDataRadioTechnology: 0 VoiceRejectCause: -1 DataRejectCause: -1 IsDataRoamingFromRegistration=false
  • 1
  • 2
  • 3
  • 4

小結

以上分析只分析了AP側流程,相對於完整的ims注冊過程來說並不完整,核心部分的協議及信令流程許多對上層來說是透明的,需要對這些部分深入了解后再做補充。

 
版權聲明:本文為meiliqiang原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。
本文鏈接: https://blog.csdn.net/meiliqiang/article/details/78501947


免責聲明!

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



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