Android7.0 IMS开机初始化

IMS(IP Multimedia Subsystem)被认为是下一代网络的核心技术,是解决移动与固网融合,引入语音、数据、视频三重融合等差异化业务的重要方式。Android作为移动网络终端的主要操作系统,也提供了对IMS的支持。
本篇博客的目的就是弄清楚Android中的IMS是如何完成开机初始化的。

一、监控IMS Service
之前的博客中已经分析过PhoneApp的启动过程(Android7.0 PhoneApp的启动),同时在分析数据业务基础类创建的过程时(Android7.0 数据业务基础类的创建),已经提到了PhoneFactory中的makeDefaultPhone函数。

makeDefaultPhone函数负责启动对IMS Service的监控,其中相关的代码如下:

<code class="hljs cs has-numbering"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">makeDefaultPhone</span>(Context context) {
    ........
    <span class="hljs-comment">// Start monitoring after defaults have been made.</span>
    <span class="hljs-comment">// Default phone must be ready before ImsPhone is created</span>
    <span class="hljs-comment">// because ImsService might need it when it is being opened.</span>
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i < numPhones; i++) {
        <span class="hljs-comment">//sPhones为静态数组,持有实际的GsmCdmaPhone对象</span>
        sPhones[i].startMonitoringImsService();
    }
    ........
}</code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li></ul>

startMonitoringImsService将启动对IMS Service的监控,该函数定义于GsmCdmaPhone的父对象Phone中:

<code class="hljs java has-numbering"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">startMonitoringImsService</span>() {
    <span class="hljs-comment">//正常情况下,应该是GSM或CDMA类型</span>
    <span class="hljs-keyword">if</span> (getPhoneType() == PhoneConstants.PHONE_TYPE_SIP) {
        <span class="hljs-keyword">return</span>;
    }

    <span class="hljs-keyword">synchronized</span>(Phone.lockForRadioTechnologyChange) {
        IntentFilter filter = <span class="hljs-keyword">new</span> IntentFilter();
        filter.addAction(ImsManager.ACTION_IMS_SERVICE_UP);
        filter.addAction(ImsManager.ACTION_IMS_SERVICE_DOWN);
        <span class="hljs-comment">//利用mImsIntentReceiver监听IMS服务启动和关闭的广播</span>
        mContext.registerReceiver(mImsIntentReceiver, filter);

        <span class="hljs-comment">// Monitor IMS service - but first poll to see if already up (could miss</span>
        <span class="hljs-comment">// intent)</span>
        <span class="hljs-comment">//1 、获取ImsManager</span>
        ImsManager imsManager = ImsManager.getInstance(mContext, getPhoneId());
        <span class="hljs-comment">//2、 判断ImsService是否已经启动,初始时未启动,略过下文</span>
        <span class="hljs-keyword">if</span> (imsManager != <span class="hljs-keyword">null</span> && imsManager.isServiceAvailable()) {
            mImsServiceReady = <span class="hljs-keyword">true</span>;
            updateImsPhone();
            ImsManager.updateImsServiceConfig(mContext, mPhoneId, <span class="hljs-keyword">false</span>);
        }
    }
}</code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li></ul>

从上面的代码可以看出,所谓的监控IMS Service,实际上指的是监听IMS Service启动和关闭时的广播。

1、获取ImsManager
我们先看看如何获取ImsManager:

<code class="hljs cs has-numbering"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> ImsManager <span class="hljs-title">getInstance</span>(Context context, <span class="hljs-keyword">int</span> phoneId) {
    synchronized (sImsManagerInstances) {
        <span class="hljs-comment">//sImsManagerInstances为一个静态的HashMap</span>
        <span class="hljs-keyword">if</span> (sImsManagerInstances.containsKey(phoneId))
            <span class="hljs-keyword">return</span> sImsManagerInstances.<span class="hljs-keyword">get</span>(phoneId);

            ImsManager mgr = <span class="hljs-keyword">new</span> ImsManager(context, phoneId);
            sImsManagerInstances.put(phoneId, mgr);

            <span class="hljs-keyword">return</span> mgr;
        }
    }
}</code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li></ul>

从上面的代码来看,我们知道每个Phone都有对应的ImsManager对象。

跟进一下ImsManager的构造函数:

<code class="hljs java has-numbering"><span class="hljs-keyword">private</span> <span class="hljs-title">ImsManager</span>(Context context, <span class="hljs-keyword">int</span> phoneId) {
    mContext = context;
    mPhoneId = phoneId;
    createImsService(<span class="hljs-keyword">true</span>);
}

