IMS的注册流程分析

IMS的基础常识:
https://www.cnblogs.com/moon-lights/p/7018789.html
http://www.360doc.com/content/15/0624/06/9966538_480253246.shtml
http://www.txrjy.com/thread-879446-1-1.html

本次的IMS注册流程分析基于MT6580_O平台。关于IMS的相关流程,MTK释放的文档讲得已经蛮详细了,本次记录的内容纯属在文档的基础上加上自己的理解,以便日后的复习,仅供参考。
IMS的整体框架图如下:
IMS的注册流程分析_第1张图片

其中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的开关。它们的时序图如下:
IMS的注册流程分析_第2张图片

这个”增强型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的注册过程。
IMS的注册流程分析_第3张图片

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:[B@3f853cc
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

4.

分析:
log 中发现未找到IMS APN 参数,导致没有发起PDN 请求,需要在apns-conf.xml 中添加对应运营商apn 参数
https://share.weiyun.com/18012b10941f0e727515e80555bb8880

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.
IMS的注册流程分析_第4张图片

分析:
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.
IMS的注册流程分析_第5张图片
分析:
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

你可能感兴趣的:(系统开发---通讯模块相关,sip,volte,ims)