网络连接评分机制之NetworkAgent

        前面介绍了开机过程中各个网络提供者的初始化过程,其实就是创建自己的NetworkFactory,并将其注册到ConnectivityService。而在介绍NetworkFactory的时候,我们看到该类的官方注释中有这么一句描述:
  1. "A NetworkFactory is an entity that creates NetworkAgent objects."  
        "A NetworkFactory is an entity that creates NetworkAgent objects."
        这说明NetworkFactory的主要作用还是用来创建NetworkAgent的,那么NetworkAgent是什么对象,而NetworkFactory与NetworkAgent又是什么关系呢?

        我们接下来介绍NetworkAgent。


一、NetworkAgent介绍


        其实在上一个文档《 Framework中的连接管理机制》中已经介绍过NetworkAgent相关知识了,现在我们来从另一个角度分析一下该对象的作用。
        从刚才NetworkFactory的注释我们知道,NetworkAgent是被NetworkFactory创建的,这里的创建并不是说在NetworkFactory内部创建NetworkAgent,而是说, 在NetworkFactory这个环境就绪之后,网络提供者才可以创建NetworkAgent。并且在一个NetworkFactory中可以创建不同的NetworkAgent,他们拥有不同的Capabilities等参数。
        而他们之间还有一个区别就是,NetworkFactory是在 系统初始化时就被创建,而NetworkAgent是在 真正接入网络时才会创建。
        我们用运营商之间的关系来比喻他们的关系。
        NetworkFactory相当于不同的运营商,比如中国电信、铁通、移动,他们具备联通互联网的能力,当用户入网时就决定了自己的运营商(即完成NetworkFactory初始化)。但同时在每个运营商内部又创建各个不同的接入点,比如对于中国电信来说,还分为上海电信、河北电信等,只有当用户打开电脑真正上网的时候,才会被分配具体的接入点(即完成NetworkAgent初始化)。
        也就是说,同一个NetworkFactory可以在不同的时刻根据需要创建不同的NetworkAgent,比如使用数据上网时,会根据当前的需要(发送MMS还是IMS,或者单纯上网)来创建不同参数的NetworkAgent(不同的APN参数)对象,然后将其注册到ConnectivityService中。

        下面我们跟踪一下数据连接的创建过程来看一下NetworkAgent的使用。


