(1)android下可以有多种网络存在,如:wifi、mobile network、ethernet、bt-pan。而对于上层应用来说,只会看到一个连通的网络,在多个网络同时存在的情况下,android就需要一套评分机制来选择一个当前使用的网络,当那个网络的分值高时,就优先使用那个网络。Android专门设计了一套管理方法来实现上面的这种机制,包括ConnectivityManager、ConnectivityService、NetworkAgent等对象之间的关系以及消息流走向,其中ConnectivityService是管理员身份,没种网络都会去向它注册,网络的使用权全靠它来分配。
(2)Android下各种网络的分值在NetworkAgentInfo.java中管理,保存在currentScore中,各种网络初始化时会设置自己的分值。

Wifi初始分值为60(WifiStateMachine.java); 
Ethernet初始分值为70(EthernetNetworkFactory.java); 
Mobile network初始分值为50(DataConnection.java); 
bt-pan初始分值为69(BluetoothTetheringNetworkFactory.java): 
在实际运行中,还会根据网络的实时状态调整分值。

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时,该标志就不会设置。

下面我们利用三个部分来分析评分机制的原理: 
1、NetworkFactory 
2、NetworkAgent 
3、NetworkMonitor 


1、NetworkFactory

NetworkFactory直译就是网络工厂,开机之后每种网络都必须注册自己的NetworkFactory,NetworkFactory的作用是用来创建NetworkAgent,同时作为ConnectivityService与网络之间的通讯枢纽

