DcTracker是android上网流程中的“大管家”,起着响应上网拨号,判断当前是否能够拨号,以及管理apn的作用。现在我们先从它的初始化讲起。
一、DcTracker的初始化
每个Phone对象有自己DcTracker
每个DcTracker加载各自卡可用的APN
DcTracker的构造方法中,有几个比较重要的部分。分别是:
1、监听卡载入
mUiccController.registerForIccChanged(this, DctConstants.EVENT_ICC_CHANGED, null);
1.handler消息注册(向RILJ,GsmCdmdCallTracker,ServiceStateTracker三个对象发起handler,Message消息注册)
2、监听卡信息变化
mSubscriptionManager = SubscriptionManager.from(mPhone.getContext());
mSubscriptionManager.addOnSubscriptionsChangedListener(mOnSubscriptionsChangedListener)
3、监听APN数据库变化

mApnObserver = new ApnChangeObserver();
phone.getContext().getContentResolver().registerContentObserver(
        Telephony.Carriers.CONTENT_URI, true, mApnObserver);

4.向RILJ,GsmCdmdCallTracker,ServiceStateTracker三个对象发起handler,Message消息注册
registerForAllEvents();
5、初始化不同APN类型对应的网络能力

initApnContexts();

总而言之,就是与各关键类,消息建立联系,并且初始化了ApnContext,得到mApnContexts,mApnContextsById,mPrioritySortedApnContexts都保存了10个ApnContext对象。
二、讲解重点模块
1.handler消息注册
registerForAllEvents(),然后在registerForAllEvents再次注册,调用registerServiceStateTrackerEvents。
这里注意三点:
1)handler消息注册对象
DcTracker主要向RILJ,GsmCdmdCallTracker,ServiceStateTracker三个对象发起handler,Message消息注册

2.初始化ApnContext
ApnContext是ApnContext是拨号时使用的数据结构,也是apn管理的最小单位,里面是有关apn的所有信息。一条apn信息,就对应一个ApnContext。在初始化Apncontext后,会生成三个集合来管理ApnContext。分别是:mApnContexts,mApnContextsById,mPrioritySortedApnContexts都保存了10个ApnContext对象
初始化ApnContext是调用方法initApnContexts()。
这是ApnContext的构造函数,在创建ApnContext时,将Network Config与APN type关联起来了。

其中有几个重要的属性ApnType和priority(apn的优先级)。
再来看看NetworkConfig是什么,NetworkConfig其实就是代表一种网络类型。构造方法如下:

具体赋值是从xml表中加载(最重要的当然是第一列的name,第二列的apntype,第四列的priority):

文件的位置Honor_V20/system/frameworks/base/core/res/res/values/config.xml。
在initApnContexts方法中会将加载好的NetworkConfig的信息,包装到到ApnContext中去。然后通过addApnContext方法,将这些ApnContext保存到三个列表中,mApnContexts,mApnContextsById,mPrioritySortedApnContexts(这是根据NetworkConfig中优先级排的)

PS:从config.xml中解析出的网络配置信息从而创建了12个NetworkConfig对象,共匹配了10个ApnContext对象。匹配的关系就是NetworkConfig的type属性。这里只截图了一部分。

从Apn type中能知道APN type对应的具体网络能力。
例如:APN type包含default时,利用这个APN建立的网络就具有Mobile能力,即能够用数据网络访问Internet;
当APN type包含mms时,利用这个APN建立的网络就具有发送彩信的能力。
因此这三个集合mApnContexts,mApnContextsById,mPrioritySortedApnContexts都保存了10个ApnContext对象。mPrioritySortedApnContexts是根据NetworkConfig的优先级排列的。也就是priority属性。mPrioritySortedApnContexts中第一个ApnContext对象的mApnType是ConnectivityManager.TYPE_MOBILE_HIPRI,因为config.xml中,HIPRI的priority属性为3,最高。我们在收到彩信的时候会先断开default数据(正常的上网数据业务类型)连接就是因为mms的优先级比default的优先级要高。断开default数据连接而创建mms数据连接,从而能快速接受彩信,因此,在发送和接收彩信的同时不能上网。
PS:在ApnContext中还有ApnSetting对象作为属性。之后会介绍ApnSetting,不要弄混了。

  1. 监听APN数据库变化

1)监听Telephony.Carriers.CONTENT_URI,其实就是Telephony数据库中carriers表中apn信息是否发生变化。