二、NetworkAgent创建过程


        当数据连接建立成功时,就会在DataConnection中进入DcActiveState的状态机,然后就会创建数据连接的NetworkAgent对象:
  1. @DataConnection.java  
  2. private class DcActiveState extends State {  
  3.     @Override public void enter() {  
  4.         mRetryManager.restoreCurMaxRetryCount();  
  5.         mDcController.addActiveDcByCid(DataConnection.this);  
  6.         //更新当前的NetworkInfo状态  
  7.         mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, mNetworkInfo.getReason(), null);  
  8.         mNetworkInfo.setExtraInfo(mApnSetting.apn);  
  9.         updateTcpBufferSizes(mRilRat);  
  10.         //数据建立成功,创建并注册NetworkAgent  
  11.         mNetworkAgent = new DcNetworkAgent(getHandler().getLooper(), mPhone.getContext(),  
  12.                 "DcNetworkAgent", mNetworkInfo, makeNetworkCapabilities(), mLinkProperties,  
  13.                 50);  
  14.     }  
  15. }  
        @DataConnection.java
        private class DcActiveState extends State {
            @Override public void enter() {
                mRetryManager.restoreCurMaxRetryCount();
                mDcController.addActiveDcByCid(DataConnection.this);
                //更新当前的NetworkInfo状态
                mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, mNetworkInfo.getReason(), null);
                mNetworkInfo.setExtraInfo(mApnSetting.apn);
                updateTcpBufferSizes(mRilRat);
                //数据建立成功,创建并注册NetworkAgent
                mNetworkAgent = new DcNetworkAgent(getHandler().getLooper(), mPhone.getContext(),
                        "DcNetworkAgent", mNetworkInfo, makeNetworkCapabilities(), mLinkProperties,
                        50);
            }
        }
        我们看到,当数据连接建立成功后,就会更新当前的NetworkInfo( 点击这里了解NetworkInfo),然后创建当前的NetworkAgent,并把NetworkInfo传递给NetworkAgent。
        下面我们来看NetworkAgent的创建过程:
  1. @NetworkAgent.java  
  2. public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni, NetworkCapabilities nc, LinkProperties lp, int score, NetworkMisc misc) {  
  3.     super(looper);  
  4.     LOG_TAG = logTag;  
  5.     mContext = context;  
  6.     if (ni == null || nc == null || lp == null) {  
  7.         throw new IllegalArgumentException();  
  8.     }  
  9.   
  10.   
  11.     ConnectivityManager cm = (ConnectivityManager)mContext.getSystemService( Context.CONNECTIVITY_SERVICE);  
  12.     cm.registerNetworkAgent(new Messenger(this), new NetworkInfo(ni), new LinkProperties(lp), new NetworkCapabilities(nc), score, misc);  
  13. }  
        @NetworkAgent.java
        public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni, NetworkCapabilities nc, LinkProperties lp, int score, NetworkMisc misc) {
            super(looper);
            LOG_TAG = logTag;
            mContext = context;
            if (ni == null || nc == null || lp == null) {
                throw new IllegalArgumentException();
            }


            ConnectivityManager cm = (ConnectivityManager)mContext.getSystemService( Context.CONNECTIVITY_SERVICE);
            cm.registerNetworkAgent(new Messenger(this), new NetworkInfo(ni), new LinkProperties(lp), new NetworkCapabilities(nc), score, misc);
        }
        在NetworkAgent的创建过程中,只做了一件事情,就是将其注册到ConnectivityService中,而这里传递的参数包含当前NetworkAgent的Messenger(用于与ConnectivityService之间建立AsyncChannel通道)、传递进来的NetworkInfo、NetworkCapabilities、以及当前连接的分数score等。
        然后我们继续来看在ConnectivityService中的注册过程:
  1. @ConnectivityService.java  
  2. public void registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo, LinkProperties linkProperties, NetworkCapabilities networkCapabilities, int currentScore, NetworkMisc networkMisc) {  
  3.     //权限检查  
  4.     enforceConnectivityInternalPermission();  
  5.   
  6.   
  7.     NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(),  
  8.             new NetworkInfo(networkInfo), new LinkProperties(linkProperties),  
  9.             new NetworkCapabilities(networkCapabilities), currentScore, mContext, mTrackerHandler,  
  10.             new NetworkMisc(networkMisc));  
  11.     synchronized (this) {  
  12.         nai.networkMonitor.systemReady = mSystemReady;  
  13.     }  
  14.     mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_AGENT, nai));  
  15. }  
        @ConnectivityService.java
        public void registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo, LinkProperties linkProperties, NetworkCapabilities networkCapabilities, int currentScore, NetworkMisc networkMisc) {
            //权限检查
            enforceConnectivityInternalPermission();


            NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(),
                    new NetworkInfo(networkInfo), new LinkProperties(linkProperties),
                    new NetworkCapabilities(networkCapabilities), currentScore, mContext, mTrackerHandler,
                    new NetworkMisc(networkMisc));
            synchronized (this) {
                nai.networkMonitor.systemReady = mSystemReady;
            }
            mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_AGENT, nai));
        }
        我们看到,当NetworkAgent注册时,在ConnectivityService的内部创建了一个新的对象NetworkAgentInfo,该对象中保留了传递进来的一系列参数,包括NetworkAgent的Messenger对象、NetworkInfo、NetworkCapabilities、score以及创建了一个用于通讯的AsyncChannel通道。
        然后就把当前创建的NetworkAgentInfo对象放入EVENT_REGISTER_NETWORK_AGENT消息中,发送给Handler处理:
  1. @ConnectivityService.java  
  2. private class InternalHandler extends Handler {  
  3.     public void handleMessage(Message msg) {  
  4.         NetworkInfo info;  
  5.         switch (msg.what) {  
  6.             case EVENT_REGISTER_NETWORK_AGENT: {  
  7.                handleRegisterNetworkAgent((NetworkAgentInfo)msg.obj);  
  8.                break;  
  9.            }  
  10.         }  
  11.     }  
  12. }  
        @ConnectivityService.java
        private class InternalHandler extends Handler {
            public void handleMessage(Message msg) {
                NetworkInfo info;
                switch (msg.what) {
                    case EVENT_REGISTER_NETWORK_AGENT: {
                       handleRegisterNetworkAgent((NetworkAgentInfo)msg.obj);
                       break;
                   }
                }
            }
        }
        继续:
  1. private void handleRegisterNetworkAgent(NetworkAgentInfo na) {  
  2.     //将NetworkAgentInfo放入mNetworkAgentInfos中  
  3.     mNetworkAgentInfos.put(na.messenger, na);  
  4.     assignNextNetId(na);  
  5.     //发起连接请求  
  6.     na.asyncChannel.connect(mContext, mTrackerHandler, na.messenger);  
  7.     NetworkInfo networkInfo = na.networkInfo;  
  8.     na.networkInfo = null;  
  9.     //更新最新的NetworkInfo  
  10.     updateNetworkInfo(na, networkInfo);  
  11. }  
        private void handleRegisterNetworkAgent(NetworkAgentInfo na) {
            //将NetworkAgentInfo放入mNetworkAgentInfos中
            mNetworkAgentInfos.put(na.messenger, na);
            assignNextNetId(na);
            //发起连接请求
            na.asyncChannel.connect(mContext, mTrackerHandler, na.messenger);
            NetworkInfo networkInfo = na.networkInfo;
            na.networkInfo = null;
            //更新最新的NetworkInfo
            updateNetworkInfo(na, networkInfo);
        }
        在这里,ConnectivityService做了三个事情:
        1、将新注册的NetworkAgentInfo保存到mNetworkAgentInfos中;
        2、利用刚才创建的AsyncChannel向NetworkAgent发起单向连接请求
        3、更新最新的NetworkAgentInfo状态;

        我们主要关注第二个过程,而第三个过程将会在接下来小节中介绍。
        根据AsyncChannel的原理( 不懂的点这里),此时ConnectivityService发起的是单向的AsyncChannel连接,发起后将会在mTrackerHandler中收到CMD_CHANNEL_HALF_CONNECTED的消息:
  1. @ConnectivityService.java  
  2. private class NetworkStateTrackerHandler extends Handler {  
  3.     public void handleMessage(Message msg) {  
  4.         NetworkInfo info;  
  5.         switch (msg.what) {  
  6.             case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: {  
  7.               handleAsyncChannelHalfConnect(msg);  
  8.               break;  
  9.            }  
  10.         }  
  11.     }  
  12. }  
        @ConnectivityService.java
        private class NetworkStateTrackerHandler extends Handler {
            public void handleMessage(Message msg) {
                NetworkInfo info;
                switch (msg.what) {
                    case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: {
                      handleAsyncChannelHalfConnect(msg);
                      break;
                   }
                }
            }
        }
        然后来看详细处理:
  1. private void handleAsyncChannelHalfConnect(Message msg) {  
  2.     AsyncChannel ac = (AsyncChannel) msg.obj;  
  3.     if (mNetworkFactoryInfos.containsKey(msg.replyTo)) {  
  4.     } else if (mNetworkAgentInfos.containsKey(msg.replyTo)) {  
  5.         if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {  
  6.             //向NetworkAgent发起双向连接请求  
  7.             mNetworkAgentInfos.get(msg.replyTo).asyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);  
  8.         } else {  
  9.         }  
  10.     }  
  11. }  
        private void handleAsyncChannelHalfConnect(Message msg) {
            AsyncChannel ac = (AsyncChannel) msg.obj;
            if (mNetworkFactoryInfos.containsKey(msg.replyTo)) {
            } else if (mNetworkAgentInfos.containsKey(msg.replyTo)) {
                if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
                    //向NetworkAgent发起双向连接请求
                    mNetworkAgentInfos.get(msg.replyTo).asyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
                } else {
                }
            }
        }
        我们看到,当ConnectivityService与NetworkAgent之间单向通道建立完成后, 又发起了双向通道的请求,此时在NetworkAgent端,将会收到CMD_CHANNEL_FULL_CONNECTION的消息:
  1. @NetworkAgent.java  
  2. public void handleMessage(Message msg) {  
  3.     switch (msg.what) {  
  4.         case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: {  
  5.            if (mAsyncChannel != null) {  
  6.            } else {  
  7.                AsyncChannel ac = new AsyncChannel();  
  8.                ac.connected(nullthis, msg.replyTo);  
  9.                //连接建立成功  
  10.                ac.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED, AsyncChannel.STATUS_SUCCESSFUL);  
  11.                synchronized (mPreConnectedQueue) {  
  12.                    mAsyncChannel = ac;  
  13.                    for (Message m : mPreConnectedQueue) {  
  14.                        //如果有缓存消息,则发送出去  
  15.                        ac.sendMessage(m);  
  16.                    }  
  17.                    mPreConnectedQueue.clear();  
  18.                }  
  19.            }  
  20.            break;  
  21.        }  
  22.     }  
  23. }  
        @NetworkAgent.java
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: {
                   if (mAsyncChannel != null) {
                   } else {
                       AsyncChannel ac = new AsyncChannel();
                       ac.connected(null, this, msg.replyTo);
                       //连接建立成功
                       ac.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED, AsyncChannel.STATUS_SUCCESSFUL);
                       synchronized (mPreConnectedQueue) {
                           mAsyncChannel = ac;
                           for (Message m : mPreConnectedQueue) {
                               //如果有缓存消息,则发送出去
                               ac.sendMessage(m);
                           }
                           mPreConnectedQueue.clear();
                       }
                   }
                   break;
               }
            }
        }
        从NetworkAgent的消息处理中我们看到他收到请求之后就发送了建立成功的消息,然后检测消息队列,如果有消息就及时向ConnectivityService传递。

        至此,NetworkAgent的初始化完毕。


