1. 程式人生 > >IMS的註冊流程分析

IMS的註冊流程分析

本次的IMS註冊流程分析基於MT6580_O平臺。關於IMS的相關流程,MTK釋放的文件講得已經蠻詳細了,本次記錄的內容純屬在文件的基礎上加上自己的理解,以便日後的複習,僅供參考。
IMS的整體框架圖如下:
這裡寫圖片描述

其中MAL層以so庫檔案的形式存在,程式碼不對外開放。
ImsService.java在framework中是比較核心的類,IMS的多數功能都依賴於ImsService展開,其作用是:
Create ImsRILAdapter which to communicate with RJILD
Create ImsAdapter which to communicate with IMSM
Provide turn on/off Ims interface to ImsManager and ImsSwitchController to enable/disable IMS
Listen Registration information and notify ImsManager to broadcast to the receivers.
Listen incoming call indicator to create ImsCallsessionProxy to handle incoming call.

MTK的IMS設計中,能接觸到的部分,主要分為兩個方面:
一. 開關的控制
二. IMS的註冊過程

一.開關的控制

這裡的開關有兩個,一個是settings下的”增強型4G LTE模式”選項,這個是使用者能接觸到的VOLTE的開關。一個是radio的開關。它們的時序圖如下:
這裡寫圖片描述

這個”增強型4G LTE模式”,控制著是否啟用ims的哪些功能,主要有volte,vilte,wfc等等,具體看程式碼中的實現:

ImsManager.java

    public void setAdvanced4GMode(boolean turnOn) throws ImsException {
        checkAndThrowExceptionIfServiceUnavailable();

        // if turnOn: first set feature values then call turnOnIms()
// if turnOff: only set feature values if IMS turn off is not allowed. If turn off is // allowed, first call turnOffIms() then set feature values if (turnOn) { setLteFeatureValues(turnOn); log("setAdvanced4GMode: turnOnIms"); turnOnIms(); } else
{ if (isImsTurnOffAllowed()) { log("setAdvanced4GMode: turnOffIms"); turnOffIms(); } setLteFeatureValues(turnOn); } } protected void setLteFeatureValues(boolean turnOn) { log("setLteFeatureValues: " + turnOn); try { ImsConfig config = getConfigInterface(); if (config != null) { config.setFeatureValue(ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_LTE, TelephonyManager.NETWORK_TYPE_LTE, turnOn ? 1 : 0, mImsConfigListener); if (isVolteEnabledByPlatformForSlot()) { boolean ignoreDataEnabledChanged = getBooleanCarrierConfig(mContext, CarrierConfigManager.KEY_IGNORE_DATA_ENABLED_CHANGED_FOR_VIDEO_CALLS); boolean enableViLte = turnOn && isVtEnabledByUserForSlot() && (ignoreDataEnabledChanged || isDataEnabled()); config.setFeatureValue(ImsConfig.FeatureConstants.FEATURE_TYPE_VIDEO_OVER_LTE, TelephonyManager.NETWORK_TYPE_LTE, enableViLte ? 1 : 0, mImsConfigListener); } } } catch (ImsException e) { loge("setLteFeatureValues: exception ", e); } }

ims開啟的功能用feature,network,value,phoneId等引數值來表示,除了保持在SystemProperties中,還儲存在了資料庫imsconfig.db 中的tb_feature 表中,並對資料庫進行了監聽,如果資料庫有更新,發出一個廣播(ImsConfigContract.ACTION_IMS_FEATURE_CHANGED)通知資料庫的變化:
這裡寫圖片描述
ImsConfigStorage.java

        private void updateFeature(int featureId, int network, int value) {
            int curValue = -1;
            boolean result = false;
            ContentValues cv = new ContentValues();
            cv.put(ImsConfigContract.Feature.PHONE_ID, mPhoneId);
            cv.put(ImsConfigContract.Feature.FEATURE_ID, featureId);
            cv.put(ImsConfigContract.Feature.NETWORK_ID, network);
            cv.put(ImsConfigContract.Feature.VALUE, value);

            // Check exist or not
            try {
                curValue = getFeatureValue(featureId, network);
                if (DEBUG) Log.d(TAG, "updateFeature() comparing: curValue: " +
                        curValue + ", value:" + value);
                if (!checkIfBroadcastOnce(featureId, mPhoneId) || curValue != value || curValue == -1) {
                    mContentResolver.update(
                            ImsConfigContract.Feature.getUriWithFeatureId(mPhoneId, featureId, network),
                            cv, null, null);
                }
            } catch (ImsException e) {
                Log.e(TAG, "updateFeature() ImsException featureId:" + featureId +", value:" + value);
                mContentResolver.insert(ImsConfigContract.Feature.CONTENT_URI, cv);
            }
        }