<span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">createImsService</span>(<span class="hljs-keyword">boolean</span> checkService) {
    <span class="hljs-keyword">if</span> (checkService) {
        <span class="hljs-comment">//如果ImsService启动了,就会将自己注册到service_manager进程中</span>
        IBinder binder = ServiceManager.checkService(getImsServiceName(mPhoneId));

        <span class="hljs-keyword">if</span> (binder == <span class="hljs-keyword">null</span>) {
            <span class="hljs-keyword">return</span>;
        }

        <span class="hljs-comment">//如果ImsService已经注册,获取对应的Binder对象</span>
        IBinder b = ServiceManager.getService(getImsServiceName(mPhoneId));

        <span class="hljs-keyword">if</span> (b != <span class="hljs-keyword">null</span>) {
            <span class="hljs-keyword">try</span> {
                <span class="hljs-comment">//注册一个“讣告”观察者,当ImsService的Binder dead时,</span>
                <span class="hljs-comment">//mDeathRecipient将发送ACTION_IMS_SERVICE_DOWN的广播信息</span>
                b.linkToDeath(mDeathRecipient, <span class="hljs-number">0</span>);
            } <span class="hljs-keyword">catch</span> (RemoteException e) {
            }
        }

        <span class="hljs-comment">//将binder对象转化为ImsService的Proxy</span>
        mImsService = IImsService.Stub.asInterface(b);
    }
}</code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li></ul>

2、判断IMS Service是否可用

接下来跟进一下isServiceAvailable函数:

<code class="hljs java has-numbering"><span class="hljs-keyword">public</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">isServiceAvailable</span>() {
    <span class="hljs-keyword">if</span> (mImsService != <span class="hljs-keyword">null</span>) {
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">true</span>;
    }

    IBinder binder = ServiceManager.checkService(getImsServiceName(mPhoneId));
    <span class="hljs-keyword">if</span> (binder != <span class="hljs-keyword">null</span>) {
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">true</span>;
    }

    <span class="hljs-keyword">return</span> <span class="hljs-keyword">false</span>;
}</code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li></ul>

从代码可以看出,isServiceAvailable同样是根据ImsService是否注册到service manager进程,来判断ImsService是否可用。

二、IMS Service的结构

如上图所示,在Android的原生代码里,定义了抽象类ImsServiceBase,在该类中定义了内部类ImsServiceBinder。
ImsServiceBinder类实现了ImsService.aidl定义的接口,负责为ImsManager的调用提供服务。

实际上,ImsServiceBinder提供的所有函数并没有完成实际的功能,而是转调用ImsServiceBase中的定义的函数。按照Android的提供代码的结构,ImsServiceBase中定义的函数,将由其子类ImsService来实现。
也就是说经过几次转换,ImsManager的调用接口时,将由ImsService来提供具体的服务。

然而Android原生代码中并没有实现ImsService,仅仅定义了上面描述的继承和通信的结构。可能由于保密的原因,或者由于ImsService与HAL层强相关,ImsService一般由实际的芯片厂商来实现。

因此,在这里我们无法分析原生的ImsService启动过程。我们就以Qualcomm启动ImsService的流程为例,简单介绍一下整体的思路。
需要提出的是,在Qualcomm的设计中,ImsService并没有继承ImsServiceBase,而是直接用ImsService替换掉了ImsServiceBase,它的代码结构如下(MTK中ImsService直接继承ImsService.Stub,连ImsServiceBase.Java都去掉了):

在Qualcomm的代码中,在vendor目录下定义了一个IMS相关的APK。在该APK中,定义了一个常驻的BroadcastReceiver。
当该广播监听器,收到ACTION_BOOT_COMPLETED或ACTION_SIM_STATE_CHANGED消息时,就会发送Intent拉起Qualcomm定义的ImsService。

ImsService启动后,将自己注册到service manager进程,然后进一步创建IMS服务所需的对象,及注册一些观察者监听modem上报的事件,同时发送ACTION_IMS_SERVICE_UP和ACTION_IMS_SERVICE_DOWN的广播。

在第一部分”监控IMS Service”中,我们已经提到在Phone对象中创建了广播监听器,用于监听IMS服务的广播。
由于同时只有一个Phone具备IMS能力,因此IMS会发送两个广播并携带对应的PHONE_ID。
于是,一个Phone将处理ACTION_IMS_SERVICE_UP;另一个Phone将处理ACTION_IMS_SERVICE_DOWN。

