1. 程式人生 > >資料業務建立流程之APN引數的啟用(原)

資料業務建立流程之APN引數的啟用(原)

        APN引數在前面《資料業務建立流程之常規APN引數的建立》一文中已經都被建立完畢並存入mAllApnSettings的陣列中,但是這些APN引數預設都是沒有被Enable的,只有當APN被Enable之後,該APN才可以被使用,下面我們就來看如何將一個APN引數啟用。
        APN的Enable是通過TelephonyNetworkFactory中的needNetworkFor()方法觸發的,我們在《網路連線評分機制之NetworkFactory》文章中介紹過,噹噹前網路的評分比其他網路高時,就會通過needNetworkFor()方法觸發當前網路的建立。比如當前WIFI斷開時,如果發現數據網路是開啟的,此時就會通過該方法啟用資料流量,從而實現從WIFI到資料的轉換過程。
        而當needNetworkFor()被觸發時,就會引發APN的Enable過程:
        protected void needNetworkFor(NetworkRequest networkRequest, int score) {
            //根據網路需求尋找合適APN
            ApnContext apnContext = apnContextForNetworkRequest(networkRequest);
            //Enable上網用的APN
            if (apnContext != null) apnContext.incRefCount();
        }
        由於不同網路需求可能需要不同的APN引數,因此先要經過apnContextForNetworkRequest()來尋找合適的APN,對於上網來說,其尋找到的APN型別為TYPE_MOBILE,然後通過incRefCount()來Enable當前的APN:
        @ApnContext.java
        public void incRefCount() {
            synchronized (mRefCountLock) {
                if (mRefCount++ == 0) {
                    //設定Enable
                    mDcTracker.setEnabled(mDcTracker.apnTypeToId(mApnType), true);
                }
            }
        }
        這裡需要用到DcTracker父類DcTrackerBase中的setEnabled()方法來將APN開啟:
        @DcTrackerBase.java
        protected void setEnabled(int id, boolean enable) {
            Message msg = obtainMessage(DctConstants.EVENT_ENABLE_NEW_APN);
            msg.arg1 = id;
            msg.arg2 = (enable ? DctConstants.ENABLED : DctConstants.DISABLED);
            sendMessage(msg);
        }
        這裡傳送了一條EVENT_ENABLE_NEW_APN的訊息,該訊息將會在DcTrackerBase中handleMessage()中被處理:
        @DcTrackerBase.java
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case DctConstants.EVENT_ENABLE_NEW_APN:
                    onEnableApn(msg.arg1, msg.arg2);
                    break;
            }
        }
        這裡的onEnableApn()在子類DcTracker中被覆蓋:
        @DcTracker.java
        protected void onEnableApn(int apnId, int enabled) {
            ApnContext apnContext = mApnContexts.get(apnIdToType(apnId));
            if (apnContext == null) {
                loge("onEnableApn(" + apnId + ", " + enabled + "): NO ApnContext");
                return;
            }
            //開啟APN
            applyNewState(apnContext, enabled == DctConstants.ENABLED, apnContext.getDependencyMet());
        }
        繼續看applyNewState()過程,這裡傳遞的第二個引數為true,第二個引數是從networkAttributes陣列中讀取的,預設都為true。
        private void applyNewState(ApnContext apnContext, boolean enabled, boolean met) {
            boolean cleanup = false;
            boolean trySetup = false;
            if (apnContext.isReady()) {
                //APN如果已經被Enable
            } else {
                if (enabled && met) {
                    //APN需要被Enable
                    if (apnContext.isEnabled()) {
                        apnContext.setReason(Phone.REASON_DATA_DEPENDENCY_MET);
                    } else {
                        //設定reason為REASON_DATA_ENABLED
                        apnContext.setReason(Phone.REASON_DATA_ENABLED);
                    }
                    if (apnContext.getState() == DctConstants.State.FAILED) {
                        apnContext.setState(DctConstants.State.IDLE);
                    }
                    trySetup = true;
                }
            }
            //Enable當前APN
            apnContext.setEnabled(enabled);
            //設定其mDependencyMet屬性也為true
            apnContext.setDependencyMet(met);
            //清除當前連線
            if (cleanup) cleanUpConnection(true, apnContext);
            //建立資料連線
            if (trySetup) trySetupData(apnContext);
        }
        由於enabled、met兩個引數此時都為true,因此將會設定APN的Reason為REASON_DATA_ENABLED,並且其mDataEnabled和mDependencyMet屬性都為true:
        public void setEnabled(boolean enabled) {
            mDataEnabled.set(enabled);
        }
        public void setDependencyMet(boolean met) {
            mDependencyMet.set(met);
        }
        再來看一下該APN引數isReady的判斷:
        public boolean isReady() {
            return mDataEnabled.get() && mDependencyMet.get();
        }
        由此可知,以後當判斷該APN是否isReady()時,將會得到true的狀態,也就是說,當前APN已經準備就緒。