三、NetworkAgent更新过程


        前面第二节我们分析过,NetworkFactory是在系统初始化时就被创建,并赋予初始的分值, 当有新的网络请求更新过来时,将其所携带的分值与当前NetworkFactory的分值比较,如果低于当前NetworkFactory,将会触发NetworkFactory内部建立连接的流程,反之将会触发NetworkFactory释放连接的流程
        那么网络请求中的分值来自于哪里呢?其实就是来自于NetworkAgent。

        在网络连接过程中,根据网络情况,各个网络的NetworkFactory可以修改当前的NetworkAgent分值,此操作将会把最新的分值广播到系统内所有的NetworkFactory中,从而引发上面描述的评分过程,而更新NetworkAgent分值有两种方式,分别是:直接更新分值、通过sendNetworkInfo更新。下面我们分别来看这两种过程。


3.1、直接更新分值过程


        直接更新分值是通过NetworkAgent的 sendNetworkScore()方法实现的。所有的NetworkAgent对象,都可以通过这个方法来直接更新当前的NetworkAgent分值,对于WIFI环境来说,会根据当前的WIFI信号强度、速率、干扰等参数动态调节当前的NetworkAgent分值,其实现是在calculateWifiScore()完成的:
  1. @WifiStateMachine.java  
  2. private void calculateWifiScore(WifiLinkLayerStats stats) {  
  3.     //初始值56  
  4.     int score = 56// Starting score, temporarily hardcoded in between 50 and 60  
  5.   
  6.   
  7.     if (isBadLinkspeed) {  
  8.         //网速过低,扣4分  
  9.         score -= 4 ;  
  10.     } else if ((isGoodLinkspeed) && (mWifiInfo.txSuccessRate > 5)) {  
  11.         //否则加4分  
  12.         score += 4// So as bad rssi alone dont kill us  
  13.     }  
  14.     score -= mWifiInfo.badRssiCount * 2 +  mWifiInfo.lowRssiCount ;  
  15.     //是否干扰太大  
  16.     if (isHighRSSI) {  
  17.         score += 5;  
  18.     }  
  19.     //调整分值,最大为60,最小为0  
  20.     if (score > NetworkAgent.WIFI_BASE_SCORE)  
  21.         score = NetworkAgent.WIFI_BASE_SCORE;  
  22.     if (score < 0)  
  23.         score = 0;  
  24.     if (score != mWifiInfo.score) {  
  25.         mWifiInfo.score = score;  
  26.         if (mNetworkAgent != null) {  
  27.             //更新当前分值  
  28.             mNetworkAgent.sendNetworkScore(score);  
  29.         }  
  30.     }  
  31. }  
        @WifiStateMachine.java
        private void calculateWifiScore(WifiLinkLayerStats stats) {
            //初始值56
            int score = 56; // Starting score, temporarily hardcoded in between 50 and 60


            if (isBadLinkspeed) {
                //网速过低,扣4分
                score -= 4 ;
            } else if ((isGoodLinkspeed) && (mWifiInfo.txSuccessRate > 5)) {
                //否则加4分
                score += 4; // So as bad rssi alone dont kill us
            }
            score -= mWifiInfo.badRssiCount * 2 +  mWifiInfo.lowRssiCount ;
            //是否干扰太大
            if (isHighRSSI) {
                score += 5;
            }
            //调整分值,最大为60,最小为0
            if (score > NetworkAgent.WIFI_BASE_SCORE)
                score = NetworkAgent.WIFI_BASE_SCORE;
            if (score < 0)
                score = 0;
            if (score != mWifiInfo.score) {
                mWifiInfo.score = score;
                if (mNetworkAgent != null) {
                    //更新当前分值
                    mNetworkAgent.sendNetworkScore(score);
                }
            }
        }
        在上面这个方法中,我们看到最终的分数将会通过sendNetworkScore方法更新到NetworkAgent中:
  1. @NetworkAgent.java  
  2. public void sendNetworkScore(int score) {  
  3.     if (score < 0) {  
  4.         throw new IllegalArgumentException("Score must be >= 0");  
  5.     }  
  6.     queueOrSendMessage(EVENT_NETWORK_SCORE_CHANGED, new Integer(score));  
  7. }  
        @NetworkAgent.java
        public void sendNetworkScore(int score) {
            if (score < 0) {
                throw new IllegalArgumentException("Score must be >= 0");
            }
            queueOrSendMessage(EVENT_NETWORK_SCORE_CHANGED, new Integer(score));
        }
        继续:
  1. private void queueOrSendMessage(int what, Object obj) {  
  2.     synchronized (mPreConnectedQueue) {  
  3.         if (mAsyncChannel != null) {  
  4.             mAsyncChannel.sendMessage(what, obj);  
  5.         } else {  
  6.             Message msg = Message.obtain();  
  7.             msg.what = what;  
  8.             msg.obj = obj;  
  9.             mPreConnectedQueue.add(msg);  
  10.         }  
  11.     }  
  12. }  
        private void queueOrSendMessage(int what, Object obj) {
            synchronized (mPreConnectedQueue) {
                if (mAsyncChannel != null) {
                    mAsyncChannel.sendMessage(what, obj);
                } else {
                    Message msg = Message.obtain();
                    msg.what = what;
                    msg.obj = obj;
                    mPreConnectedQueue.add(msg);
                }
            }
        }
        我们看到,NetworkAgent将会把最新的分值封装到EVENT_NETWORK_SCORE_CHANGED消息中,通过AsyncChannel发送出去,而这里的AsyncChannel通道就是当初NetworkAgent向ConnectivityService注册时由ConnectivityService发起的双向通道,也就是说,该消息将会被ConnectivityService中的mTrackerHandler处理:
  1. @ConnectivityService.java  
  2. private class NetworkStateTrackerHandler extends Handler {  
  3.     public void handleMessage(Message msg) {  
  4.         NetworkInfo info;  
  5.         switch (msg.what) {  
  6.             case NetworkAgent.EVENT_NETWORK_SCORE_CHANGED: {  
  7.                NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo);  
  8.                if (nai == null) {  
  9.                    break;  
  10.                }  
  11.                Integer score = (Integer) msg.obj;  
  12.                //更新ConnectivityService中的NetworkAgent分值  
  13.                if (score != null) updateNetworkScore(nai, score.intValue());  
  14.                break;  
  15.            }  
  16.         }  
  17.     }  
  18. }  
        @ConnectivityService.java
        private class NetworkStateTrackerHandler extends Handler {
            public void handleMessage(Message msg) {
                NetworkInfo info;
                switch (msg.what) {
                    case NetworkAgent.EVENT_NETWORK_SCORE_CHANGED: {
                       NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo);
                       if (nai == null) {
                           break;
                       }
                       Integer score = (Integer) msg.obj;
                       //更新ConnectivityService中的NetworkAgent分值
                       if (score != null) updateNetworkScore(nai, score.intValue());
                       break;
                   }
                }
            }
        }
        在ConnectivityService收到该消息后,就通过updateNetworkScore方法来更新NetworkAgent分值:
  1. private void updateNetworkScore(NetworkAgentInfo nai, int score) {  
  2.     if (score < 0) {  
  3.         score = 0;  
  4.     }  
  5.     final int oldScore = nai.getCurrentScore();  
  6.     //将分值更新到NetworkAgentInfo中  
  7.     nai.setCurrentScore(score);  
  8.     //触发评分机制  
  9.     if (nai.created) rematchAllNetworksAndRequests(nai, oldScore);  
  10.     //将当前最新分值更新到每个NetworkFactory中  
  11.     sendUpdatedScoreToFactories(nai);  
  12. }  
        private void updateNetworkScore(NetworkAgentInfo nai, int score) {
            if (score < 0) {
                score = 0;
            }
            final int oldScore = nai.getCurrentScore();
            //将分值更新到NetworkAgentInfo中
            nai.setCurrentScore(score);
            //触发评分机制
            if (nai.created) rematchAllNetworksAndRequests(nai, oldScore);
            //将当前最新分值更新到每个NetworkFactory中
            sendUpdatedScoreToFactories(nai);
        }
        在这个过程中,ConnectivityService将会把最新的分值更新到NetworkAgentInfo中,最后通过sendUpdatedScoreToFactories方法将此评分送达到每个NetworkFactory中。
        但是该过程还有一个重要的作用,就是通过rematchAllNetworksAndRequests方法将当前的NetworkRequest分配给合适的NetworkAgent,最后把当前最合适的NetworkAgent分数同步给所有的NetworkFactory。
  1. private void rematchNetworkAndRequests(NetworkAgentInfo newNetwork, boolean nascent) {  
  2.     for (NetworkRequestInfo nri : mNetworkRequests.values()) {  
  3.         //寻找当前NetworkRequest所使用的NetworkAgent  
  4.         if (nri.request.networkCapabilities.satisfiedByNetworkCapabilities( newNetwork.networkCapabilities)) {  
  5.             //如果当前NetworkRequest使用的NetworkAgent分数低于新的NetworkAgent分数,将会用新的NetworkAgent替代  
  6.             if (currentNetwork == null || currentNetwork.getCurrentScore() < newNetwork.getCurrentScore()) {  
  7.                 //找到新的NetworkAgent替代方案  
  8.                 if (currentNetwork != null) {  
  9.                     if (DBG) log("   accepting network in place of " + currentNetwork.name());  
  10.                     currentNetwork.networkRequests.remove(nri.request.requestId);  
  11.                     currentNetwork.networkLingered.add(nri.request);  
  12.                     affectedNetworks.add(currentNetwork);  
  13.                 } else {  
  14.                     if (DBG) log("   accepting network in place of null");  
  15.                 }  
  16.                 mNetworkForRequestId.put(nri.request.requestId, newNetwork);  
  17.                 newNetwork.addRequest(nri.request);  
  18.                 if (nri.isRequest && nri.request.legacyType != TYPE_NONE) {  
  19.                     mLegacyTypeTracker.add(nri.request.legacyType, newNetwork);  
  20.                 }  
  21.                 keep = true;  
  22.                 //将分数更新到各个NetworkFactory中  
  23.                 sendUpdatedScoreToFactories(nri.request, newNetwork.getCurrentScore());  
  24.             }  
  25.         }  
  26.     }  
  27. }  
        private void rematchNetworkAndRequests(NetworkAgentInfo newNetwork, boolean nascent) {
            for (NetworkRequestInfo nri : mNetworkRequests.values()) {
                //寻找当前NetworkRequest所使用的NetworkAgent
                if (nri.request.networkCapabilities.satisfiedByNetworkCapabilities( newNetwork.networkCapabilities)) {
                    //如果当前NetworkRequest使用的NetworkAgent分数低于新的NetworkAgent分数,将会用新的NetworkAgent替代
                    if (currentNetwork == null || currentNetwork.getCurrentScore() < newNetwork.getCurrentScore()) {
                        //找到新的NetworkAgent替代方案
                        if (currentNetwork != null) {
                            if (DBG) log("   accepting network in place of " + currentNetwork.name());
                            currentNetwork.networkRequests.remove(nri.request.requestId);
                            currentNetwork.networkLingered.add(nri.request);
                            affectedNetworks.add(currentNetwork);
                        } else {
                            if (DBG) log("   accepting network in place of null");
                        }
                        mNetworkForRequestId.put(nri.request.requestId, newNetwork);
                        newNetwork.addRequest(nri.request);
                        if (nri.isRequest && nri.request.legacyType != TYPE_NONE) {
                            mLegacyTypeTracker.add(nri.request.legacyType, newNetwork);
                        }
                        keep = true;
                        //将分数更新到各个NetworkFactory中
                        sendUpdatedScoreToFactories(nri.request, newNetwork.getCurrentScore());
                    }
                }
            }
        }
        我们再看一下通知NetworkFactory的方法:
  1. private void sendUpdatedScoreToFactories(NetworkRequest networkRequest, int score) {  
  2.     for (NetworkFactoryInfo nfi : mNetworkFactoryInfos.values()) {  
  3.         //将分值发送到各个NetworkFactory  
  4.         nfi.asyncChannel.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK, score, 0, networkRequest);  
  5.     }  
  6. }  
        private void sendUpdatedScoreToFactories(NetworkRequest networkRequest, int score) {
            for (NetworkFactoryInfo nfi : mNetworkFactoryInfos.values()) {
                //将分值发送到各个NetworkFactory
                nfi.asyncChannel.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK, score, 0, networkRequest);
            }
        }

        至此,ConnectivityService就将最新的NetworkAgent分值通过AsyncChannel通道发送给各个NetworkFactory,由NetworkFactory来决定自己的网络是否需要建立连接或者释放连接。