以上的流程是属于Qualcomm的,并不是开源代码,为了遵守保密协议,这里就不附上实际的代码了。

三、ImsPhone的创建
ImsService发送广播后,我们回到Phone.java中看看对应的广播接收器如何处理:

<code class="hljs java has-numbering"><span class="hljs-keyword">private</span> BroadcastReceiver mImsIntentReceiver = <span class="hljs-keyword">new</span> BroadcastReceiver() {
    <span class="hljs-annotation">@Override</span>
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onReceive</span>(Context context, Intent intent) {
        Rlog.d(LOG_TAG, <span class="hljs-string">"mImsIntentReceiver: action "</span> + intent.getAction());

        <span class="hljs-keyword">if</span> (intent.hasExtra(ImsManager.EXTRA_PHONE_ID)) {
            <span class="hljs-comment">//取出Intent中的Phone_ID</span>
            <span class="hljs-keyword">int</span> extraPhoneId = intent.getIntExtra(ImsManager.EXTRA_PHONE_ID,
                    SubscriptionManager.INVALID_PHONE_INDEX);
            Rlog.d(LOG_TAG, <span class="hljs-string">"mImsIntentReceiver: extraPhoneId = "</span> + extraPhoneId);

            <span class="hljs-comment">//Phone_ID与当前的Phone不符时,不做处理</span>
            <span class="hljs-keyword">if</span> (extraPhoneId == SubscriptionManager.INVALID_PHONE_INDEX ||
                    extraPhoneId != getPhoneId()) {
                <span class="hljs-keyword">return</span>;
            }
        }

        <span class="hljs-keyword">synchronized</span> (Phone.lockForRadioTechnologyChange) {
            <span class="hljs-comment">//按情况修改mImsServiceReady变量</span>
            <span class="hljs-keyword">if</span> (intent.getAction().equals(ImsManager.ACTION_IMS_SERVICE_UP)) {
                mImsServiceReady = <span class="hljs-keyword">true</span>;
                updateImsPhone();
                ImsManager.updateImsServiceConfig(mContext, mPhoneId, <span class="hljs-keyword">false</span>);
            } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (intent.getAction().equals(ImsManager.ACTION_IMS_SERVICE_DOWN)) {
                mImsServiceReady = <span class="hljs-keyword">false</span>;
                updateImsPhone();
            }
        }
    }
};</code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li></ul>

从上面的代码来看收到广播后需要调用updateImsPhone函数;只有收到ACTION_IMS_SERVICE_UP消息时,才会调用updateImsServiceConfig函数。

接下来我们分别看看updateImsPhone和updateImsServiceConfig。

1、updateImsPhone

<code class="hljs lasso has-numbering"><span class="hljs-keyword">private</span> <span class="hljs-literal">void</span> updateImsPhone() {
    <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-attribute">...</span>
    <span class="hljs-keyword">if</span> (mImsServiceReady <span class="hljs-subst">&&</span> (mImsPhone <span class="hljs-subst">==</span> <span class="hljs-built_in">null</span>)) {
        <span class="hljs-comment">//收到ACTION_IMS_SERVICE_UP时,创建ImsPhone</span>
        <span class="hljs-comment">//ImsPhone继承自ImsPhoneBase,后者继承自Phone</span>
        mImsPhone <span class="hljs-subst">=</span> PhoneFactory<span class="hljs-built_in">.</span>makeImsPhone(mNotifier, this);
        <span class="hljs-comment">//完成拨号相关的注册</span>
        CallManager<span class="hljs-built_in">.</span>getInstance()<span class="hljs-built_in">.</span>registerPhone(mImsPhone);
        mImsPhone<span class="hljs-built_in">.</span>registerForSilentRedial(
                this, EVENT_INITIATE_SILENT_REDIAL, <span class="hljs-built_in">null</span>);
    } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (<span class="hljs-subst">!</span>mImsServiceReady <span class="hljs-subst">&&</span> (mImsPhone <span class="hljs-subst">!=</span> <span class="hljs-built_in">null</span>)) {
        <span class="hljs-comment">//如果之前创建过ImsPhone的phone,收到ACTION_IMS_SERVICE_DOWN时</span>
        <span class="hljs-comment">//注销ImsPhone</span>
        CallManager<span class="hljs-built_in">.</span>getInstance()<span class="hljs-built_in">.</span>unregisterPhone(mImsPhone);
        mImsPhone<span class="hljs-built_in">.</span>unregisterForSilentRedial(this);

        mImsPhone<span class="hljs-built_in">.</span>dispose();
        <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-built_in">.</span>
        mImsPhone <span class="hljs-subst">=</span> <span class="hljs-built_in">null</span>;
    }
}</code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li></ul>