ImsConfigProvider.java

    @Override
    public int update(Uri uri, ContentValues values, String selection,
                      String[] selectionArgs) {
        int count = 0;
        Arguments args = new Arguments(
                OperationMode.MODE_UPDATE, uri, values, selection, selectionArgs);

        try {
            SQLiteDatabase db = mDatabaseHelper.getWritableDatabase();
            count = db.update(args.table, values, args.selection, args.selectionArgs);
            if (count > 0) {
                notifyChange(uri, args, values);
            }
        } catch (SQLiteFullException e) {
            onDiskFull(e);
        }
        return count;
    }
    private void notifyChange(Uri uri, Arguments args, ContentValues cv) {
        //final long oldId = Binder.clearCallingIdentity();
        try {
            int itemId, mimeType;
            String simState;
            int value = -1;
            boolean isECCBroadcastFlag = false;
            boolean isFeatureEnabled = false;
            boolean isSimStateAllow = false;
            String valueStr = "";
            Intent intent;

            switch (args.table) {
            ......
                case ImsConfigContract.TABLE_FEATURE:
                    simState = LatestSimState.get(Integer.parseInt(args.phoneId));
                    Log.d(TAG, "getSimState() for checking whether broadcast phoneId: " +
                            Integer.parseInt(args.phoneId) + ", Sim state: " + simState);

                    itemId = Integer.parseInt(args.itemId);
                    value = cv.getAsInteger(ImsConfigContract.Feature.VALUE);

                    if (simState == null) {
                        simState = "";
                    }

                    // ECCAllowBroadcast: The flag is used to allow broadcast for PS ECC
                    // when sim is absent and the calculated platform support of VoLTE is true
                    if (ECCAllowBroadcast.get(Integer.parseInt(args.phoneId)) == null) {
                        isECCBroadcastFlag = false;
                    } else {
                        isECCBroadcastFlag = (simState.equals(IccCardConstants.INTENT_VALUE_ICC_ABSENT) &&
                                ECCAllowBroadcast.get(Integer.parseInt(args.phoneId)) &&
                                itemId == ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_LTE);
                        isFeatureEnabled = (value == ImsConfig.FeatureValueConstants.ON);
                        if (isECCBroadcastFlag && !isFeatureEnabled) {
                            ECCAllowBroadcast.put(Integer.parseInt(args.phoneId), false);
                            Log.d(TAG, "Sim absent but the calculated VoLTE is false," +
                                    " so no need broadcast");
                        }
                    }

                    /// M: Sync volte setting value. @{
                    boolean isForceNotify =
                            (itemId == ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_LTE) &&
                            (SystemProperties.getInt(PROPERTY_IMSCONFIG_FORCE_NOTIFY, 0) == 1);
                    Log.d(TAG, "isForceNotify " + isForceNotify);
                    /// @}

                    // Check SIM state
                    if (simState.equals(IccCardConstants.INTENT_VALUE_ICC_READY) ||
                          simState.equals(IccCardConstants.INTENT_VALUE_ICC_IMSI) ||
                          simState.equals(IccCardConstants.INTENT_VALUE_ICC_LOADED)) {
                        isSimStateAllow = true;
                    } else {
                        isSimStateAllow = false;
                    }

                    if (isSimStateAllow || (isECCBroadcastFlag && isFeatureEnabled) ||
                            isForceNotify) {
                        // For observers who don't have dedicated process, use broadcast mechanism.
                        intent = new Intent(ImsConfigContract.ACTION_IMS_FEATURE_CHANGED, uri);
                        intent.putExtra(ImsConfigContract.EXTRA_PHONE_ID, Integer.parseInt(args.phoneId));
                        intent.putExtra(ImsConfigContract.EXTRA_CHANGED_ITEM, itemId);
                        intent.putExtra(ImsConfigContract.EXTRA_NEW_VALUE, value); // need to modify
                        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
                        getContext().sendBroadcast(intent);
                        // Notify content observers
                        getContext().getContentResolver().notifyChange(uri, null);

                        ECCAllowBroadcast.put(Integer.parseInt(args.phoneId), false);
                        Log.d(TAG, "Update uri " + uri + " on phone " + args.phoneId + " value: " + value);
                    }
                    break;
                    ......                                                    

ImsConfigContract.ACTION_IMS_FEATURE_CHANGED 廣播最後被WifiOffloadService接收,並從資料庫中查詢當前IMS所支援的功能的最新狀態,並將結果返回給回撥函式onGetFeatureResponse()
WifiOffloadService.java

    private BroadcastReceiver mFeatureValueReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent == null || intent.getAction() == null) {
                return;
            }

            if (intent.getAction().equals(ImsConfig.ACTION_IMS_FEATURE_CHANGED)) {
                int feature = intent.getIntExtra(ImsConfig.EXTRA_CHANGED_ITEM, -1);
                int phoneId = intent.getIntExtra(EXTRA_PHONE_ID, -1);
                Log.d(TAG,
                    "onRecevied IMS feature changed phoneId: " + phoneId + ", feature: " + feature);

                if (checkInvalidSimIdx(phoneId, "ignore it for invalid SIM id")) return;
                if (checkNullObject(mCfgListeners[phoneId], "no CfgListener")) return;

                ImsManager imsMgr = ImsManager.getInstance(mContext, phoneId);
                if (checkNullObject(imsMgr, "can't get ImsManager")) return;

                try {
                    ImsConfig imsCfg = imsMgr.getConfigInterface();
                    if (checkNullObject(imsCfg, "can't get ImsConfig")) return;

                    imsCfg. (
                            feature, getNetworkTypeByFeature(feature), mCfgListeners[phoneId]);
                } catch (ImsException e) {
                    Log.e(TAG, "getFeatureValue has exception: " + e);
                    return;
                }
            }
        }
    };            
        @Override
        public void onGetFeatureResponse(int feature, int network, int value, int status) {
            if (status == ImsConfig.OperationStatusConstants.FAILED) {
                Log.d(TAG, "onGetFeatureResponse: get feature failed:" + feature);
                return;
            }
            Log.d(TAG, "onGetFeatureResponse: sim=" + mPhoneId + ", feature=" + feature
                    + ", value=" + value);
            fetchFeatureValue(feature, value);
            notifyMalUserProfile(mPhoneId);
        }        

