DcTracker是Telephony框架中负责数据业务的核心(类似于GsmCallTracker是通话业务核心,GsmServiceStateTracker是网络CS业务的核心),所有对数据网络的请求(打开关闭数据开关、切换数据卡、修改APN参数等)都会发送到该处理中心来处理。本节所涉及的大部分代码也都在该对象中。下面我们先来看该对象的初始化流程。
DcTracker是在Phone对象创建过程中被创建的,确切来说,如果当前使用的是GSMPhone,那么在GSMPhone创建过程中就会创建DcTracker对象:@GSMPhone.java public GSMPhone (Context context, CommandsInterface ci, PhoneNotifier notifier, boolean unitTestMode) { //创建DcTracker对象,传递的参数就是当前的GSMPhone对象 mDcTracker = new DcTracker(this); }那么DcTracker是什么属性呢?
public final class DcTracker extends DcTrackerBase {} public abstract class DcTrackerBase extends Handler {}从这里看到,DcTracker的父类是DcTrackerBase, 他们的本质都是Handler。
@DcTracker.java public DcTracker(PhoneBase p) { super(p); mDataConnectionTracker = this; //注册监听器 update(); //监听APN状态 mApnObserver = new ApnChangeObserver(); p.getContext().getContentResolver().registerContentObserver(Telephony.Carriers.CONTENT_URI, true, mApnObserver); //从networkAttributes数组中初始化APN参数 initApnContexts(); for (ApnContext apnContext : mApnContexts.values()) { IntentFilter filter = new IntentFilter(); filter.addAction(INTENT_RECONNECT_ALARM + '.' + apnContext.getApnType()); filter.addAction(INTENT_RESTART_TRYSETUP_ALARM + '.' + apnContext.getApnType()); mPhone.getContext().registerReceiver(mIntentReceiver, filter, null, mPhone); } ConnectivityManager cm = (ConnectivityManager)p.getContext().getSystemService(Context.CONNECTIVITY_SERVICE); //添加各种网络请求过滤器,用于根据这些过滤器发起不同的数据连接 mNetworkFilter = new NetworkCapabilities(); mNetworkFilter.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR); mNetworkFilter.addCapability(NetworkCapabilities.NET_CAPABILITY_MMS); mNetworkFilter.addCapability(NetworkCapabilities.NET_CAPABILITY_SUPL); mNetworkFilter.addCapability(NetworkCapabilities.NET_CAPABILITY_DUN); mNetworkFilter.addCapability(NetworkCapabilities.NET_CAPABILITY_FOTA); mNetworkFilter.addCapability(NetworkCapabilities.NET_CAPABILITY_IMS); mNetworkFilter.addCapability(NetworkCapabilities.NET_CAPABILITY_CBS); mNetworkFilter.addCapability(NetworkCapabilities.NET_CAPABILITY_IA); mNetworkFilter.addCapability(NetworkCapabilities.NET_CAPABILITY_RCS); mNetworkFilter.addCapability(NetworkCapabilities.NET_CAPABILITY_XCAP); mNetworkFilter.addCapability(NetworkCapabilities.NET_CAPABILITY_EIMS); mNetworkFilter.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); mNetworkFilter.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); //初始化数据网络的NetworkFactory,并设置数据网络的分值为50 mNetworkFactory = new TelephonyNetworkFactory(this.getLooper(), p.getContext(), "TelephonyNetworkFactory", mNetworkFilter); mNetworkFactory.setScoreFilter(50); mNetworkFactoryMessenger = new Messenger(mNetworkFactory); cm.registerNetworkFactory(mNetworkFactoryMessenger, "Telephony"); //初始化紧急APN initEmergencyApnSetting(); addEmergencyApnSetting(); mProvisionActionName = "com.android.internal.telephony.PROVISION" + p.getPhoneId(); }在上面这个初始化过程中,主要完成了三个任务:
下面我们分别详细介绍这三个过程。
public void update() { if (isActiveDataSubscription()) { //注册各种监听器 registerForAllEvents(); //注册SIM卡状态监听器 onUpdateIcc(); //mUserDataEnabled就是用户是否打开网络开关的标志位,当为0时,表示当前数据流量被关闭 mUserDataEnabled = Settings.Global.getInt(mPhone.getContext().getContentResolver(), Settings.Global.MOBILE_DATA, 1) == 1; if (mPhone instanceof CDMALTEPhone) { ((CDMALTEPhone)mPhone).updateCurrentCarrierInProvider(); supplyMessenger(); } else if (mPhone instanceof GSMPhone) { ((GSMPhone)mPhone).updateCurrentCarrierInProvider(); supplyMessenger(); } else { log("Phone object is not MultiSim. This should not hit!!!!"); } } else { unregisterForAllEvents(); log("update(): NOT the active DDS, unregister for all events!"); } }在这个方法里面,首先遇到的是isActiveDataSubscription()的判断,该方法定义为:
protected boolean isActiveDataSubscription() { // FIXME This should have code like // return (mPhone.getSubId() == SubscriptionManager.getDefaultDataSubId()); return true; }可以看到,其内部直接返回了true,貌似没有什么作用,其实这是Google在为双卡项目预留的判断。
protected void registerForAllEvents() { //监听射频是否打开,没有处理动作 mPhone.mCi.registerForAvailable(this, DctConstants.EVENT_RADIO_AVAILABLE, null); //监听射频是否可用,没有处理动作 mPhone.mCi.registerForOffOrNotAvailable(this, DctConstants.EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null); //监听当前连接状态,没有处理动作 mPhone.mCi.registerForDataNetworkStateChanged(this, DctConstants.EVENT_DATA_STATE_CHANGED, null); //监听当前通话状态,没有处理动作 mPhone.getCallTracker().registerForVoiceCallEnded (this, DctConstants.EVENT_VOICE_CALL_ENDED, null); //监听当前通话状态,没有处理动作 mPhone.getCallTracker().registerForVoiceCallStarted (this, DctConstants.EVENT_VOICE_CALL_STARTED, null); //监听是否PS域Attach状态 mPhone.getServiceStateTracker().registerForDataConnectionAttached(this, DctConstants.EVENT_DATA_CONNECTION_ATTACHED, null); //监听是否PS域Detach状态 mPhone.getServiceStateTracker().registerForDataConnectionDetached(this, DctConstants.EVENT_DATA_CONNECTION_DETACHED, null); //监听漫游状态,没有处理动作 mPhone.getServiceStateTracker().registerForRoamingOn(this, DctConstants.EVENT_ROAMING_ON, null); //监听漫游状态,没有处理动作 mPhone.getServiceStateTracker().registerForRoamingOff(this, DctConstants.EVENT_ROAMING_OFF, null); mPhone.getServiceStateTracker().registerForPsRestrictedEnabled(this, DctConstants.EVENT_PS_RESTRICT_ENABLED, null); mPhone.getServiceStateTracker().registerForPsRestrictedDisabled(this, DctConstants.EVENT_PS_RESTRICT_DISABLED, null); //监听接入技术状态 mPhone.getServiceStateTracker().registerForDataRegStateOrRatChanged(this, DctConstants.EVENT_DATA_RAT_CHANGED, null); }这里注册了大量的监听器,实际上很多都没有对监听动作进行处理(可能是为了扩展后续代码预留的),但是其中有两个比较重要的监听器,他们将会对上网事件产生影响,分别是:
protected void onUpdateIcc() { if (mUiccController == null ) { return; } IccRecords newIccRecords = getUiccRecords(UiccController.APP_FAM_3GPP); IccRecords r = mIccRecords.get(); if (r != newIccRecords) { if (r != null) { r.unregisterForRecordsLoaded(this); mIccRecords.set(null); } if (newIccRecords != null) { mIccRecords.set(newIccRecords); //监听SIM各项数据是否载入完毕 newIccRecords.registerForRecordsLoaded( this, DctConstants.EVENT_RECORDS_LOADED, null); } } }这里监听的是SIM卡数据(SPN/FDN/ADN等)是否载入完毕。
public DcTracker(PhoneBase p) { update(); mApnObserver = new ApnChangeObserver(); p.getContext().getContentResolver().registerContentObserver( Telephony.Carriers.CONTENT_URI, true, mApnObserver); }这里监听器内容为:
private class ApnChangeObserver extends ContentObserver { public ApnChangeObserver () { super(mDataConnectionTracker); } @Override public void onChange(boolean selfChange) { sendMessage(obtainMessage(DctConstants.EVENT_APN_CHANGED)); } }也就是说,当APN参数的数据库(Telephony.Carriers.CONTENT_URI)发生改动时,将会触发ApnChangeObserver,向DcTracker发送EVENT_APN_CHANGED的消息。
至此,DcTracker中所有监听器准备就绪,其中比较重要的监听器被触发时所产生的影响我们会在稍后过程中介绍。
public DcTracker(PhoneBase p) { ConnectivityManager cm = (ConnectivityManager)p.getContext().getSystemService(Context.CONNECTIVITY_SERVICE); //初始化数据网络的NetworkFactory,并设置数据网络的分值为50 mNetworkFactory = new TelephonyNetworkFactory(this.getLooper(), p.getContext(), "TelephonyNetworkFactory", mNetworkFilter); mNetworkFactory.setScoreFilter(50); mNetworkFactoryMessenger = new Messenger(mNetworkFactory); cm.registerNetworkFactory(mNetworkFactoryMessenger, "Telephony"); }看一下该TelephonyNetworkFactory定义:
private class TelephonyNetworkFactory extends NetworkFactory { public TelephonyNetworkFactory(Looper l, Context c, String TAG, NetworkCapabilities nc) { super(l, c, TAG, nc); } @Override protected void needNetworkFor(NetworkRequest networkRequest, int score) { ApnContext apnContext = apnContextForNetworkRequest(networkRequest); if (apnContext != null) apnContext.incRefCount(); } @Override protected void releaseNetworkFor(NetworkRequest networkRequest) { ApnContext apnContext = apnContextForNetworkRequest(networkRequest); if (apnContext != null) apnContext.decRefCount(); } }其中的两个方法分别用来覆盖父类, needNetworkFor()是当其他高分值的网络断开时,用于开启当前数据流量用的,而releaseNetworkFor()是当有更高分值的网络打开时,关闭当前数据流量用的。
更多的NetworkFactory使用与原理请点击《连接管理中的评分机制》。
public DcTracker(PhoneBase p) { //从networkAttributes数组中初始化APN参数 initApnContexts(); //初始化紧急APN initEmergencyApnSetting(); addEmergencyApnSetting(); }
protected void initApnContexts() { //载入networkAttributes数组 String[] networkConfigStrings = mPhone.getContext().getResources().getStringArray( com.android.internal.R.array.networkAttributes); for (String networkConfigString : networkConfigStrings) { NetworkConfig networkConfig = new NetworkConfig(networkConfigString); ApnContext apnContext = null; //根据不同类型创建不同APN参数 switch (networkConfig.type) { case ConnectivityManager.TYPE_MOBILE: apnContext = addApnContext(PhoneConstants.APN_TYPE_DEFAULT, networkConfig); break; case ConnectivityManager.TYPE_MOBILE_MMS: apnContext = addApnContext(PhoneConstants.APN_TYPE_MMS, networkConfig); break; case ConnectivityManager.TYPE_MOBILE_EMERGENCY: apnContext = addApnContext(PhoneConstants.APN_TYPE_EMERGENCY, networkConfig); break; default: log("initApnContexts: skipping unknown type=" + networkConfig.type); continue; } } }
这个过程比较简单,就是从networkAttributes数组中获取所有APN字串,然后根据类型分别创建APN参数。
private void initEmergencyApnSetting() { String selection = "type=\"emergency\""; Cursor cursor = mPhone.getContext().getContentResolver().query( Telephony.Carriers.CONTENT_URI, null, selection, null, null); if (cursor != null) { if (cursor.getCount() > 0) { if (cursor.moveToFirst()) { mEmergencyApn = makeApnSetting(cursor); } } cursor.close(); } }这个载入过程其实就是从数据库中搜索条件为"type="emergency""的APN参数,那么这个数据库中的内容是哪里来的呢?
@TelephonyProvider.java private void initDatabase(SQLiteDatabase db) { Resources r = mContext.getResources(); //从apns文件读取APN参数 XmlResourceParser parser = r.getXml(com.android.internal.R.xml.apns); int publicversion = -1; try { XmlUtils.beginDocument(parser, "apns"); //解析该文件 publicversion = Integer.parseInt(parser.getAttributeValue(null, "version")); loadApns(db, parser); } catch (Exception e) { } finally { parser.close(); } XmlPullParser confparser = null; //从"etc/apns-conf.xml"配置文件读取APN参数 File confFile = new File(Environment.getRootDirectory(), PARTNER_APNS_PATH); FileReader confreader = null; try { confreader = new FileReader(confFile); confparser = Xml.newPullParser(); confparser.setInput(confreader); XmlUtils.beginDocument(confparser, "apns"); int confversion = Integer.parseInt(confparser.getAttributeValue(null, "version")); if (publicversion != confversion) { throw new IllegalStateException("Internal APNS file version doesn't match " + confFile.getAbsolutePath()); } //将配置文件解析后存入数据库 loadApns(db, confparser); } catch (FileNotFoundException e) { } catch (Exception e) { } finally { try { if (confreader != null) confreader.close(); } catch (IOException e) { } } }从上面可以看到,从com.android.internal.R.xml.apns和"etc/apns-conf.xml"两个路径下读取了APN的配置文件并解析,然后存入了数据库,这些配置文件的配置内容如下:
@apns-conf.xml <?xml version="1.0" encoding="utf-8"?> <apns version="8"> <apn carrier="T-Mobile US" mcc="310" mnc="260" apn="epc.tmobile.com" user="none" server="*" password="none" mmsc="http://mms.msg.eng.t-mobile.com/mms/wapenc" /> <apn carrier="T-Mobile US 250" mcc="310" mnc="250" apn="epc.tmobile.com" user="none" server="*" password="none" mmsc="http://mms.msg.eng.t-mobile.com/mms/wapenc" /> </apns>从这个配置文件中可以看到,其每一项数据都包含了某个运营商的PLMN name、MCC、MNC、apn、user、server、password、mmsc等信息。
private void addEmergencyApnSetting() { if(mEmergencyApn != null) { if(mAllApnSettings == null) { mAllApnSettings = new ArrayList<ApnSetting>(); } else { boolean hasEmergencyApn = false; for (ApnSetting apn : mAllApnSettings) { if (ArrayUtils.contains(apn.types, PhoneConstants.APN_TYPE_EMERGENCY)) { //如果之前的SIM APN中已经包含了紧急APN,就无需再次添加 hasEmergencyApn = true; break; } } if(hasEmergencyApn == false) { //将mEmergencyApn添加到APN列表中 mAllApnSettings.add(mEmergencyApn); } else { log("addEmergencyApnSetting - E-APN setting is already present"); } } } }通过以上步骤,紧急APN的创建过程就完成了。