我们跟进一下ImsPhone的创建过程:

<code class="hljs cs has-numbering"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> Phone <span class="hljs-title">makeImsPhone</span>(PhoneNotifier phoneNotifier, Phone defaultPhone) {
    <span class="hljs-comment">//PhoneFactory实际上调用ImsPhoneFactory的静态函数</span>
    <span class="hljs-keyword">return</span> ImsPhoneFactory.makePhone(sContext, phoneNotifier, defaultPhone);
}</code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li></ul>
<code class="hljs cs has-numbering"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> ImsPhone <span class="hljs-title">makePhone</span>(Context context,
        PhoneNotifier phoneNotifier, Phone defaultPhone) {
    <span class="hljs-keyword">try</span> {
        <span class="hljs-comment">//ImsPhoneFactory直接调用ImsPhone的构造函数</span>
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> ImsPhone(context, phoneNotifier, defaultPhone);
    } <span class="hljs-keyword">catch</span> (Exception e) {
        Rlog.e(<span class="hljs-string">"VoltePhoneFactory"</span>, <span class="hljs-string">"makePhone"</span>, e);
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">null</span>;
    }
}</code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li></ul>

最后看一下ImsPhone的构造函数:

<code class="hljs java has-numbering"><span class="hljs-keyword">public</span> <span class="hljs-title">ImsPhone</span>(Context context, PhoneNotifier notifier, Phone defaultPhone) {
    <span class="hljs-keyword">this</span>(context, notifier, defaultPhone, <span class="hljs-keyword">false</span>);
}

<span class="hljs-annotation">@VisibleForTesting</span>
<span class="hljs-keyword">public</span> <span class="hljs-title">ImsPhone</span>(Context context, PhoneNotifier notifier, Phone defaultPhone,
        <span class="hljs-keyword">boolean</span> unitTestMode) {
    <span class="hljs-keyword">super</span>(<span class="hljs-string">"ImsPhone"</span>, context, notifier, unitTestMode);

    mDefaultPhone = defaultPhone;
    <span class="hljs-comment">//定义Ims拨号对应的Call Tracker</span>
    mCT = TelephonyComponentFactory.getInstance().makeImsPhoneCallTracker(<span class="hljs-keyword">this</span>);
    mExternalCallTracker =
            TelephonyComponentFactory.getInstance().makeImsExternalCallTracker(<span class="hljs-keyword">this</span>, mCT);

     <span class="hljs-keyword">try</span> {
         <span class="hljs-comment">//定义Call State Listener</span>
        mImsMultiEndpoint = mCT.getMultiEndpointInterface();
        mImsMultiEndpoint.setExternalCallStateListener(
                mExternalCallTracker.getExternalCallStateListener());
    } <span class="hljs-keyword">catch</span> (ImsException e) {
        Rlog.i(LOG_TAG, <span class="hljs-string">"ImsMultiEndpointInterface is not available."</span>);
    }

    <span class="hljs-comment">//将ImsPhone的service复位</span>
    mSS.setStateOff();

    mPhoneId = mDefaultPhone.getPhoneId();
    ...........
    <span class="hljs-comment">//ImsPhone利用对应的defaultPhone监听数据注册状态和无线技术的变化</span>
    <span class="hljs-keyword">if</span> (mDefaultPhone.getServiceStateTracker() != <span class="hljs-keyword">null</span>) {
        mDefaultPhone.getServiceStateTracker()
                .registerForDataRegStateOrRatChanged(<span class="hljs-keyword">this</span>,
                        EVENT_DEFAULT_PHONE_DATA_STATE_CHANGED, <span class="hljs-keyword">null</span>);
    }
    <span class="hljs-comment">//利用defaultPhone更新mSS,得到数据服务的注册状态及无线技术</span>
    updateDataServiceState();
}</code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li></ul>

以上是ImsPhone创建的基本流程。
IMS依赖于数据业务,并为语音业务提供服务。今后分析语音业务时,会再进一步分析IMS。

