admin 管理员组

文章数量: 887021

前言:
本文介绍了android下网络的评分机制,同时分析wifi连接国内ap时,重新打开wifi后,wifi不回连ap的问题,并提供解决方法。

android下可以有多种网络存在,如:wifi、mobile network、ethernet、bt-pan。而对于上层应用来说,只会看到一个连通的网络,在多个网络同时存在的情况下,android就需要一套评分机制来选择一个当前使用的网络,当那个网络的分值高时,就优先使用那个网络。
Android下各种网络的分值在NetworkAgentInfo.java中管理,保存在currentScore中,各种网络初始化时会设置自己的分值。

Wifi初始分值为60(WifiStateMachine.java);
Ethernet初始分值为70(EthernetNetworkFactory.java);
Mobile network初始分值为50(DataConnection.java);
bt-pan初始分值为69(BluetoothTetheringNetworkFactory.java):
bt-pan的分值比wifi还高,这比较奇怪,已知的bt-pan网速都比较慢,google出于什么原因设计成这样?就不清楚了。

在实际运行中,还会根据网络的实时状态调整分值。

ethernet根据网卡的up和down状态,把分值设置为70(NETWORK_SCORE)或0。

(EthernetNetworkFactory.java)
mNetworkAgent.sendNetworkScore(mLinkUp? NETWORK_SCORE : 0); 

而wifi的分值还跟信号状态、当前数据速率等一系列因素有关:
Wifi的分值计算在WifiStateMachine.java的calculateWifiScore函数中进行,初始计算的基础分值为:int score = 56;根据wifi网络的状态,进行小的加减,最后,如果分值大于60(NetworkAgent.WIFI_BASE_SCORE),就把分值设置为60。
上面设置的分值计算,只考虑网络是否连接好,至于连接的网络是否能连接上internet,还没加入考虑。如wifi已经连接上ap,而该ap是否能连接上internet,就没在这里考虑。
上面设置的网络分值,是最终保存在NetworkAgentInfo类中的分值,而在获取网络分值时,还会根据网络是否连接上internet,是否用户指定使用的网络,返回经过计算后的分值。

NetworkAgentInfo.java
    private int getCurrentScore(boolean pretendValidated) {
        // TODO: We may want to refactor this into a NetworkScore class that takes a base score from
        // the NetworkAgent and signals from the NetworkAgent and uses those signals to modify the
        // score.  The NetworkScore class would provide a nice place to centralize score constants
        // so they are not scattered about the transports.
        int score = currentScore;
        if (!everValidated && !pretendValidated) score -= UNVALIDATED_SCORE_PENALTY;
        if (score < 0) score = 0;
        if (networkMisc.explicitlySelected) score = EXPLICITLY_SELECTED_NETWORK_SCORE;
        return score;
    }
如果需要根据网络是否连通internet,就进行if (!everValidated && !pretendValidated) score -= UNVALIDATED_SCORE_PENALTY(40);处理,当网络与internet不通时,分值减去40。如果是用户指定使用的网络,直接返回分值if (networkMisc.explicitlySelected) score = EXPLICITLY_SELECTED_NETWORK_SCORE;(100)。
pretendValidated参数确定是否认为当前网络就是与internet连通的。everValidated表示当前网络与internet是否连通的标志。networkMisc.explicitlySelected为用户是否指定使用当前网络的标志,在用户手动连接ap的时候,该标志就会被设置,所以这时候的分值比ethernet还高,就会优先选择wifi作为首选网络。但在开关wifi后,自动连接上ap时,该标志就不会设置。

最后,分析一下everValidated标志是由哪里设置的,这里以wifi作为例子分析。
在连接wifi的过程中,当WifiStateMachine进入L2ConnectedState时,就会创建:
    mNetworkAgent = new WifiNetworkAgent(getHandler().getLooper(), mContext,
                    "WifiNetworkAgent", mNetworkInfo, mNetworkCapabilitiesFilter,
                    mLinkProperties, 60);
在WifiNetworkAgent初始化时,把everValidated设置为false,而当网络断开连接时,就会注销WifiNetworkAgent:
        if (mNetworkAgent != null) {
            mNetworkAgent.sendNetworkInfo(mNetworkInfo);
            mNetworkAgent = null;
        }
所以在每次连接网络后,都会重新设置everValidated,断开网络时就会清除。
创建WifiNetworkAgent时,在WifiNetworkAgent内创建了NetworkMonitor, NetworkMonitor就是一个检测网络的状态机,状态机包含下面状态,初始状态为mDefaultState,检测网络是否与internet连通就是在该状态机中实现。
        addState(mDefaultState);
        addState(mOfflineState, mDefaultState);
        addState(mValidatedState, mDefaultState);
        addState(mMaybeNotifyState, mDefaultState);
            addState(mEvaluatingState, mMaybeNotifyState);
            addState(mCaptivePortalState, mMaybeNotifyState);
        addState(mLingeringState, mDefaultState);
        setInitialState(mDefaultState);
当网络与internet连通时,NetworkMonitor所走的状态机如下图:

当进入mValidatedState时,就会给connectivity发送消息:
   mConnectivityServiceHandler.sendMessage(obtainMessage(EVENT_NETWORK_TESTED,

NETWORK_TEST_RESULT_VALID, mNetwork3gTestResultIsFake,
mNetworkAgentInfo));
connectivity对NETWORK_TEST_RESULT_VALID消息进行处理时,就会设置everValidated为true。

检测网络是否连通的代码如下:
            
            
            

本文标签: 不回 评分 机制 国内 网络