然後通過jni 函式nativeSetWosProfile 向MAL 設定IMS feature 引數,由MAL 決定turn on/off IMS,通過函式onRequestImsSwitch() 向WifiOffloadService 返回,WifiOffloadService 通過此方法通知了所有註冊監聽它的類,比如ImsService。所以最後在ImsService的onRequestImsSwitch()方法中對turnOnIms\turnOffIms方法對RIL發起開關ims功能的動作。如下:

    protected void onRequestImsSwitch(int simIdx, boolean isImsOn) {
        Message msg = mHandler.obtainMessage(EVENT_ON_REQUEST_IMS_SWITCH, simIdx, (isImsOn)? 1: 0);
        mHandler.sendMessage(msg);
    }
    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            Log.d(TAG, "handleMessage: " + messageToString(msg) + " = " + msg);
            switch (msg.what) {
            ......
                case EVENT_ON_REQUEST_IMS_SWITCH:
                    int simIdx = msg.arg1;
                    boolean isImsOn = msg.arg2 == 1;
                    notifyOnRequestImsSwitch(simIdx, isImsOn);
                    break;           
                    ......
             }
         }
     }
    private void notifyOnRequestImsSwitch(int simIdx, boolean isImsOn) {
        Log.d(TAG, "onRequestImsSwitch simIdx: " + simIdx + ", isImsOn: " + isImsOn);

        int i = mListeners.beginBroadcast();
        while (i > 0) {
            i--;
            try {
                mListeners.getBroadcastItem(i).onRequestImsSwitch(simIdx, isImsOn);
            } catch (RemoteException e) {
                // The RemoteCallbackList will take care of removing
                // the dead object for us.
                Log.e(TAG, "onRequestImsSwitch: RemoteException occurs!");
            }
        }
        mListeners.finishBroadcast();
    }     

ImsService.java

        @Override
        public void onRequestImsSwitch(int simIdx, boolean isImsOn) {
            if (ImsCommonUtil.supportMdAutoSetupIms()) {
                return;
            }
            int mainCapabilityPhoneId = ImsCommonUtil.getMainCapabilityPhoneId();
            log("onRequestImsSwitch simIdx=" + simIdx +
                    " isImsOn=" + isImsOn + " mainCapabilityPhoneId=" + mainCapabilityPhoneId);

            if (simIdx >= mNumOfPhones) {
                loge("onRequestImsSwitch can't enable/disable ims due to wrong sim id");
            }
            if (ImsCommonUtil.supportMims() == false) {
                if (simIdx != mainCapabilityPhoneId) {
                    logw("onRequestImsSwitch, ignore not MainCapabilityPhoneId request");
                    return;
                }
            }            
            if (isImsOn) {
                if (mImsState[simIdx] != MtkPhoneConstants.IMS_STATE_ENABLE
                    || mExpectedImsState[simIdx] == MtkPhoneConstants.IMS_STATE_DISABLED) {
                    mImsRILAdapters[simIdx].turnOnIms(
                            mHandler[simIdx].obtainMessage(EVENT_SET_IMS_ENABLED_DONE));
                    mExpectedImsState[simIdx] = MtkPhoneConstants.IMS_STATE_ENABLE;
                    mImsState[simIdx] = MtkPhoneConstants.IMS_STATE_ENABLING;
                } else {
                    log("Ims already enable and ignore to send AT command.");
                }
            } else {
                if (mImsState[simIdx] != MtkPhoneConstants.IMS_STATE_DISABLED
                    || mExpectedImsState[simIdx] == MtkPhoneConstants.IMS_STATE_ENABLE) {
                    mImsRILAdapters[simIdx].turnOffIms(
                            mHandler[simIdx].obtainMessage(EVENT_SET_IMS_DISABLE_DONE));
                    mExpectedImsState[simIdx] = MtkPhoneConstants.IMS_STATE_DISABLED;
                    mImsState[simIdx] = MtkPhoneConstants.IMS_STATE_DISABLING;
                } else {
                    log("Ims already disabled and ignore to send AT command.");
                }
            }
        }
    }            

