一、DcTracker介紹
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);
- }
- public final class DcTracker extends DcTrackerBase {}
- public abstract class DcTrackerBase extends Handler {}
然後來看DcTracker的初始化過程:
- @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();
- }
1、初始化各種監聽器;
2、初始化TelephonyNetworkFactory對象;
3、初始化一些基本的APN參數;
下面我們分別詳細介紹這三個過程。
二、DcTracker中監聽器的初始化
- 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!");
- }
- }
- protected boolean isActiveDataSubscription() {
- // FIXME This should have code like
- // return (mPhone.getSubId() == SubscriptionManager.getDefaultDataSubId());
- return true;
- }
對於雙卡的手機,由於任意時刻只能有一個SIM卡在上網,因此就需要根據用戶選擇的上網卡來配置不同的APN參數,該方法的原始意圖應該是在內部判斷當前的DcTracker是否就是用戶設置的上網SIM(用戶當前使用哪張卡上網可以通過SubscriptionManager.getDefaultDataSubId()方法查詢到SIM的SubID),如果是當前卡的話返回true,否則返回false。但是由於Google並未完善其雙卡邏輯,因此這裏直接返回了true。
接下來繼續來看判斷後的registerForAllEvents()的過程:
- 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);
- }
EVENT_DATA_CONNECTION_ATTACHED
----監聽PS的Attach事件,觸發時將進入onDataConnectionAttached()
EVENT_DATA_RAT_CHANGED
----監聽當前所註冊的網絡技術(LTE/UMTS/GSM)是否發生改變,觸發時將進入setupDataOnConnectableApns()
然後在update()中還對SIM卡狀態進行監聽:
- 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);
- }
- }
- }
除了以上的update()和onUpdateIcc()外,在DcTracker的構造方法裏面還註冊了對APN參數的監聽器:
- 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));
- }
- }
至此,DcTracker中所有監聽器準備就緒,其中比較重要的監聽器被觸發時所產生的影響我們會在稍後過程中介紹。
三、DcTracker中NetworkFactory的創建過程
- 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");
- }
- 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();
- }
- }
更多的NetworkFactory使用與原理請點擊《連接管理中的評分機制》。
四、DcTracker中初始APN的創建過程
- public DcTracker(PhoneBase p) {
- //從networkAttributes數組中初始化APN參數
- initApnContexts();
- //初始化緊急APN
- initEmergencyApnSetting();
- addEmergencyApnSetting();
- }
4.1、初始化networkAttributes數組中的APN參數
- 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參數。
4.2、初始化緊急APN參數
1、通過initEmergencyApnSetting()載入緊急APN;
2、通過addEmergencyApnSetting()將緊急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();
- }
- }
這些參數是在TelephonyProvider被創建的時候被初始化,下面簡單看一下初始化流程:
- @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) { }
- }
- }
- @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>
上面是數據庫初始化的過程,回到DcTracker的緊急APN初始化過程中來,當從數據庫中搜索到"type="emergency""的緊急APN參數後,通過initEmergencyApnSetting()方法將這些參數放入mEmergencyApn中,接下來還需要通過addEmergencyApnSetting()方法把這些緊急APN存入統一的APN庫中:
- 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");
- }
- }
- }
- }
至此,DcTracker所有初始化工作全部完成,在這個過程中註冊了監聽器、創建了TelephonyNetworkFactory、初始化了緊急APN,接下來就是等待監聽器被觸發。