3.2、间接更新分值过程


        间接更新过程是指,当NetworkAgent的其他状态(比如是否漫游、是否可用、连接状态等)发生改变时,可以通过 sendNetworkInfo方法来将最新的NetworkAgent通知到ConnectivityService,此过程最终也会触发评分机制。
        比如当WIFI被关闭时,将会把WIFI的状态置为断开状态,然后通知到ConnectivityService:
  1. @WifiStateMachine.java  
  2. private void handleNetworkDisconnect() {  
  3.     //断开时,状态应该设置为DISCONNECTED  
  4.     setNetworkDetailedState(DetailedState.DISCONNECTED);  
  5. }  
        @WifiStateMachine.java
        private void handleNetworkDisconnect() {
            //断开时,状态应该设置为DISCONNECTED
            setNetworkDetailedState(DetailedState.DISCONNECTED);
        }
        将WIFI状态更新为DISCONNECTED:
  1. private boolean setNetworkDetailedState(NetworkInfo.DetailedState state) {  
  2.     if (state != mNetworkInfo.getDetailedState()) {  
  3.         //将DISCONNECTED状态更新到WIFI的NetworkAgent中  
  4.         mNetworkInfo.setDetailedState(state, null, mWifiInfo.getSSID());  
  5.         if (mNetworkAgent != null) {  
  6.             //将NetworkAgent更新到ConnectivityService中  
  7.             mNetworkAgent.sendNetworkInfo(mNetworkInfo);  
  8.         }  
  9.         return true;  
  10.     }  
  11.     return false;  
  12. }  
        private boolean setNetworkDetailedState(NetworkInfo.DetailedState state) {
            if (state != mNetworkInfo.getDetailedState()) {
                //将DISCONNECTED状态更新到WIFI的NetworkAgent中
                mNetworkInfo.setDetailedState(state, null, mWifiInfo.getSSID());
                if (mNetworkAgent != null) {
                    //将NetworkAgent更新到ConnectivityService中
                    mNetworkAgent.sendNetworkInfo(mNetworkInfo);
                }
                return true;
            }
            return false;
        }
        我们看到,最终通过sendNetworkInfo方法将最新的NetworkInfo更新到NetworkAgent中:
  1. @NetworkAgent.java  
  2. public void sendNetworkInfo(NetworkInfo networkInfo) {  
  3.     queueOrSendMessage(EVENT_NETWORK_INFO_CHANGED, new NetworkInfo(networkInfo));  
  4. }  
        @NetworkAgent.java
        public void sendNetworkInfo(NetworkInfo networkInfo) {
            queueOrSendMessage(EVENT_NETWORK_INFO_CHANGED, new NetworkInfo(networkInfo));
        }
        与sendNetworkScore类似,NetworkAgent也将把最新的NetworkInfo通过AsyncChannel消息同步到ConnectivityService中:
  1. @ConnectivityService.java  
  2. private class NetworkStateTrackerHandler extends Handler {  
  3.     public void handleMessage(Message msg) {  
  4.         NetworkInfo info;  
  5.         switch (msg.what) {  
  6.             case NetworkAgent.EVENT_NETWORK_INFO_CHANGED: {  
  7.               NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo);  
  8.               info = (NetworkInfo) msg.obj;  
  9.               updateNetworkInfo(nai, info);  
  10.               break;  
  11.           }  
  12.         }  
  13.     }  
  14. }  
        @ConnectivityService.java
        private class NetworkStateTrackerHandler extends Handler {
            public void handleMessage(Message msg) {
                NetworkInfo info;
                switch (msg.what) {
                    case NetworkAgent.EVENT_NETWORK_INFO_CHANGED: {
                      NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo);
                      info = (NetworkInfo) msg.obj;
                      updateNetworkInfo(nai, info);
                      break;
                  }
                }
            }
        }
        ConnectivityService通过updateNetworkInfo来更新NetworkInfo:
  1. private void updateNetworkInfo(NetworkAgentInfo networkAgent, NetworkInfo newInfo) {  
  2.     NetworkInfo.State state = newInfo.getState();  
  3.     NetworkInfo oldInfo = null;  
  4.     synchronized (networkAgent) {  
  5.         oldInfo = networkAgent.networkInfo;  
  6.         networkAgent.networkInfo = newInfo;  
  7.     }  
  8.     if (state == NetworkInfo.State.CONNECTED && !networkAgent.created) {  
  9.         //网络连接上  
  10.         networkAgent.created = true;  
  11.         updateLinkProperties(networkAgent, null);  
  12.         notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_PRECHECK);  
  13.         networkAgent.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_CONNECTED);  
  14.         rematchNetworkAndRequests(networkAgent, false);  
  15.     } else if (state == NetworkInfo.State.DISCONNECTED || state == NetworkInfo.State.SUSPENDED) {  
  16.         //网络断开  
  17.         networkAgent.asyncChannel.disconnect();  
  18.     }  
  19. }  
        private void updateNetworkInfo(NetworkAgentInfo networkAgent, NetworkInfo newInfo) {
            NetworkInfo.State state = newInfo.getState();
            NetworkInfo oldInfo = null;
            synchronized (networkAgent) {
                oldInfo = networkAgent.networkInfo;
                networkAgent.networkInfo = newInfo;
            }
            if (state == NetworkInfo.State.CONNECTED && !networkAgent.created) {
                //网络连接上
                networkAgent.created = true;
                updateLinkProperties(networkAgent, null);
                notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_PRECHECK);
                networkAgent.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_CONNECTED);
                rematchNetworkAndRequests(networkAgent, false);
            } else if (state == NetworkInfo.State.DISCONNECTED || state == NetworkInfo.State.SUSPENDED) {
                //网络断开
                networkAgent.asyncChannel.disconnect();
            }
        }
        在这里我们看到,updateNetworkInfo的方法中将会对最新状态进行分类,如果是连接状态,则会触发rematchNetworkAndRequests,这个过程将会和上面直接更新分值的过程一致,而如果是断开状态,则直接把AsyncChannel通道断开即可,此时将会在ConnectivityService中收到CMD_CHANNEL_DISCONNECTED的消息:
  1. private class NetworkStateTrackerHandler extends Handler {  
  2.     public void handleMessage(Message msg) {  
  3.         NetworkInfo info;  
  4.         switch (msg.what) {  
  5.             case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {  
  6.                 handleAsyncChannelDisconnected(msg);  
  7.                 break;  
  8.             }  
  9.         }  
  10.     }  
  11. }  
        private class NetworkStateTrackerHandler extends Handler {
            public void handleMessage(Message msg) {
                NetworkInfo info;
                switch (msg.what) {
                    case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
                        handleAsyncChannelDisconnected(msg);
                        break;
                    }
                }
            }
        }
        然后进入handleAsyncChannelDisconnected方法:
  1. private void handleAsyncChannelDisconnected(Message msg) {  
  2.     NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo);  
  3.     if (nai != null) {  
  4.         //删掉当前NetworkAgent对象  
  5.         mNetworkAgentInfos.remove(msg.replyTo);  
  6.         final ArrayList<NetworkAgentInfo> toActivate = new ArrayList<NetworkAgentInfo>();  
  7.         for (int i = 0; i < nai.networkRequests.size(); i++) {  
  8.             NetworkRequest request = nai.networkRequests.valueAt(i);  
  9.             NetworkAgentInfo currentNetwork = mNetworkForRequestId.get(request.requestId);  
  10.             if (currentNetwork != null && currentNetwork.network.netId == nai.network.netId) {  
  11.                 mNetworkForRequestId.remove(request.requestId);  
  12.                 //将0分更新到各个NetworkFactory中  
  13.                 sendUpdatedScoreToFactories(request, 0);  
  14.             }  
  15.         }  
  16.     }  
  17. }  
        private void handleAsyncChannelDisconnected(Message msg) {
            NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo);
            if (nai != null) {
                //删掉当前NetworkAgent对象
                mNetworkAgentInfos.remove(msg.replyTo);
                final ArrayList<NetworkAgentInfo> toActivate = new ArrayList<NetworkAgentInfo>();
                for (int i = 0; i < nai.networkRequests.size(); i++) {
                    NetworkRequest request = nai.networkRequests.valueAt(i);
                    NetworkAgentInfo currentNetwork = mNetworkForRequestId.get(request.requestId);
                    if (currentNetwork != null && currentNetwork.network.netId == nai.network.netId) {
                        mNetworkForRequestId.remove(request.requestId);
                        //将0分更新到各个NetworkFactory中
                        sendUpdatedScoreToFactories(request, 0);
                    }
                }
            }
        }
        在这里,由于当前连接是断开状态,因此其分值必然为0,这样就把他的0分值通知到各个NetworkFactory中,由NetworkFactory判断是否需要开启自己的网络。
        也就是说,无论是直接更新NetworkAgent中的分数,还是更新NetworkAgent的状态,最终都会触发NetworkFactory中的评分机制。