如果RIL處理完開關ims的操作後,會給ImsService發一個攜帶EVENT_SET_IMS_ENABLED_DONE,EVENT_SET_IMS_DISABLE_DONE的訊息,在ImsService中,並沒有對這兩個訊息做特殊的處理。僅僅是一些列印。

同理,Radio開關的流程大致上也跟”增強型4G LTE模式開關”差不多,只是在MAL中的處理可能有些差異。

DEBUG:

1. Enable Volte
D/ImsConfigImpl( 3729): setFeatureValue(0, 13, 1) on phone 1 from pid 3721, uid 1001, listener null
//update database
D/ImsConfigProvider( 3729): Update uri content://com.mediatek.ims.config.provider/tb_feature/1/0/13 on phone 1 value: 1
//notify Mal user profile
D/WifiOffloadService( 3760): notifyMalUserProfile simId: 1 mIsVolteEnabled: true, mIsVilteEnabled: false mIsWfcEnabled: false
mFqdn: mIsWifiEnabled: true mHasWiFiDisabledPending: false mWfcMode: 3 mDataRoamingEnabled: 0 mIsAllowTurnOffIms: true
D/WifiOffloadService( 3760): onRequestImsSwitch simIdx: 1 isImsOn: true
//send AT
I/AT ( 1062): AT> AT+EIMSVOICE=1 (RIL_CMD2_READER_3, tid:529387332688)
I/AT ( 1062): AT> AT+EIMSVOLTE=1 (RIL_CMD2_READER_3, tid:529387332688)
I/AT ( 1062): AT> AT+EIMS=1 (RIL_CMD2_READER_3, tid:529387332688)

2. Enable Vilte
D/ImsConfigImpl( 3729): setFeatureValue(1, 13, 1) on phone 1 from pid 3721, uid 1001, listener null
//update database
D/ImsConfigProvider( 3729): Update uri content://com.mediatek.ims.config.provider/tb_feature/1/1/13 on phone 1 value: 1
//notify Mal user profile
D/WifiOffloadService( 3760): notifyMalUserProfile simId: 1 mIsVolteEnabled: true, mIsVilteEnabled: true mIsWfcEnabled: false
mFqdn: mIsWifiEnabled: true mHasWiFiDisabledPending: false mWfcMode: 3 mDataRoamingEnabled: 0 mIsAllowTurnOffIms: true
//send At
I/AT ( 1062): AT> AT+EIMSCCP=1 (RIL_CMD2_READER_3, tid:529387332688)

二. IMS的註冊過程

IMS的註冊過程有兩個,一個是ims pdn連線的建立,一個是sip的註冊。

IMS的開關設定完後,會根據相應的狀態發起IMS的註冊過程。
這裡寫圖片描述