2、updateImsServiceConfig
如上文所述,当Phone收到ACTION_IMS_SERVICE_UP时,会调用ImsManager的updateImsServiceConfig函数:

<code class="hljs java has-numbering"><span class="hljs-comment">//force的值为false</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">updateImsServiceConfig</span>(Context context, <span class="hljs-keyword">int</span> phoneId, <span class="hljs-keyword">boolean</span> force) {
    <span class="hljs-comment">//当不是强制启动时,必须保证对应的卡就绪</span>
    <span class="hljs-keyword">if</span> (!force) {
        <span class="hljs-keyword">if</span> (TelephonyManager.getDefault().getSimState() != TelephonyManager.SIM_STATE_READY) {
            log(<span class="hljs-string">"updateImsServiceConfig: SIM not ready"</span>);
            <span class="hljs-comment">// Don't disable IMS if SIM is not ready</span>
            <span class="hljs-keyword">return</span>;
        }
    }

    <span class="hljs-keyword">final</span> ImsManager imsManager = ImsManager.getInstance(context, phoneId);
    <span class="hljs-comment">//初始时ImsManager的mConfigUpdated为false</span>
    <span class="hljs-keyword">if</span> (imsManager != <span class="hljs-keyword">null</span> && (!imsManager.mConfigUpdated || force)) {
        <span class="hljs-keyword">try</span> {
        } <span class="hljs-keyword">catch</span> (ImsException e) {
            loge(<span class="hljs-string">"updateImsServiceConfig: "</span> + e);
            imsManager.mConfigUpdated = <span class="hljs-keyword">false</span>;
        }

        <span class="hljs-comment">//IMS包括语音VoLTE、视频VideoCall和WFC(WiFiCall)</span>
        <span class="hljs-comment">//当三种中的一种可用时,就可以使用IMS</span>
        <span class="hljs-comment">//以下是根据基本都是依据系统属性等,判断是否可用</span>
        <span class="hljs-keyword">boolean</span> isImsUsed = imsManager.updateVolteFeatureValue();
        isImsUsed |= imsManager.updateVideoCallFeatureValue();
        isImsUsed |= imsManager.updateWfcFeatureAndProvisionedValues();

        <span class="hljs-keyword">if</span> (isImsUsed || !getBooleanCarrierConfig(context,
            CarrierConfigManager.KEY_CARRIER_ALLOW_TURNOFF_IMS_BOOL)) {
            <span class="hljs-comment">// Turn on IMS if it is used.</span>
            <span class="hljs-comment">// Also, if turning off is not allowed for current carrier,</span>
            <span class="hljs-comment">// we need to turn IMS on because it might be turned off before</span>
            <span class="hljs-comment">// phone switched to current carrier.</span>
            imsManager.turnOnIms();
        } <span class="hljs-keyword">else</span> {
            <span class="hljs-comment">// Turn off IMS if it is not used AND turning off is allowed for carrier.</span>
            imsManager.turnOffIms();
        }

        imsManager.mConfigUpdated = <span class="hljs-keyword">true</span>;
    }
}</code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li><li>42</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li><li>42</li></ul>

从updateImsServiceConfig函数的代码可以看出,它将根据IMS服务是否可用,选择开启或关闭IMS(这里指的是开启或关闭modem对IMS能力的支持,不是开启或关闭Java层的ImsService)。
但它在什么地方进行了update ImsService Config的操作呢?毕竟函数的名字已经这么取了。

2.1updateVolteFeatureValue
为了解释这个问题,我们以updateVolteFeatureValue为例进行分析:

<code class="hljs java has-numbering"><span class="hljs-comment">//定义于ImsManger中</span>
<span class="hljs-keyword">private</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">updateVolteFeatureValue</span>() <span class="hljs-keyword">throws</span> ImsException {
    <span class="hljs-comment">//以下读取数据库、系统属性和资源文件得到对应字段的值</span>
    <span class="hljs-keyword">boolean</span> available = isVolteEnabledByPlatform(mContext);
    <span class="hljs-keyword">boolean</span> enabled = isEnhanced4gLteModeSettingEnabledByUser(mContext);
    <span class="hljs-keyword">boolean</span> isNonTty = isNonTtyOrTtyOnVolteEnabled(mContext);
    <span class="hljs-comment">//均为true时,feature才是on</span>
    <span class="hljs-keyword">boolean</span> isFeatureOn = available && enabled && isNonTty;

    <span class="hljs-comment">//打印log</span>
    .........

    <span class="hljs-comment">//这里就是进行update IMS config的位置</span>
    getConfigInterface().setFeatureValue(
            ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_LTE,
            TelephonyManager.NETWORK_TYPE_LTE,
            isFeatureOn ?
                    ImsConfig.FeatureValueConstants.ON :
                    ImsConfig.FeatureValueConstants.OFF,
            mImsConfigListener);

    <span class="hljs-keyword">return</span> isFeatureOn;
}</code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li></ul>