private DctController(PhoneProxy[] phones) {    for (int i = 0; i < mPhoneNum; ++i) {        // Register for radio state change        PhoneBase phoneBase = (PhoneBase)mPhones[i].getActivePhone();        updatePhoneBaseForIndex(i, phoneBase);    }}    private void updatePhoneBaseForIndex(int index, PhoneBase phoneBase) {    phoneBase.getServiceStateTracker().registerForDataConnectionAttached(mRspHandler,               EVENT_DATA_ATTACHED + index, null);    phoneBase.getServiceStateTracker().registerForDataConnectionDetached(mRspHandler,               EVENT_DATA_DETACHED + index, null);    mNetworkFilter[index] = new NetworkCapabilities();    mNetworkFilter[index].addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);    mNetworkFilter[index].addCapability(NetworkCapabilities.NET_CAPABILITY_MMS);    mNetworkFilter[index].addCapability(NetworkCapabilities.NET_CAPABILITY_SUPL);    mNetworkFilter[index].addCapability(NetworkCapabilities.NET_CAPABILITY_DUN);    mNetworkFilter[index].addCapability(NetworkCapabilities.NET_CAPABILITY_FOTA);    mNetworkFilter[index].addCapability(NetworkCapabilities.NET_CAPABILITY_IMS);    mNetworkFilter[index].addCapability(NetworkCapabilities.NET_CAPABILITY_CBS);    mNetworkFilter[index].addCapability(NetworkCapabilities.NET_CAPABILITY_IA);    mNetworkFilter[index].addCapability(NetworkCapabilities.NET_CAPABILITY_RCS);    mNetworkFilter[index].addCapability(NetworkCapabilities.NET_CAPABILITY_XCAP);    mNetworkFilter[index].addCapability(NetworkCapabilities.NET_CAPABILITY_EIMS);    mNetworkFilter[index].addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);    mNetworkFilter[index].addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);    mNetworkFactory[index] = new TelephonyNetworkFactory(this.getLooper(),            mPhones[index].getContext(), "TelephonyNetworkFactory", phoneBase,            mNetworkFilter[index]);    mNetworkFactory[index].setScoreFilter(50);    mNetworkFactoryMessenger[index] = new Messenger(mNetworkFactory[index]);    cm.registerNetworkFactory(mNetworkFactoryMessenger[index], "Telephony");}

可以看出来一个NetworkFactory 支持多种网络类型(NetworkCapabilities),网络类型与APN的TYPE相对应。 
以移动数据网络为例,TelephonyNetworkFactory 将会继承NetworkFactory ,并重写其中两个重要的方法,needNetworkFor和releaseNetworkFor,这两个方法就是ConnectivityService与移动网络之间桥梁,分别负责请求当前网络和断开当前网络。
 

private class TelephonyNetworkFactory extends NetworkFactory {    protected void needNetworkFor(NetworkRequest networkRequest, int score) {        // figure out the apn type and enable it        if (!SubscriptionManager.isUsableSubIdValue(mPhone.getSubId())) {            mPendingReq.put(networkRequest.requestId, networkRequest);            return;        }        if (getRequestPhoneId(networkRequest) == mPhone.getPhoneId()) {             DcTrackerBase dcTracker =((PhoneBase)mPhone).mDcTracker;            String apn = apnForNetworkRequest(networkRequest);            if (dcTracker.isApnSupported(apn)) {                requestNetwork(networkRequest, dcTracker.getApnPriority(apn));            }        } else {            mPendingReq.put(networkRequest.requestId, networkRequest);        }    }      protected void releaseNetworkFor(NetworkRequest networkRequest) {        if (!SubscriptionManager.isUsableSubIdValue(mPhone.getSubId())) {            mPendingReq.remove(networkRequest.requestId);            return;        }        if (getRequestPhoneId(networkRequest) == mPhone.getPhoneId()) {             DcTrackerBase dcTracker =((PhoneBase)mPhone).mDcTracker;            String apn = apnForNetworkRequest(networkRequest);            if (dcTracker.isApnSupported(apn)) {                releaseNetwork(networkRequest);            }        }    }     

再看NetworkFactory 的注册cm.registerNetworkFactory(mNetworkFactoryMessenger[index], “Telephony”);其中mNetworkFactoryMessenger是一个包装了mNetworkFactory的Messenger对象,这个主要是建立AsyncChannel通道时用。
 

@ConnectivityService.javapublic void registerNetworkFactory(Messenger messenger, String name) {    enforceConnectivityInternalPermission();    NetworkFactoryInfo nfi = new NetworkFactoryInfo(name, messenger, new AsyncChannel());    mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_FACTORY, nfi));}

handleRegisterNetworkFactory处理EVENT_REGISTER_NETWORK_FACTORY消息

private void handleRegisterNetworkFactory(NetworkFactoryInfo nfi) {    mNetworkFactoryInfos.put(nfi.messenger, nfi);    nfi.asyncChannel.connect(mContext, mTrackerHandler, nfi.messenger);}

在这里,ConnectivityService做了两个事情: 
1、将新注册的NetworkFactoryInfo 保存到mNetworkFactoryInfos中; 
2、利用刚才创建的AsyncChannel向NetworkAgent发起单向连接请求; 
nfi.asyncChannel.connect(mContext, mTrackerHandler, nfi.messenger);即利用传入的Messenger对象建立起ConnectivityService与NetworkFactory的通讯通道,ConnectivityService后续的消息都将通过这个asyncChannel传入到数据网络中的NetworkFactory。 
当asyncChannel通道建立成功后ConnectivityService会收到CMD_CHANNEL_HALF_CONNECTED消息。

@Overridepublic void handleMessage(Message msg) {    NetworkInfo info;    switch (msg.what) {        case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: {            handleAsyncChannelHalfConnect(msg);            break;        }}

 

private void handleAsyncChannelHalfConnect(Message msg) {    AsyncChannel ac = (AsyncChannel) msg.obj;    if (mNetworkFactoryInfos.containsKey(msg.replyTo)) {  //此时是链接的是NetworkFactory,走这个path        if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {            // A network factory has connected.  Send it all current NetworkRequests.            for (NetworkRequestInfo nri : mNetworkRequests.values()) {                if (nri.isRequest == false) continue;                NetworkAgentInfo nai = mNetworkForRequestId.get(nri.request.requestId);                ac.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK,(nai != null ? nai.getCurrentScore() : 0), 0, nri.request);            }        } else {            mNetworkFactoryInfos.remove(msg.obj);        }    } else if (mNetworkAgentInfos.containsKey(msg.replyTo)) {    }}

此时是链接的是NetworkFactory,走这个path,mNetworkFactoryInfos是在handleRegisterNetworkFactory时保存的。 
在这里,ConnectivityService通过AsyncChannel通道向当前的NetworkFactory发起CMD_REQUEST_NETWORK的请求,需要注意的是,该请求所附带的第二个参数选择,由于当前处于初始化阶段,因此当前的mNetworkForRequestId中为空,也就是说此时传递的第二个参数必然为0。 
我们接下来看NetworkFactory收到该请求时的处理:
 

@NetworkFactory.javapublic void handleMessage(Message msg) {    switch (msg.what) {        case CMD_REQUEST_NETWORK: {            handleAddRequest((NetworkRequest)msg.obj, msg.arg1);            break;        }    }}
private void handleAddRequest(NetworkRequest request, int score) {    NetworkRequestInfo n = mNetworkRequests.get(request.requestId);    if (n == null) {        if (DBG) log("got request " + request + " with score " + score);        n = new NetworkRequestInfo(request, score);        mNetworkRequests.put(n.request.requestId, n);    } else {        n.score = score;    }    evalRequest(n);}

接下来评估网络评分,是需要链接网络还是断开网路

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;    } }

该逻辑就是整个网络评价系统最关键的地方,如果NetworkRequestInfo没有被requested过,并且其分值(n.score)小于当前NetworkFactory自己的分值(mScore),那么就说明,当前NetworkFactory所处的网络优先级高于其他网络的优先级,就会触发当前NetworkFactory所在网络的needNetworkFor()流程,也就是连接建立流程,并将标记NetworkRequestInfo.requested=true。 
当NetworkRequestInfo被requested过(也就是当前网络被needNetworkFor过),此时如果再次收到请求,并且携带的新score大于当前NetworkFactory所处网络的mScore,那么就说明当前NetworkFactory所在网络优先级已经不是最高,需要将其releaseNetworkFor掉,并标记NetworkRequestInfo.requested=false。

evalRequest中调用TelephonyNetworkFactory 重写的needNetworkFor或者releaseNetworkFor,分别是链接网络和断开网络,后续的流程如下图(请求网络的情况) 

在此数据链接的NetworkFactory算是创建完毕,并将自己注册到ConnectivityService中。

2、NetworkAgent

前面提到NetworkFactory是在系统初始化时就被创建,而NetworkAgent是在真正接入网络时才会创建,NetworkAgent的创建在DataConnection状态机里的DcActiveState状态时。

private class DcActiveState extends State {    @Override public void enter() {        // If we were retrying there maybe more than one, otherwise they'll only be one.        notifyAllOfConnected(Phone.REASON_CONNECTED);        mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED,                mNetworkInfo.getReason(), null);        mNetworkInfo.setExtraInfo(mApnSetting.apn);        updateTcpBufferSizes(mRilRat);        final NetworkMisc misc = new NetworkMisc();        misc.subscriberId = mPhone.getSubscriberId();        mNetworkAgent = new DcNetworkAgent(getHandler().getLooper(), mPhone.getContext(),                "DcNetworkAgent", mNetworkInfo, makeNetworkCapabilities(), mLinkProperties,                50, misc);    }}
public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni,        NetworkCapabilities nc, LinkProperties lp, int score, NetworkMisc misc) {    super(looper);    mContext = context;    ConnectivityManager cm = (ConnectivityManager)mContext.getSystemService(            Context.CONNECTIVITY_SERVICE);    cm.registerNetworkAgent(new Messenger(this), new NetworkInfo(ni),            new LinkProperties(lp), new NetworkCapabilities(nc), score, misc);}  

当网络链接完成之后,就会新建一个DcNetworkAgent,接着分析NetworkAgent的构造,和NetworkFactory类似,也是将自己注册到ConnectivityService中去,继续看registerNetworkAgent

public void registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo,        LinkProperties linkProperties, NetworkCapabilities networkCapabilities,        int currentScore, NetworkMisc networkMisc) {    NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(),        new NetworkInfo(networkInfo), new LinkProperties(linkProperties),        new NetworkCapabilities(networkCapabilities), currentScore, mContext, mTrackerHandler,        new NetworkMisc(networkMisc), mDefaultRequest);    synchronized (this) {        nai.networkMonitor.systemReady = mSystemReady;    }    mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_AGENT, nai));}private void handleRegisterNetworkAgent(NetworkAgentInfo na) {    mNetworkAgentInfos.put(na.messenger, na);    assignNextNetId(na);    na.asyncChannel.connect(mContext, mTrackerHandler, na.messenger);    NetworkInfo networkInfo = na.networkInfo;    na.networkInfo = null;    updateNetworkInfo(na, networkInfo);}