ImsService中註冊監聽了很多內容,比如:

    public ImsService(Context context) {
        log("init");
        mContext = context;
        /// Get Number of Phones
        mNumOfPhones = TelephonyManager.getDefault().getPhoneCount();
        /// M: keep old logic for 92gen and before
        if (ImsCommonUtil.supportMdAutoSetupIms() == false) {
            mImsAdapter = new ImsAdapter(context);
        }

        mHandler = new MyHandler[mNumOfPhones];
        mImsRILAdapters = new ImsCommandsInterface[mNumOfPhones];
        for(int i = 0; i < mNumOfPhones; i++) {
            mHandler[i] = new MyHandler(i);
            ImsRILAdapter ril = new ImsRILAdapter(context, i);

            /// register for radio state changed
            ril.registerForNotAvailable(mHandler[i], EVENT_RADIO_NOT_AVAILABLE, null);
            ril.registerForOff(mHandler[i], EVENT_RADIO_OFF, null);
            ril.registerForOn(mHandler[i], EVENT_RADIO_ON, null);

            ril.registerForImsRegistrationInfo(mHandler[i], EVENT_IMS_REGISTRATION_INFO, null);
            ril.registerForImsEnableStart(mHandler[i], EVENT_IMS_ENABLING_URC, null);
            ril.registerForImsEnableComplete(mHandler[i], EVENT_IMS_ENABLED_URC, null);
            ril.registerForImsDisableStart(mHandler[i], EVENT_IMS_DISABLING_URC, null);
            ril.registerForImsDisableComplete(mHandler[i], EVENT_IMS_DISABLED_URC, null);
            ril.setOnIncomingCallIndication(mHandler[i], EVENT_INCOMING_CALL_INDICATION, null);
            ril.registerForCallProgressIndicator(mHandler[i], EVENT_SIP_CODE_INDICATION, null);
            ril.registerForImsDeregisterComplete(mHandler[i], EVENT_IMS_DEREG_URC, null);
            ril.registerForMultiImsCount(mHandler[i], EVENT_MULTI_IMS_COUNT_URC, null);
            /// M: Listen for network initiated USSI @{
            ril.setOnNetworkInitUSSI(mHandler[i], EVENT_ON_NETWORK_INIT_USSI, null);
            /// @}
            /// M: register for IMS RTP report event @{
            ril.registerForImsRTPInfo(mHandler[i], EVENT_IMS_RTP_INFO_URC, null);
            /// @}
            /// M: Sync volte setting value. @{
            ril.registerForVolteSettingChanged(mHandler[i], EVENT_IMS_VOLTE_SETTING_URC, null);
            /// @}
            mImsRILAdapters[i] = ril;
        }            

比較重要的狀態有,ims開關相關的EVENT_IMS_ENABLING_URC,ims註冊狀態相關的EVENT_IMS_REGISTRATION_INFO,ims通話相關EVENT_INCOMING_CALL_INDICATION等等。
在上面已經說過的ims開關的設定,ImsService會向RIL發起turn on/off ims開關的操作。而RIL開關ims操作後返回的EVENT_SET_IMS_ENABLED_DONE訊息中,並沒有明顯的後續處理。是因為ImsService對開關ims狀態的處理放在了EVENT_IMS_ENABLING_URC中。如時序圖所示,EVENT_IMS_ENABLING_URC的訊息處理主要有三個部分:
1.通知MAL處理
2.在DataDispatcher中註冊廣播
3.發廣播通知資料庫更新

以上,通知MAL處理的具體實現我們看不到,省略不提。在DataDispatcher中註冊廣播,這個廣播的處理是:如果當前的資料連線狀態變更,且攜帶failure資訊,則通知MAL。

        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();

            if (action.equalsIgnoreCase(
                    TelephonyManager.ACTION_PRECISE_DATA_CONNECTION_STATE_CHANGED)) {
                String type = intent.getStringExtra(PhoneConstants.DATA_APN_TYPE_KEY);
                String failure = intent.getStringExtra(PhoneConstants.DATA_FAILURE_CAUSE_KEY);
                if (failure != null && failure.length() > 0) {
                    logd("onReceive, intent action is " + intent.getAction());
                    logd("APN: " + type + " failCause: " + failure);
                    switch(type) {
                        case PhoneConstants.APN_TYPE_IMS:
                            Handler imsHandle = mImsConnection.getHandler();
                            imsHandle.sendMessage(
                                imsHandle.obtainMessage(MSG_ID_WRAP_IMSM_IMSPA_PDN_ACT_FAIL, failure));
                            break;
                        case PhoneConstants.APN_TYPE_EMERGENCY:
                            Handler emcHandle = mEmcConnection.getHandler();
                            emcHandle.sendMessage(
                                emcHandle.obtainMessage(MSG_ID_WRAP_IMSM_IMSPA_PDN_ACT_FAIL, failure));
                            break;
                        default:
                            loge("UnKnown APN: " + type);
                            break;
                    }
                }
            }
        }                

從時序圖中,我們可以看到,ims開關設定後,ims主動發起requestNetwork()的動作(建立PDN連線請求),有三個觸發地方:
1.MAL處理結束後,通知DataDispatcher發起PDN連線
2.監聽SIM卡狀態,主副卡切換時發起PDN連線
3.監聽RIL層的ims鏈路情況,合適時機發起PDN連線

發起PDN連線還是需要通過ConnectivityManager,之後會有ims apn的檢查過程,PDN的連線過程可以參考 路由配置資訊的獲取

ims pdn連線建立的過程,需要建立在正常4G pdn連線的基礎上,這部分的判斷應該是被封裝在了MAL中,我們無法檢視。

DEBUG:

