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