在这里,ConnectivityService做了三个事情: 
1、将新注册的NetworkAgentInfo保存到mNetworkAgentInfos中; 
2、利用刚才创建的AsyncChannel向NetworkAgent发起单向连接请求; 
3、更新最新的NetworkAgentInfo状态;

@Overridepublic void handleMessage(Message msg) {    NetworkInfo info;    switch (msg.what) {        case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: {            handleAsyncChannelHalfConnect(msg);            break;        }}

以上流程和NetworkFactory注册时几乎一模一样的模式

private void handleAsyncChannelHalfConnect(Message msg) {    AsyncChannel ac = (AsyncChannel) msg.obj;    if (mNetworkFactoryInfos.containsKey(msg.replyTo)) {      }  else if (mNetworkAgentInfos.containsKey(msg.replyTo)) {  //此时是链接的是NetworkAgent,走这个path        if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {            // A network agent has requested a connection.  Establish the connection.            mNetworkAgentInfos.get(msg.replyTo).asyncChannel.                    sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);        }     }}

唯一的区别是在handleAsyncChannelHalfConnect中这里,当ConnectivityService与NetworkAgent之间单向通道建立完成后,又发起了双向通道的请求,此时在NetworkAgent端,将会收到CMD_CHANNEL_FULL_CONNECTION的消息,建立双向通道的目的是,有时候网络也需要通过AsyncChannel向ConnectivityService发送消息。至此,NetworkAgent的初始化完毕。 
现在的问题是NetworkAgent如何影响网络链接的? 
NetworkAgent提供了两种方法更新评分管理: 
1、sendNetworkScore

public void sendNetworkScore(int score) {    queueOrSendMessage(EVENT_NETWORK_SCORE_CHANGED, new Integer(score));}

2、sendNetworkInfo

public void sendNetworkInfo(NetworkInfo networkInfo) {    queueOrSendMessage(EVENT_NETWORK_INFO_CHANGED, new NetworkInfo(networkInfo));}

先来分析第二种情况,比如移动数据网络的断开时就会调用此方法:

@DataConnection.javaprivate class DcActiveState extends State {    public void exit() {        mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED,                mNetworkInfo.getReason(), mNetworkInfo.getExtraInfo());        mNetworkAgent.sendNetworkInfo(mNetworkInfo);        mNetworkAgent = null;    }}

接着就会进入ConnectivityService

@Overridepublic void handleMessage(Message msg) {    NetworkInfo info;        case NetworkAgent.EVENT_NETWORK_INFO_CHANGED: {            NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo);            info = (NetworkInfo) msg.obj;            updateNetworkInfo(nai, info);            break;        }}
private void updateNetworkInfo(NetworkAgentInfo networkAgent, NetworkInfo newInfo) {    if (state == NetworkInfo.State.CONNECTED && !networkAgent.created) {    } else if (state == NetworkInfo.State.DISCONNECTED || state == NetworkInfo.State.SUSPENDED) {        networkAgent.asyncChannel.disconnect();            }   

由于是断开数据网络,因此这里是断开AsyncChannel,从而进入

AsyncChannel.CMD_CHANNEL_DISCONNECTED        @Override        public void handleMessage(Message msg) {            NetworkInfo info;            switch (msg.what) {                case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {                    handleAsyncChannelDisconnected(msg);                    break;                }        }
private void handleAsyncChannelDisconnected(Message msg) {      NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo);      if (nai != null) {          //删掉当前NetworkAgent对象          mNetworkAgentInfos.remove(msg.replyTo);          final ArrayList toActivate = new ArrayList();          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);              }          }      }  }  
private void sendUpdatedScoreToFactories(NetworkRequest networkRequest, int score) {    for (NetworkFactoryInfo nfi : mNetworkFactoryInfos.values()) {        nfi.asyncChannel.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK, score, 0,networkRequest);    }}

在这里,由于当前连接是断开状态,因此其分值必然为0,这样就把他的0分值通知到各个NetworkFactory中,由NetworkFactory判断是否需要开启自己的网络,通知方法同样是CMD_REQUEST_NETWORK,也就是说,无论是直接更新NetworkAgent中的分数,还是更新NetworkAgent的状态,最终都会触发NetworkFactory中的评分机制。

3、NetworkMonitor

NetworkMonitor的构造是在注册NetworkAgent,构造NetworkAgentInfo是创建的,其实质ping网络是在updateNetworkInfo中,细节不分析,但是NetworkMonitor对网络可用性的评分是有影响的,即当网络链接上之后,会去ping当前网络是否可用,如果不可用则会影响getCurrentScore获取的分数值,getCurrentScore是每次网络评分获取的分数的必经之路:

private int getCurrentScore(boolean pretendValidated) {    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;}

当一个网络连接建立时,系统将用该连接Ping一个Google的网站来判断该连接是否真的可以上网,如果不可以,那么就会扣掉该网络40分,从而可能导致该网络的评分低于其他网络评分 
如果是用户指定了网络那么分数直接等于EXPLICITLY_SELECTED_NETWORK_SCORE(100分) 
 

更多相关文章

  1. GoogleIO 2013 Android快速联网框架Volley介绍
  2. Android(安卓)项目实践(二)——网络连接
  3. Android(安卓)客户端与服务器交互方式
  4. adb 无线调试
  5. Android中LocationManager的简单使用,获取当前位置
  6. Android(安卓)网络安全配置
  7. Android(安卓)P/9.0 http网络请求异常
  8. Android(安卓)网络:Retrofit 与 Kotlin 协程
  9. Android(安卓)SIP 网络通话

随机推荐

  1. 获取Android(安卓)System 写入权限
  2. [日更-2019.4.22、23、24] cm-14.1 Andro
  3. Android下引用系统库的方法及问题
  4. 【Android】Android中两种常用布局(Linear
  5. 解决AndroidStudio连不上Android设备真机
  6. android中简单的Handler与Message
  7. Android(安卓)Drawable 那些不为人知的高
  8. Android(安卓)逆向apk程序的心得
  9. Android框架理解之USB
  10. Android(安卓)自定义上面圆角下面直角的I