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 的初始化主流程和相關核心代碼邏輯; 本文轉載自本人的私人博客,傷神