我们先看看getConfigInterface函数:

<code class="hljs lasso has-numbering"><span class="hljs-keyword">public</span> ImsConfig getConfigInterface() throws ImsException {
    <span class="hljs-keyword">if</span> (mConfig <span class="hljs-subst">==</span> <span class="hljs-built_in">null</span>) {
        <span class="hljs-comment">//判断ImsService是否存活</span>
        checkAndThrowExceptionIfServiceUnavailable();

        try {
            <span class="hljs-comment">//从ImsService获取一个Binder通信客户端</span>
            IImsConfig config <span class="hljs-subst">=</span> mImsService<span class="hljs-built_in">.</span>getConfigInterface(mPhoneId);
            <span class="hljs-keyword">if</span> (config <span class="hljs-subst">==</span> <span class="hljs-built_in">null</span>) {
                throw <span class="hljs-literal">new</span> ImsException(<span class="hljs-string">"getConfigInterface()"</span>,
                        ImsReasonInfo<span class="hljs-built_in">.</span>CODE_LOCAL_SERVICE_UNAVAILABLE);
            }
            mConfig <span class="hljs-subst">=</span> <span class="hljs-literal">new</span> ImsConfig(config, mContext);
        } catch (RemoteException e) {
            <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-built_in">..</span>
        }
    }
    <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-built_in">.</span>
    <span class="hljs-keyword">return</span> mConfig;
}</code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li></ul>

现在跟进ImsConfig的setFeatureValue函数:

<code class="hljs cs has-numbering"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setFeatureValue</span>(<span class="hljs-keyword">int</span> feature, <span class="hljs-keyword">int</span> network, <span class="hljs-keyword">int</span> <span class="hljs-keyword">value</span>,
        ImsConfigListener listener) throws ImsException {
    ..........
    <span class="hljs-keyword">try</span> {
        <span class="hljs-comment">//利用ImsService返回的Binder通信客户端,调用服务端的setFeatureValue函数</span>
        miConfig.setFeatureValue(feature, network, <span class="hljs-keyword">value</span>, listener);
    } <span class="hljs-keyword">catch</span> (RemoteException e) {
        .......
    }
}</code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li></ul>

ImsConfig的实际功能由芯片厂商来提供,例如Qualcomm就定义了ImsConfigImpl的类作为Binder通信的服务端。
ImsConfigImpl类将利用RIL,将Config Feature信息发往modem。

按照上述代码,我们可以看出Android原生的逻辑定义了一个ImsConfigListener作为回调接口,
不过在Qualcomm修改过的代码中,传入的ImsConfigListener是null。

2.2 turnOnIms
接下来,我们看看turnOnIms是如何完成的:

<code class="hljs java has-numbering"><span class="hljs-comment">//定义于ImsManager中</span>
<span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">turnOnIms</span>() <span class="hljs-keyword">throws</span> ImsException {
    checkAndThrowExceptionIfServiceUnavailable();

    <span class="hljs-keyword">try</span> {
        <span class="hljs-comment">//依赖于ImsService</span>
        mImsService.turnOnIms(mPhoneId);
    } <span class="hljs-keyword">catch</span> (RemoteException e) {
        ......
    }
}</code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li></ul>

如上代码所示,turnOnIms和turnOffIms将依赖于实际的ImsService类。

在QualComm的实现中:
ImsService下发开/关IMS的消息给modem;
然后,等待modem主动上报IMS服务状态改变;
AP侧收到状态改变信息后,再次主动向modem发送查询IMS服务状态的消息;
获得modem的返回结果后,AP进行逻辑处理,并发送广播给监听者,进行对应的操作,例如更新SystemUI等。

以上就是IMS开机初始化的主要流程,由于考虑到芯片厂商的利益,大量的代码不是开源的,因此重在理解IMS整体的通信结构。

四、获取IMS的注册状态
上文已经提到过,当ImsService启动后,发送广播给Phone对象。
Phone对象收到广播后,将创建出ImsPhone。在ImsPhone的构造函数中:

<code class="hljs java has-numbering"><span class="hljs-comment">//定义于ImsPhone.java</span>
<span class="hljs-keyword">public</span> <span class="hljs-title">ImsPhone</span>(Context context, PhoneNotifier notifier, Phone defaultPhone,
        <span class="hljs-keyword">boolean</span> unitTestMode) {
    ..........
    <span class="hljs-comment">//创建了ImsPhoneCallTracker</span>
    mCT = TelephonyComponentFactory.getInstance().makeImsPhoneCallTracker(<span class="hljs-keyword">this</span>);
    .........       
}

<span class="hljs-comment">//定义于TelephonyComponentFactory.java</span>
<span class="hljs-keyword">public</span> ImsPhoneCallTracker <span class="hljs-title">makeImsPhoneCallTracker</span>(ImsPhone imsPhone) {
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> ImsPhoneCallTracker(imsPhone);
}</code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li></ul>

我们跟进一下ImsPhoneCallTracker的构造函数:

<code class="hljs cs has-numbering"><span class="hljs-keyword">public</span> <span class="hljs-title">ImsPhoneCallTracker</span>(ImsPhone phone) {
    <span class="hljs-keyword">this</span>.mPhone = phone;
    ...........

    <span class="hljs-comment">//监听是否有来电</span>
    IntentFilter intentfilter = <span class="hljs-keyword">new</span> IntentFilter();
    intentfilter.addAction(ImsManager.ACTION_IMS_INCOMING_CALL);
    intentfilter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
    mPhone.getContext().registerReceiver(mReceiver, intentfilter);

    <span class="hljs-comment">//由卡信息决定    </span>
    mAllowEmergencyVideoCalls = isEmergencyVtCallAllowed(mPhone.getSubId());

    Thread t = <span class="hljs-keyword">new</span> Thread() {
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">run</span>() {
            <span class="hljs-comment">//重头戏在这里</span>
            getImsService();
        }
    };
    t.start();
}</code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li></ul>

我们从代码可以看出,在ImsCallTracker的构造函数中启动了一个线程,调用getImsService:

<code class="hljs lasso has-numbering"><span class="hljs-keyword">private</span> <span class="hljs-literal">void</span> getImsService() {
    <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-built_in">..</span>
    mImsManager <span class="hljs-subst">=</span> ImsManager<span class="hljs-built_in">.</span>getInstance(mPhone<span class="hljs-built_in">.</span>getContext(), mPhone<span class="hljs-built_in">.</span>getPhoneId());
    try {
        mServiceId <span class="hljs-subst">=</span> mImsManager<span class="hljs-built_in">.</span>open(ImsServiceClass<span class="hljs-built_in">.</span>MMTEL,
                createIncomingCallPendingIntent(),
                <span class="hljs-comment">//传入了一个ConnectionStateListener,这就是获取IMS服务状态的接口</span>
                mImsConnectionStateListener);

        <span class="hljs-comment">//设置更新feature的回调接口;Qualcomm直接去掉了这句</span>
        <span class="hljs-comment">//原生的实现也就是打印了log</span>
        mImsManager<span class="hljs-built_in">.</span>setImsConfigListener(mImsConfigListener);

        <span class="hljs-comment">//处理EmergencyCabllback和TtyMode</span>
        <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-built_in">.</span>
    } catch (ImsException e) { 
        <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-attribute">...</span><span class="hljs-built_in">.</span>
    }
}</code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li></ul>

上面调用ImsManger的open函数,实际上会利用ImsService进行实际的处理,依赖于芯片厂商实现,此处就不贴具体的源码了。

这里需要说明的是,不要被open函数的名称骗到了,它不会进行类似于turnOnIms的操作,仅仅用于从modem获取IMS服务当前的注册状态,同时将mImsConnectionStateListener注册到ImsService中(或其成员中)。

当获取到IMS服务的注册状态,或IMS服务状态发送改变时,均会回调mImsConnectionStateListener的接口。
最后我们看看ImsPhoneCallTracker中定义的ImsConnectionStateListener,目前重点关注IMS服务连接和断开的接口:

