Platform: Rockchip
OS: Android 6.0
Kernel: 3.10.92
NetworkFactory作为网络评分机制中一个重要角色而存在,每个模块实现需要继承NetworkFactory
当Wifi状态机初始化处于默认状态时,会注册WifiNetworkFactory
processMessage -> WifiStateMachine.java//DefaultState
maybeRegisterNetworkFactory
void maybeRegisterNetworkFactory() {
if (mNetworkFactory == null) {
//连接ConnectivityService
checkAndSetConnectivityInstance();
if (mCm != null) {
//继承自NetworkFactory
mNetworkFactory = new WifiNetworkFactory(getHandler().getLooper(), mContext,
NETWORKTYPE, mNetworkCapabilitiesFilter);
//设置评分为60,后面在分析evalRequest会看到
mNetworkFactory.setScoreFilter(60);
//所有的NetworkFactory注册到ConnectivityService才能参与评分机制
mNetworkFactory.register();
}
}
}
上面过程设置评分和注册两个步骤
设置评分:
setScoreFilter -> sendMessage(CMD_SET_SCORE) -> handleMessage-> handleSetScore
private void handleSetScore(int score) {
//当前的score为60,初始化时关键是设置一个mScore值作为Wifi模块的标准值
mScore = score;
//当任何一个网络的score有变化时,需要重新评分来判断是否需要切换网络
evalRequests();
}
mScore在后面evalRequest()会用到,用于比较ConnectivityService传进来的score而去决定request还是release网络
private void evalRequests() {
//暂时mNetworkRequests为空,不作用
for (int i = 0; i < mNetworkRequests.size(); i++) {
NetworkRequestInfo n = mNetworkRequests.valueAt(i);
evalRequest(n);
}
}
注册:
register -> registerNetworkFactory
NetworkFactory.java
public void register() {
if (DBG) log("Registering NetworkFactory");
if (mMessenger == null) {
mMessenger = new Messenger(this);
ConnectivityManager.from(mContext).registerNetworkFactory(mMessenger, LOG_TAG);
}
}
调用service端,ConnectivityService.java
public void registerNetworkFactory(Messenger messenger, String name) {
enforceConnectivityInternalPermission();
//每个client会在server端创建一个NetworkFactoryInfo作为NetworkFactory的代表,并且包含了异步通道和messager信息
NetworkFactoryInfo nfi = new NetworkFactoryInfo(name, messenger, new AsyncChannel());
//把service端的NetworkFactoryInfo当做参数发给内部的InternalHandler处理
mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_FACTORY, nfi));
}
收到EVENT_REGISTER_NETWORK_FACTORY消息后处理:
handleMessage -> //InternalHandler类,处理EVENT_REGISTER_NETWORK_FACTORY
handleRegisterNetworkFactory ->
mNetworkFactoryInfos.put(nfi.messenger, nfi) //NetworkFactoryInfo被存到mNetworkFactoryInfos数组中
nfi.asyncChannel.connect -> //发起异步通道连接请求
handleMessage -> //异步通道对应处理的NetworkStateTrackerHandler类
handleAsyncChannelHalfConnect -> ConnectivityService.java //CMD_CHANNEL_HALF_CONNECTED
来看handleAsyncChannelHalfConnect():
private void handleAsyncChannelHalfConnect(Message msg)
{
AsyncChannel ac = (AsyncChannel) msg.obj;
//mNetworkFactoryInfos前面注册过了,因此条件成立
if (mNetworkFactoryInfos.containsKey(msg.replyTo)) {
if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
if (VDBG) log("NetworkFactory connected:"+mNetworkRequests.size());
// A network factory has connected. Send it all current NetworkRequests.
//这里的mNetworkRequests列表开始用的是构造函数ConnectivityService里的默认值
// NetworkRequestInfo defaultNRI = new NetworkRequestInfo(null, mDefaultRequest,new Binder(), NetworkRequestInfo.REQUEST);
// mNetworkRequests.put(mDefaultRequest, defaultNRI);
// mDefaultRequest被加入到mNetworkRequests中,类型是NetworkRequestInfo.REQUEST,请求网络类型
for (NetworkRequestInfo nri : mNetworkRequests.values()) {
//NetworkRequest分申请网络和监听网络用的,只处理申请网络,这里可以通过nri.toString()打印出来
if (nri.isRequest == false) continue;
//根据requestId取出NetworkRequest对应的NetworkAgentInfo,当网络处于连接状态时,这个值才会有
//比如wifi的NetworkAgent的子类是WifiNetworkAgent,只有在连接时即L2ConnectedState状态才会去
//创建,new WifiNetworkAgent(.....),其中参数就包含了score
NetworkAgentInfo nai = mNetworkForRequestId.get(nri.request.requestId);
//因此,第一次进来默认没连接上wifi(未连接状态)时第二个参数是为0的
ac.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK,
(nai != null ? nai.getCurrentScore() : 0), 0, nri.request);
}
} else {
loge("Error connecting NetworkFactory");
mNetworkFactoryInfos.remove(msg.obj);
}
} else if (mNetworkAgentInfos.containsKey(msg.replyTo)) {
......
}
}
接着通过异步通道发送消息到client,也就是NetworkFactory
ac.sendMessage -> //发送CMD_REQUEST_NETWORK给client端即wifi network factory
handleMessage -> NetworkFactory.java
handleAddRequest
protected void handleAddRequest(NetworkRequest request, int score) {
NetworkRequestInfo n = mNetworkRequests.get(request.requestId);
//第一次进来肯定是空,生成一个新的NetworkRequestInfo,保存到client的mNetworkRequests数组中
//注意这是client端的数据结构,只是和server端名字一样
if (n == null) {
if (DBG) log("got request " + request + " with score " + score);
n = new NetworkRequestInfo(request, score);
mNetworkRequests.put(n.request.requestId, n);
} else {
//否则只更新NetworkRequest的分数
if (VDBG) log("new score " + score + " for exisiting request " + request);
n.score = score;
}
if (VDBG) log(" my score=" + mScore + ", my filter=" + mCapabilityFilter);
//评估NetworkRequest
evalRequest(n);
}
private void evalRequest(NetworkRequestInfo n) {
if (VDBG) log("evalRequest");
//第一次进来n.requested为false,n.score为0,mScore是60
if (n.requested == false && n.score < mScore &&
n.request.networkCapabilities.satisfiedByNetworkCapabilities(
mCapabilityFilter) && acceptRequest(n.request, n.score)) {
if (VDBG) log(" needNetworkFor");
needNetworkFor(n.request, n.score);
//改变状态,表示已经申请过
n.requested = true;
//如果之前已经申请过了,而且当前申请的分数比mScore要大,那么就要释放网络
} else if (n.requested == true &&
(n.score > mScore || n.request.networkCapabilities.satisfiedByNetworkCapabilities(
mCapabilityFilter) == false || acceptRequest(n.request, n.score) == false)) {
if (VDBG) log("releaseNetworkFor");
releaseNetworkFor(n.request);
n.requested = false;
} else {
if (VDBG) log(" done");
}
}
对于evalRequest()函数,摘录一段网友的结论:
该逻辑就是整个网络评价系统最关键的地方,如果NetworkRequestInfo没有被requested过,并且其分值(n.score)小于当前NetworkFactory自己的分值(mScore),那么就说明,当前NetworkFactory所处的网络优先级高于其他网络的优先级,就会触发当前NetworkFactory所在网络的needNetworkFor()流程,也就是连接建立流程,并将标记NetworkRequestInfo.requested=true。
当NetworkRequestInfo被requested过(也就是当前网络被needNetworkFor过),此时如果再次收到请求,并且携带的新score大于当前NetworkFactory所处网络的mScore,那么就说明当前NetworkFactory所在网络优先级已经不是最高,需要将其releaseNetworkFor掉,并标记NetworkRequestInfo.requested=false。
申请网络函数needNetworkFor()被子类覆盖,调用wifi state machine中的WifiNetworkFactory
WifiStateMachine.java
protected void needNetworkFor(NetworkRequest networkRequest, int score) {
++mConnectionRequests;
}
最终的作用只是增加mConnectionRequests计数,而这个值会影响WiFi状态机是否去执行连接。也就是说默认情况下mConnectionRequests是不为0的
函数evalRequest()不仅仅是在这次默认初始化会调用,当任一模块比如有线网络连接更新评分机制时,ConnectivityService会通知所有注册了NetworkFactory的模块(也是通过发消息CMD_REQUEST_NETWORK的方式,最终调用到evalRequest())来让模块决定是否要去申请还是释放网络,而决定这一动作的标准值正式上面的mScore值。
关于为什么要用这样的方式而不是直接在ConnectivityService做比较,前辈给出了解释:
参考:
网络连接评分机制之NetworkFactory(原)
Android7.0 数据拨号前的准备工作