数据业务建立流程之DcTracker创建过程(原)

一、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);
        }
        那么DcTracker是什么属性呢?
        public final class DcTracker extends DcTrackerBase {}
        public abstract class DcTrackerBase extends Handler {}
        从这里看到,DcTracker的父类是DcTrackerBase, 他们的本质都是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中监听器的初始化


        DcTracker在update()方法中注册了对各种事件的监听, 用于触发DcTracker创建APN或者发起数据连接
       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在为双卡项目预留的判断。
        对于双卡的手机,由于任意时刻只能有一个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);
                }
            }
        }
        这里监听的是SIM卡数据(SPN/FDN/ADN等)是否载入完毕。 
        除了以上的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));
            }
        }
        也就是说,当APN参数的数据库(Telephony.Carriers.CONTENT_URI)发生改动时,将会触发ApnChangeObserver,向DcTracker发送EVENT_APN_CHANGED的消息。

        至此,DcTracker中所有监听器准备就绪,其中比较重要的监听器被触发时所产生的影响我们会在稍后过程中介绍。


三、DcTracker中NetworkFactory的创建过程


        DcTracker初始化中还创建了NetworkFactory的子类对象TelephonyNetworkFactory,从《 连接管理中的评分机制》一节中我们知道,该对象的作用就是初始化网络环境,设置当前网络环境的分值,对于数据流量来说,其分值为50:
        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使用与原理请点击《连接管理中的评分机制》。


四、DcTracker中初始APN的创建过程


        DcTracker初始化过程中还完成了一些初始APN参数的创建,包括预置的APN参数和紧急APN参数的载入:
        public DcTracker(PhoneBase p) {
            //从networkAttributes数组中初始化APN参数
            initApnContexts();


            //初始化紧急APN
            initEmergencyApnSetting();
            addEmergencyApnSetting();
        }


4.1、初始化networkAttributes数组中的APN参数


        我们先来看initApnContexts()的过程,其主要 作用就是载入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参数


        紧急APN参数就是当没有SIM卡或者当前SIM不可用时使用的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();
            }
        }
        这个载入过程其实就是从数据库中搜索条件为"type="emergency""的APN参数,那么这个数据库中的内容是哪里来的呢?
        这些参数是在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) { }
            }
        }
        从上面可以看到,从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等信息。
        上面是数据库初始化的过程,回到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");
                    }
                }
            }
        }
        通过以上步骤,紧急APN的创建过程就完成了。
        至此,DcTracker所有初始化工作全部完成,在这个过程中注册了监听器、创建了TelephonyNetworkFactory、初始化了紧急APN,接下来就是等待监听器被触发。

你可能感兴趣的:(NetworkFactory,DcTracker,initApnContexts)