在Android中,Settings模块可以通过注册BroadcastReceiver来获取系统广播。其中,可以通过注册ACTION_NETWORK_STATE_CHANGED广播来获取网络状态变化的事件,包括NETWORK_NOT_FOUND_EVENT状态。 具体来说,可以在Settings模块中定义一个类继承BroadcastReceiver,然后在onReceive()方法中处理ACTION_NETWORK_STATE_CHANGED广播。在处理过程中,可以检查网络状态变化的extra数据,并根据其中包含的状态信息判断是否为NETWORK_NOT_FOUND_EVENT状态。 下面是一个示例代码: ``` public class NetworkStateReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) { NetworkInfo networkInfo = intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO); if (networkInfo != null && networkInfo.getState() == NetworkInfo.State.DISCONNECTED) { // 网络连接断开 } else if (networkInfo != null && networkInfo.getState() == NetworkInfo.State.CONNECTED) { // 网络连接成功 } } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) { int event = intent.getIntExtra(NetworkAgent.EVENT_NETWORK_STATUS_CHANGED, -1); if (event == NetworkAgent.EVENT_NETWORK_NOT_FOUND) { // 网络连接未找到 } } } } ``` 在以上代码中,可以通过判断intent的action来确定接收到的广播类型,然后根据extra数据中包含的信息来判断网络状态变化的类型。其中,如果接收到的广播类型为ACTION_NETWORK_STATE_CHANGED,则可以通过获取extra数据中的NetworkAgent.EVENT_NETWORK_STATUS_CHANGED来判断网络状态是否为NETWORK_NOT_FOUND_EVENT状态。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值