<code class="hljs java has-numbering"><span class="hljs-keyword">private</span> ImsConnectionStateListener mImsConnectionStateListener =
    <span class="hljs-keyword">new</span> ImsConnectionStateListener() {
        <span class="hljs-annotation">@Override</span>
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onImsConnected</span>() {
            <span class="hljs-keyword">if</span> (DBG) log(<span class="hljs-string">"onImsConnected"</span>);
            <span class="hljs-comment">//修改服务状态为STATE_IN_SERVICE</span>
            mPhone.setServiceState(ServiceState.STATE_IN_SERVICE);
            <span class="hljs-comment">//IMS成功注册</span>
            mPhone.setImsRegistered(<span class="hljs-keyword">true</span>);
            mEventLog.writeOnImsConnectionState(
                    TelephonyEventLog.IMS_CONNECTION_STATE_CONNECTED, <span class="hljs-keyword">null</span>);
        }

        <span class="hljs-annotation">@Override</span>
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onImsDisconnected</span>(ImsReasonInfo imsReasonInfo) {
            <span class="hljs-keyword">if</span> (DBG) log(<span class="hljs-string">"onImsDisconnected imsReasonInfo="</span> + imsReasonInfo);
            <span class="hljs-comment">//修改服务状态为STATE_OUT_OF_SERVICE</span>
            mPhone.setServiceState(ServiceState.STATE_OUT_OF_SERVICE);
            <span class="hljs-comment">//IMS未注册</span>
            mPhone.setImsRegistered(<span class="hljs-keyword">false</span>);
            <span class="hljs-comment">//解析错误原因,会发广播</span>
            mPhone.processDisconnectReason(imsReasonInfo);
            mEventLog.writeOnImsConnectionState(
                    TelephonyEventLog.IMS_CONNECTION_STATE_DISCONNECTED, imsReasonInfo);
        }

        <span class="hljs-annotation">@Override</span>
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onImsProgressing</span>() {
            ...........
        }

        <span class="hljs-annotation">@Override</span>
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onImsResumed</span>() {
            ...........
        }

        <span class="hljs-annotation">@Override</span>
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onImsSuspended</span>() {
            ........
        }

        <span class="hljs-annotation">@Override</span>
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onFeatureCapabilityChanged</span>(<span class="hljs-keyword">int</span> serviceClass,
            <span class="hljs-keyword">int</span>[] enabledFeatures, <span class="hljs-keyword">int</span>[] disabledFeatures) {
            .........
        }

        <span class="hljs-annotation">@Override</span>
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onVoiceMessageCountChanged</span>(<span class="hljs-keyword">int</span> count) {
            ........
        }
    };
}</code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li><li>42</li><li>43</li><li>44</li><li>45</li><li>46</li><li>47</li><li>48</li><li>49</li><li>50</li><li>51</li><li>52</li><li>53</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li><li>42</li><li>43</li><li>44</li><li>45</li><li>46</li><li>47</li><li>48</li><li>49</li><li>50</li><li>51</li><li>52</li><li>53</li></ul>

从代码容易看出,mImsConnectionStateListener将调用ImsPhone的setServiceState函数更新服务状态:

<code class="hljs cs has-numbering"><span class="hljs-keyword">void</span> setServiceState(<span class="hljs-keyword">int</span> state) {
    <span class="hljs-comment">//更改ImsPhone持有的ServiceState的语音服务状态</span>
    mSS.setVoiceRegState(state);
    updateDataServiceState();
}

<span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">updateDataServiceState</span>() {
    <span class="hljs-keyword">if</span> (mSS != <span class="hljs-keyword">null</span> && mDefaultPhone.getServiceStateTracker() != <span class="hljs-keyword">null</span>
            && mDefaultPhone.getServiceStateTracker().mSS != <span class="hljs-keyword">null</span>) {
        <span class="hljs-comment">//更改对应GsmCdmaPhone持有的ServiceState的数据服务状态及无线技术</span>
        ServiceState ss = mDefaultPhone.getServiceStateTracker().mSS;
        mSS.setDataRegState(ss.getDataRegState());
        mSS.setRilDataRadioTechnology(ss.getRilDataRadioTechnology());
        Rlog.d(LOG_TAG, <span class="hljs-string">"updateDataServiceState: defSs = "</span> + ss + <span class="hljs-string">" imsSs = "</span> + mSS);
    }
}</code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li></ul>
五、总结
这篇博客中我们分析了Anroid中ImsService如何启动、ImsPhone如何创建及如何监听实际IMS服务的注册状态等。
由于IMS相关的代码并不开源,因此有些流程没法详细分析,知道Anroid中IMS相关的通信 架构即可。
  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值