D/ImsService( 3729): receive EVENT_IMS_ENABLING_URC, mActivePhoneId = 1, phoneId = 1
//MAL-IMSM send MSG_ID_WRAP_IMSM_IMSPA_PDN_ACT_REQ
D/MAL-IMSM(10037): send MSG_ID_WRAP_IMSM_IMSPA_PDN_ACT_REQ, transaction_id = 16, rat_type = 0, emergency_ind = 0
(vendor/mediatek/proprietary/frameworks/opt/mal/volte_imsm/src/imsm_handler.c:2031)
//dispatch MSG_ID_WRAP_IMSM_IMSPA_PDN_ACT_REQ
D/[ImsAdapter]( 3729): dumpEvent:
phone_id:1,request_id:MSG_ID_WRAP_IMSM_IMSPA_PDN_ACT_REQ,data_len:4,event:[[email protected]
D/[ImsEventDispatcher]( 3729): dispatchCallback: request ID:MSG_ID_WRAP_IMSM_IMSPA_PDN_ACT_REQ
I/DataDispatcher( 3729): [dedicate] DataDispatcher receives request [900008, 4, phoneId: 1]
D/DataDispatcher( 3729): [dedicate] DataDispatcher handleDefaultBearerActivationRequest
//SETUP_DATA_CALL
D/RILJ ( 3721): [4116]> SETUP_DATA_CALL 14 2 ims 0 IPV4V6 5 [SUB1]
D/RILJ ( 3721): [4116]< SETUP_DATA_CALL DataCallResponse: {version=11 status=0 retry=0 cid=4 active=2 type=IPV6
ifname=ccmni4 mtu=0 rat=1 addresses=[FE80:0000:0000:0000:5220:368e:3Ba8:A680] dnses=[211.136.112.50,211.136.150.66]
gateways=[FE80:0000:0000:0000:5220:368e:3Ba8:A680]
pcscf=[36.9.128.20.134.1.16.16.0.0.0.0.0.0.0.9,36.9.128.20.130.1.48.16.0.0.0.0.0.0.0.9]} [SUB1]

ims pdn連線建立後,接下來就是sip註冊的過程了。MAL中處理完sip註冊過程後,會通知ImsService進行處理。見時序圖。
sip註冊:
這裡寫圖片描述

鑑權: 即認證,是識別某實體或使用者的身份,並確保該實體或使用者為合法使用者身份的方法。歸
屬網路通過使用者初始註冊過程對使用者進行鑑權。當用戶終端發起初始註冊時, S-CSCF 根據
REGISTER 訊息中攜帶的頭域以及使用者在HSS 上開戶時選擇的鑑權方式對終端進行鑑權目前固
定終端使用HTTP Digest 鑑權方式,也即使用使用者名稱和密碼進行鑑權。註冊過程的鑑權與認證保
證了網路的安全性。
註冊信令流程圖:
這裡寫圖片描述

DEBUG:

//1st register
I/VoLTE SIPTX(10758): [SIPTX-IO] Send SIP (2409:8014:8601:1010::9: 5060 )[131073:196610] ==> { REGISTER
sip:ims.mnc000.mcc460.3gppnetwork.org SIP/2.0 }
I/VoLTE SIPTX(10758): [SIPTX-IO] Send Success]
I/VoLTE SIPTX(10758): [SIPTX-IO] Recv SIP (2409:8014:8601:1010::9: 5060 )[131073:196610] <== { SIP/2.0 401 Unauthorized }
//second register
I/VoLTE SIPTX(10758): [SIPTX-IO] Send SIP (2409:8014:8601:1010::9: 9900 )[131073:262147] ==> { REGISTER
sip:ims.mnc000.mcc460.3gppnetwork.org SIP/2.0 }
I/VoLTE SIPTX(10758): [SIPTX-IO] Send Success]
I/VoLTE SIPTX(10758): [SIPTX-IO] Recv SIP (2409:8014:8601:1010::9: 9900 )[131073:262147] <== { SIP/2.0 200 OK }
//reigiter state
I/AT ( 1062): AT< +CIREGU: 1,d (RIL_URC2_READER, tid:0)
D/RILJ ( 3721): [UNSL]< RIL_UNSOL_IMS_REGISTRATION_INFO [SUB1]

三.IMS註冊問題的一些例子

案例:
向MAL 設定IMS feature 引數失敗
1.
這裡寫圖片描述
問題分析:
在離開飛航模式的時候,MAL 出現了異常,處於not ready 狀態,此時FW 不會向MAL 設定IMS feature 引數,註冊流程
終止,MAL 是封裝的庫檔案,需要MTK 修改。
// key log —- MAL isn’t ready
06-27 18:07:22.339748 1484 1529 D WifiOffloadService: onMalReset
06-27 18:07:30.628588 1484 1497 D WifiOffloadService: notifyMalRadioInfo return directly due to MAL isn’t ready yet.
https://drive.google.com/open?id=0B4KdjNMUeozNZE50QWp5TmRDQVU

2.
這裡寫圖片描述
問題分析:
在分析發現進入飛航模式前,wfo 獲取的資料庫中的值是disable 的導致,向MAL 設定的vilte feature 也是disable,所以
無法使用vilte。進一步分析發現條件不滿足,vilte feature 未寫入資料庫。

3.
這裡寫圖片描述
分析:
分析發現ims enable 之後, 未收到volte_imsm 上報的IMS PDN 啟用請求,MSG_ID_WRAP_IMSM_IMSPA_PDN_ACT_REQ,
導致未發起pdn 連線。
正常log:
D/ImsEventDispatcher: dispatchCallback: request ID:MSG_ID_WRAP_IMSM_IMSPA_PDN_ACT_REQ
I/DataDispatcher( 3729): [dedicate] DataDispatcher receives request [900008, 4, phoneId: 1]
D/DataDispatcher( 3729): [dedicate] DataDispatcher handleDefaultBearerActivationRequest
屬於MAL 封裝庫,需要MTK 修改
https://drive.google.com/open?id=0B4KdjNMUeozNLWJwaDFHdDlkSDg

5.
這裡寫圖片描述
分析:
撥打IMS emergency call 時,需要建立IMS emergency pdn,此問題apn 表中未配置Emergency apn 引數,導致未發起PDN 請求。
https://pan.baidu.com/s/1geRYFUr

6.
這裡寫圖片描述