注册了监听器,当apn数据库发生变化了,mApnObserver的onChange方法会响应APN配置信息的变化。发送EVENT_APN_CHANGER消息。交给handleMessage处理。

讲完了DcTracker的初始化,还有一个重要的内容需要讲,那就是加载apn信息。
二、DcTracker加载和设置ApnSetting的流程
手机中有预制很多国家的不同运营商的APN信息。以v20为例子,这些预制的文件是在:
/cust/global/carrier目录下,然后根据不同的mnn+mnc的号为子目录的名字,例如移动46001的APN信息就是在:/cust/global/carrier/46001/xml/apn-conf.xml。以下是它信息的截图。

当我APN数据库改变或卡状态发生变化时,DcTracker就会去加载和设置ApnSetting。
在DcTracker中,mAllApnSettings是一个保存当前运营商的APN配置信息列表。它的list中的元素是ApnSetting。

ApnSetting类使用types,carrier,apn,proxy,port,mmsc等28个属性来保存APN配置信息。之前也介绍过ApnContext,在DcTracker中管理ApnContext和ApnSettings两个对象的集合,都与Apn有关,ApnContext的mApnSetting是ApnSetting对象,提供setApnSetting方法来设置mApnSetting属性。
它的加载是在createAllApnList方法中。一般有两种场景会触发:卡状态变化引起的APN加载和数据库状态变化引起的APN加载。
1)卡状态变化引起的APN加载

1、如上图所示,DcTracker在初始化时,向SubscriptionManager注册了onSubscriptionChangedListener,以监听卡状态变化的消息。
2、当用户进行插卡等会引起卡状态变化的动作后,SubscriptionManager就会通知DcTracker。
3、DcTracker收到通知后,将判断当前卡是否有效,同时与历史信息比较,判断卡的SubId是否发生变化。
4、一旦发现SubId发生变化后,DcTracker就会调用onRecordsLoadedOrSubIdChanged函数,重新从数据库中加载APN信息。
如上图所示,onRecordsLoadedOrSubIdChanged函数中,与APN相关的函数为createAllApnList和setInitialAttachApn。其中:
在createAllApnList的功能就是:创建当前卡可用的APN。会根据当前的numeric(运营商编号)去carriers表中查询apn的信息。然后将这个apn信息保存在mAllApnSettings中。

于是,当用户使用这张卡上网时,框架就会从这张卡对应的ApnSetting中选择可用的APN。
setInitialAttachApn的功能是设置初始使用的APN。主要是从得到的所有ApnSetting中,选择一个用于初始时注册数据网络的APN,并将该APN下发给modem使用。
Initial Attach APN选择的规则是:
首先选择具有IA type的APN;
其次选择用户在设置界面选择的APN;
再次是选择第一个具有default type的APN;
最后选择第一个从数据库中加载上来的APN。
5、从上图中可以看出,当DcTracker加载完APN后,还调用了setupDataOnConnectableApns函数,尝试进行数据拨号。
不过,终端是否会进行实际的连网动作,取决于数据开关是否打开及ApnContext是否被激活等条件。
2)数据库状态变化引起的APN加载

1、如上图所示,当DcTracker收到数据库变化的通知后,将调用onApnChanged函数进行处理。
2、在onApnChanged函数中,同样将调用前文所述的createAllApnList加载数据中中的信息组成ApnSetting,
并调用setInitialAttachApn函数设置Initial Attach APN。
3、与前文不同的是,当检测到APN发生改变时,onApnChanged函数还将根据所有ApnContext的状态,判断终端当前是否已经建立起了数据连接,或者在试图建立数据连接,即ApnContext是否处于CONNECTED、CONNECTING等状态。
4、当DcTracker发现终端已经建立起数据连接,或者试图建立数据连接时,
就调用cleanUpConnectionsOnUpdatedApns函数,断开已有的数据连接或停止拨号动作。
然后,数据卡对应的DcTracker将再次调用前文所述的setupDataOnConnectableApns函数,重新建立数据连接。

至此,框架加载APN相关的主要流程介绍完毕。

这部分内容从整体来看,其实就做了两件事:
1、将XML文件中的信息,变成数据库中的数据;
2、将数据库中的数据,变成框架可以使用的数据结构。
在这两件事的基础上,当框架检测到文件或数据库等发生变化时,再启动相应的流程来应对这种变化。

DcTracker关键类图


bobo
1 声望0 粉丝