1. 程式人生 > >網路連線評分機制之再談WIFI與資料切換過程(原)

網路連線評分機制之再談WIFI與資料切換過程(原)

        前面幾節介紹了網路評分機制的執行流程,下面我們再次通過案例來梳理一下評分機制在使用過程中的體現。
        使用者原本在用資料上網,但是如果到了一個有WIFI的環境,並連線上了WIFI,此時使用者的手機將會自動斷開資料網路,這是如何做到的呢?
        當用戶來到WIFI環境時,如果連上了某個WIFI,那麼此時的WIFI狀態機將會進入L2ConnectedState狀態,然後會更新當前NetworkInfo狀態為CONNECTING狀態,並用該NetworkInfo建立WIFI的NetworkAgent物件,同時標明當前WIFI分值為60。即:
            mNetworkAgent = new WifiNetworkAgent(getHandler().getLooper(), mContext, "WifiNetworkAgent", mNetworkInfo, mNetworkCapabilitiesFilter, mLinkProperties, 60);
        然後在NetworkAgent初始化過程中將會向ConnectivityService註冊,然後ConnectivityService就會建立WIFI的NetworkAgentInfo物件:
            NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(),
                new NetworkInfo(networkInfo), new LinkProperties(linkProperties),
                new NetworkCapabilities(networkCapabilities), currentScore, mContext, mTrackerHandler,
                new NetworkMisc(networkMisc));
        然後ConnectivityService將會在handleRegisterNetworkAgent方法中更新當前WIFI的NetworkAgentInfo為CONNECTED狀態,並向NetworkMonitor傳送連線成功的訊息,然後經過有效性檢測,WIFI的分值將會保持在60分
        然後在rematchNetworkAndRequests中,將發現現有的網路請求所使用的資料流量方案的分值(50分)低於WIFI的分值,將會把最新WIFI的分值通過sendUpdatedScoreToFactories傳送到各個NetworkFactory中,其中就包括資料網路:
        private void sendUpdatedScoreToFactories(NetworkRequest networkRequest, int score) {
            for (NetworkFactoryInfo nfi : mNetworkFactoryInfos.values()) {
                nfi.asyncChannel.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK, score, 0, networkRequest);
            }
        }
        此時資料網路會再次進行分值對比,並發現自己的分值的確低於目標WIFI分值
        private void evalRequest(NetworkRequestInfo n) {
            if (n.requested == false && n.score < mScore &&
                    n.request.networkCapabilities.satisfiedByNetworkCapabilities(
                        mCapabilityFilter) && acceptRequest(n.request, n.score)) {
                needNetworkFor(n.request, n.score);
                n.requested = true;
            } else if (n.requested == true &&
                    (n.score > mScore || n.request.networkCapabilities.satisfiedByNetworkCapabilities(mCapabilityFilter) == false || acceptRequest(n.request, n.score) == false)) {
                releaseNetworkFor(n.request);
                n.requested = false;
            }
        }
        然後資料網路就進行releaseNetworkFor操作
        @DcTracker.java
        protected void releaseNetworkFor(NetworkRequest networkRequest) {
            ApnContext apnContext = apnContextForNetworkRequest(networkRequest);
            if (apnContext != null) apnContext.decRefCount();
        }
        而APN引數被刪掉時將會觸發資料業務的關閉
        @ApnContext.java
        public void decRefCount() {
            synchronized (mRefCountLock) {
                if (mRefCount-- == 1) {
                    //關閉資料業務
                    mDcTracker.setEnabled(mDcTracker.apnTypeToId(mApnType), false);
                }
            }
        }
        然後資料業務就被關閉,從而完成網路切換的任務。