問題分析:
UE 發register 訊息,網路未響應,超時後註冊失敗。MTK 提供優化方案,建立TCP 連線失敗後,跳過UDP 連線,重新
發起下一次連線。
//走TCP 失敗,三次握手失敗, 10s timeout
15:10:42.930051 100.96.153.29 10.55.41.196 TCP 76 59518 → 5060 [SYN] Seq=0 Win=65535 Len=0
MSS=1200 SACK_PERM=1 TSval=4294942468 TSecr=0 WS=256
15:10:43.921538 100.96.153.29 10.55.41.196 TCP 76 [TCP Retransmission] 59518 → 5060 [SYN] Seq=0
Win=65535 Len=0 MSS=1200 SACK_PERM=1 TSval=4294942568 TSecr=0 WS=256
15:10:49.931533 100.96.153.29 10.55.41.196 TCP 76 [TCP Retransmission] 59518 → 5060 [SYN] Seq=0
Win=65535 Len=0 MSS=1200 SACK_PERM=1 TSval=4294943169 TSecr=0 WS=256
//走UDP, 110s timeout,註冊失敗
15:10:52.943226 100.96.153.29 10.55.41.196 IPv4 1516 Fragmented IP protocol (proto=UDP 17, off=0, ID=fa25)
[Reassembled in #349]
15:10:52.943489 100.96.153.29 10.55.41.196 SIP 341 Request: REGISTER
sip:ims.mnc092.mcc404.3gppnetwork.org (1 binding) |
15:12:42.950612 100.96.153.29 10.55.41.196 IPv4 1516 Fragmented IP protocol (proto=UDP 17, off=0, ID=0b72)
[Reassembled in #1599]
15:12:42.950642 100.96.153.29 10.55.41.196 SIP 341 Request: REGISTER
sip:ims.mnc092.mcc404.3gppnetwork.org (1 binding) |
http://pan.baidu.com/s/1o8A3CAQ

7.
這裡寫圖片描述

分析:
User Agent 客製化引起NVRAM_EF_IMS_PROFILE_LID 的值不符合預期。
09-11 17:30:24.037077 4584 4626 I AT : AT> AT+EIMSVOICE=1 (RIL_CMD2_READER_3, tid:493392720976)
09-11 17:30:24.042894 4584 4626 I AT : AT> AT+EIMSVOLTE=1 (RIL_CMD2_READER_3, tid:493392720976)
09-11 17:30:24.049705 4584 4626 I AT : AT> AT+EIMS=1 (RIL_CMD2_READER_3, tid:493392720976)
09-11 17:30:24.052815 4584 4640 I AT : AT< +EIMS: 1 (RIL_URC2_READER, tid:0)
//nv execption
09-11 17:30:27.022221 7393 7393 I VoLTE IMCB-2: connection status change for module 7 as error_num 0
imcb_imcb_comm_error_handler()@0#609
118311, 0, 203151, 18:32:41:073 2017/09/11, MOD_IMC, MOD_DHL, DHL_IMC_SAP,
MSG_ID_DHL_IMC_EM_DUMP_NVRAM_IND
Local_Parameter –> Len = 3192, Addr = 0xA686C2C8
dhl_imc_em_dump_nvram_ind_struct = (struct)
ref_count = 0x01
lp_reserved = 0x13
msg_len = 0x0c78
ims_profile = (struct)
ua_config = (struct)
local_port = 0x000013c4
pcscf_port_number = 0x00000000
ipsec_local_port_start = 0x00000000
ipsec_local_port_range = 0x00000000

8.
這裡寫圖片描述
分析:
IMCB 版本和modem 側IMC 版本不匹配導致
//log
10-30 10:22:29.494560 1829 1829 I VoLTE imcb-2: imcb and IMC verno un-sync!!! disable imcb/IMC connection!!!!
@0#3524

相關推薦

IMS註冊流程分析

本次的IMS註冊流程分析基於MT6580_O平臺。關於IMS的相關流程,MTK釋放的文件講得已經蠻詳細了,本次記錄的內容純屬在文件的基礎上加上自己的理解,以便日後的複習,僅供參考。 IMS的整體框架圖如下: 其中MAL層以so庫檔案的形式存在,程式碼

基於GBT28181:SIP協議元件開發-----------第三篇SIP註冊流程分析實現

原創文章,引用請保證原文完整性,尊重作者勞動,原文地址http://www.cnblogs.com/qq1269122125/p/3941172.html,qq:1269122125。 上兩章節簡要的講解了SIP元件開發介面和開發環境的搭建。在本節將實現Linux 3

小程式生命週期分析註冊流程回撥

從小程式釋出到現在,官方api 變動了好幾個版本 首先我們先看一下小程式的生命週期 app.js 為小程式的啟動入口檔案 onLauch: 小程式初始化回掉,生命週期內只執行一次 onShow: 小程式開啟或者從後臺喚起時的回撥 onHide: 小程式從前臺進入後臺時

dubbo原始碼分析-服務端註冊流程-筆記

前面,我們已經知道,基於spring這個解析入口,到釋出服務的過程,接著基於DubboProtocol去釋出,最終呼叫Netty的api建立了一個NettyServer。 那麼繼續沿著RegistryProtocol.export這個方法,來看看註冊服務的程式碼: RegistryProtocol.ex

MTK方案GPON ONU註冊流程和OMCI分析

進入串列埠登入:輸入以下指令 開啟GPON ONU OMCI報文除錯指令: echo msg init 1 > /proc/gpon/debug echo msg oam 1 > /proc/gpon/debug echo msg err 1 > /proc/gpon/de

Ultimate Member外掛註冊登入流程分析

Ultimate Member 是一個強大而靈活的WordPress外掛,可以讓使用者在前臺註冊、登入、編輯個人資料等。該外掛可以讓你新增漂亮的使用者個人資料到你的網站中,快速建立一個先進的社群。本文我簡單的記錄下分析流程,流程簡介就是:註冊、登入、使用者中心頁面都執行短程式

newlib 中的 crt0 流程分析

gets eno -s style and 條件判斷 obj als example 最近對 newlib 中的啟動代碼 crt0 產生了興趣,於是就分析了下其代碼。crt0 的源碼位於 libgloss/arm/crt0.S,為了兼容各種 ARM 架構,crt0.S 中有

微信小程序開發者註冊流程

流程 推薦 height 開發者 技術分享 9.png images 公眾 blog 一,首先打開瀏覽器,搜索微信公眾平臺 點擊進入,此時還沒有註冊微信小程序開發賬號,我們需要點擊註冊 進入註冊頁面,會出現四種賬號,我們選擇小程序賬號 然後根據提示就可以進行註冊了

PowerManagerService流程分析

other nes func 靜下心來 沒有 light 事情 統一管理 mon 一、PowerManagerService簡介   PowerManagerService主要服務Android系統電源管理工作,這樣講比較籠統,就具體細節上大致可以認為PowerManage

翻翻git之---自己定義郵件發送buttonSendButton(流程分析,實現思路能夠學習下)

現象 date() 加速 lag restart xtend fas trace str 轉載請註明出處:王亟亟的大牛之路 距離過春節還有1天。繼續這一系列的git翻料之旅。 昨天的工具類真的非常棒,這裏再推崇一下 傳送門:http://blog.c

英文建站必備:Namesilo 購買註冊流程

你是 建議 continue 如果 服務 works 等待 結束 灰色 Namesilo 是目前價格較便宜的國外域名平臺,之前在 Bluehost 購買流程的文章中也給大家推薦過。它支持支付寶、Paypal、Visa 等多種付款方式,還可以免費使用域名隱私保護,性價比非常之

Android5 Zygote 與 SystemServer 啟動流程分析

進一步 null 正常的 rtb 這樣的 ket constant vml resp Android5 Zygote 與 SystemServer 啟動流程分析 Android5 Zygote 與 SystemServer 啟動流程分析 前言 zy

詳解Windows註冊分析取證

classes 創建 dev html ida soft free 人在 隱藏 大多數都知道windows系統中有個叫註冊表的東西,但卻很少有人會去深入的了解它的作用以及如何對它進行操作。然而對於計算機取證人員來說註冊表無疑是塊巨大的寶藏。通過註冊表取證人員能分析出系統發生

微信公眾平臺開發教程(一) 微信公眾賬號註冊流程

身份證 logs 政府 提交 註意 bsp 訪問服務器 定義 htm 具體的操作步驟 1、註冊公眾賬號 註冊地址:http://mp.weixin.qq.com/ 1)首先需要郵箱註冊: 2)郵箱激活。郵箱將會收到激活郵件,點擊激活鏈接即可。 3)需要登記個人信息。這裏需

深入了解View(一)—— measure測量流程分析

sans asc res markdown pla 轉換成 高亮 trac 體驗 歡迎使用Markdown編輯器寫博客 本Markdown編輯器使用StackEdit改動而來,用它寫博客。將會帶來全新的體驗哦: Markdown和擴展Markdow

開機啟動流程分析

boot 啟動流程 本節索引 在對系統啟動流程進行分析的時候,我想你一定是對系統有了一定的了解。系統的啟動目前來講大都為串行接力的方式來啟動。而所謂的並行方式的啟動方式也是某一個階段的並行。所以我按照系統啟動的順序來把文章連綴起來。 * BIOS階段 * BootLoader階段

kexec 內核快速啟動流程分析

-- 令行 並且 內存 tab 執行過程 family use -a 一、命令行 1. kexec -l $kpwd --append="$arg" 其中$kpwd =目標內核的路徑   $arg =傳給內核的參數,與/proc/cmdline一致時表示重啟現有內核

SpringMVC的流程分析(一)—— 整體流程概括

classes amp 不同 方法 restfu equals 類圖 strong .get SpringMVC的整體概括 之前也寫過springmvc的流程分析,只是當時理解的還不透徹所以那篇文章就放棄了,現在比之前好了些,想著寫下來分享下,也能增強記憶,也希望可以幫助到

深入淺出Mybatis系列(十)---SQL執行流程分析(源碼篇)(轉)

factor demo 讀取配置 gist wrapper load 任性 wrap 深入淺出 轉載自:http://www.cnblogs.com/dongying/p/4142476.html 1. SqlSessionFactory 與 SqlSession.   通

Spring Core Container 源碼分析三:Spring Beans 初始化流程分析

turn raw time -c rri add 步驟 引用 lin 前言 本文是筆者所著的 Spring Core Container 源碼分析系列之一; 本篇文章主要試圖梳理出 Spring Beans 的初始化主流程和相關核心代碼邏輯; 本文轉載自本人的私人博客,傷神