Android 9.0 网络评分之---NetworkFactory
Posted Mrsongs的心情杂货铺
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 9.0 网络评分之---NetworkFactory相关的知识,希望对你有一定的参考价值。
一、网络评分框架图
二、NetworkFactory 与ConnectivityService连接过程
拿以太网为例,以太网的网口检测类EthernetTracker 会在自己的构造函数中将以太网类型的networkfactory 注册到ConnectivityService中。
EthernetTracker(Context context, Handler handler)
mHandler = handler;
// The services we use.
IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
mNMService = INetworkManagementService.Stub.asInterface(b);
// Interface match regex.
mIfaceMatch = context.getResources().getString(
com.android.internal.R.string.config_ethernet_iface_regex);
// Read default Ethernet interface configuration from resources
final String[] interfaceConfigs = context.getResources().getStringArray(
com.android.internal.R.array.config_ethernet_interfaces);
for (String strConfig : interfaceConfigs)
parseEthernetConfig(strConfig);
mConfigStore = new EthernetConfigStore();
NetworkCapabilities nc = createNetworkCapabilities(true /* clear default capabilities */);
mFactory = new EthernetNetworkFactory(handler, context, nc);
mFactory.register();
NetworkFactory 中会的register 方法如下:
public void register()
if (DBG) log(“Registering NetworkFactory”);
if (mMessenger == null)
mMessenger = new Messenger(this);
ConnectivityManager.from(mContext).registerNetworkFactory(mMessenger, LOG_TAG);
ConnectivityService 中的registerNetworkFactory 方法。会为当前NetworkFactory创建一个NetworkFactoryInfo ,并通过mHandler 发送EVENT_REGISTER_NETWORK_FACTORY
从这里我们看到,在ConnectivityService中,利用当前的NetworkFactory创建NetworkFactoryInfo对象,该对象保存了当前网络连接的name、Messenger对象,并且为其创建了AsyncChannel。 接下来继续看注册过程:
@Override
public void registerNetworkFactory(Messenger messenger, String name)
enforceConnectivityInternalPermission();
NetworkFactoryInfo nfi = new NetworkFactoryInfo(name, messenger, new AsyncChannel());
mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_FACTORY, nfi));
NetworkFactoryInfo是ConnectivityService 的一个内部类,会保存当前的NetworkFactory 的messenger和asyncChannel 对象,这里name 就是EthernetNetworkFactory 里面定义的类型NETWORK_TYPE = “Ethernet”
private static class NetworkFactoryInfo
public final String name;
public final Messenger messenger;
public final AsyncChannel asyncChannel;
public NetworkFactoryInfo(String name, Messenger messenger, AsyncChannel asyncChannel)
this.name = name;
this.messenger = messenger;
this.asyncChannel = asyncChannel;
mHandler 是ConnectivityService 的一个内部类 InternalHandler
private class InternalHandler extends Handler
public InternalHandler(Looper looper)
super(looper);
@Override
public void handleMessage(Message msg)
switch (msg.what)
case EVENT_REGISTER_NETWORK_FACTORY:
handleRegisterNetworkFactory((NetworkFactoryInfo)msg.obj);
break;
到这里我们发现,ConnectivityService将当前的NetworkFactoryInfo保存到mNetworkFactoryInfos中,然后向当前的NetworkFactory发起AsyncChannel单向通道申请(AsyncChannel相关介绍见这里)。
申请成功时,将会向当前的mTrackerHandler发送CMD_CHANNEL_HALF_CONNECTED消息:
原文链接:https://blog.csdn.net/u010961631/article/details/48971431
这里面是通过AsyncChannel 让ConnectivityService 的mTrackerHandler 和NetworkFactory连接通信。
三、ConnectivityService 通过AsyncChannel与NetworkFactory 连接的详细过程
AsyncChannel 的客户端(ConnectivityService)发起connect请求,和NetworkFactory连接。所以AsyncChannel 就架起了客户端ConnectivityService 的mTrackerHandler与服务端NetworkFactory之间的桥梁。连接成功后,ConnectivityService会收到AsyncChannel.CMD_CHANNEL_HALF_CONNECTED 的message。当客户端接收到AsyncChannel.CMD_CHANNEL_HALF_CONNECTED消息后,说明当前的单项通道建立成功。此时的客户端可以通过sAsyncChannel的sendMessage()方法向服务端发送消息了。
原文链接:https://blog.csdn.net/u010961631/article/details/48179305
AsyncChannel 的例子:https://blog.csdn.net/u010961631/article/details/48179305
作为客户端,如果想要创建与服务端之间的AsyncChannel,需要做以下几个准备:
1、获取服务端的Messenger对象,该对象其实就是利用服务端的Handler构建的Messenger;
2、创建客户端自己的Handler对象;
3、创建AsyncChannel对象;
4、通过AsyncChannel对象,连接当前的Handler和服务端的Messenger,从而申请连接。
3.1 首先ConnectvityService 发起connect 连接 NetworkFactory
private void handleRegisterNetworkFactory(NetworkFactoryInfo nfi)
if (DBG) log("Got NetworkFactory Messenger for " + nfi.name);
mNetworkFactoryInfos.put(nfi.messenger, nfi);
nfi.asyncChannel.connect(mContext, mTrackerHandler, nfi.messenger);
3.2 连接成功后客户端ConnectivityService会收到服务端NetworkFactory发来的AsyncChannel.CMD_CHANNEL_HALF_CONNECTED
AsyncChannel的connected 方法实际上连接的是传入的客户端handler 和服务端messager。
代码路径:frameworks/base/core/java/com/android/internal/util/AsyncChannel.java
3.3 connect 方法如下,这里会执行connected()replyHalfConnected(STATUS_SUCCESSFUL)
public void connect(Context srcContext, Handler srcHandler, Messenger dstMessenger)
if (DBG) log(“connect srcHandler to the dstMessenger E”);
// We are connected
connected(srcContext, srcHandler, dstMessenger);
// Tell source we are half connected
replyHalfConnected(STATUS_SUCCESSFUL);
if (DBG) log("connect srcHandler to the dstMessenger X");
public void connected(Context srcContext, Handler srcHandler, Messenger dstMessenger)
if (DBG) log("connected srcHandler to the dstMessenger E");
// Initialize source fields
mSrcContext = srcContext;
mSrcHandler = srcHandler;
mSrcMessenger = new Messenger(mSrcHandler);
// Initialize destination fields
mDstMessenger = dstMessenger;
if (DBG) log("connected srcHandler to the dstMessenger X");
3.4 AsyncChannnel 的 replyHalfConnected 主要回复CMD_CHANNEL_HALF_CONNECTED MSG和添加msg.arg1为STATUS_SUCCESSFUL的参数
private void replyHalfConnected(int status)
Message msg = mSrcHandler.obtainMessage(CMD_CHANNEL_HALF_CONNECTED);
msg.arg1 = status;
msg.obj = this;
msg.replyTo = mDstMessenger;
if (!linkToDeathMonitor())
// Override status to indicate failure
msg.arg1 = STATUS_BINDING_UNSUCCESSFUL;
mSrcHandler.sendMessage(msg);
3.5 单向通道建立,ConnectivityService 收到AsyncChannel.STATUS_SUCCESSFUL 后发送网络请求android.net.NetworkFactory.CMD_REQUEST_NETWORK
private void handleAsyncChannelHalfConnect(Message msg)
AsyncChannel ac = (AsyncChannel) msg.obj;
if (mNetworkFactoryInfos.containsKey(msg.replyTo))
if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL)
if (VDBG) log(“NetworkFactory connected”);
// A network factory has connected. Send it all current NetworkRequests.
for (NetworkRequestInfo nri : mNetworkRequests.values())
if (nri.request.isListen()) continue;
NetworkAgentInfo nai = getNetworkForRequest(nri.request.requestId);
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))
if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL)
if (VDBG) log(“NetworkAgent connected”);
// A network agent has requested a connection. Establish the connection.
mNetworkAgentInfos.get(msg.replyTo).asyncChannel.
sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
else
loge(“Error connecting NetworkAgent”);
NetworkAgentInfo nai = mNetworkAgentInfos.remove(msg.replyTo);
if (nai != null)
final boolean wasDefault = isDefaultNetwork(nai);
synchronized (mNetworkForNetId)
mNetworkForNetId.remove(nai.network.netId);
mNetIdInUse.delete(nai.network.netId);
// Just in case.
mLegacyTypeTracker.remove(nai, wasDefault);
3.5 NetworkFactory 收到CMD_REQUEST_NETWORK请求。
@Override
public void handleMessage(Message msg)
switch (msg.what)
case CMD_REQUEST_NETWORK:
handleAddRequest((NetworkRequest)msg.obj, msg.arg1);
break;
3.6 handleAddRequest创建一个NetworkRequestInfo 对象将请求的ID保存起来并保存分数。
@VisibleForTesting
protected 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
if (VDBG) log(“new score " + score + " for exisiting request " + request);
n.score = score;
if (VDBG) log(” my score=” + mScore + “, my filter=” + mCapabilityFilter);
evalRequest(n);
3.7 然后评价该网络的分数是否可以用于上网
private void evalRequest(NetworkRequestInfo n)
if (VDBG) log(“evalRequest”);
// we always NEED each network for any network request
//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;
// 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");
//
该逻辑就是整个网络评价系统最关键的地方,如果NetworkRequestInfo没有被requested过,并且其分值(n.score)小于当前NetworkFactory自己的分值(mScore),那么就说明,当前NetworkFactory所处的网络优先级高于其他网络的优先级,就会触发当前NetworkFactory所在网络的needNetworkFor()流程,也就是连接建立流程,并将标记NetworkRequestInfo.requested=true。
当NetworkRequestInfo被requested过(也就是当前网络被needNetworkFor过),此时如果再次收到请求,并且携带的新score大于当前NetworkFactory所处网络的mScore,那么就说明当前NetworkFactory所在网络优先级已经不是最高,需要将其releaseNetworkFor掉,并标记NetworkRequestInfo.requested=false。
对于初始化流程来说,由于NetworkRequestInfo是刚才在handleAddRequest新创建的,所以其requested状态必然为false,而且我们前面提到,ConnectivityService发送CMD_REQUEST_NETWORK时携带的分值参数为0,并且对于数据网络来说,其mScore=50,因此此时的判定状态将会是:n.requested=false AND n.score < mScore。
也就是说,对于数据网络环境初始化过程来说,将会满足第一个if判断,进入needNetworkFor流程,也就是触发数据网络的建立。
至此,NetworkFactory注册流程结束。
四、ConnectivityService 的mTrackerHandler
mTrackerHandler是ConnectivityService定义的一个内部类Handler。里面主要处理maybeHandleAsyncChannelMessage(NetworkFactory), NetworkMonitor, NetworkAgentInfo和NetworkAgent 的消息。
@Override
public void handleMessage(Message msg)
if (!maybeHandleAsyncChannelMessage(msg) &&
!maybeHandleNetworkMonitorMessage(msg) &&
!maybeHandleNetworkAgentInfoMessage(msg))
maybeHandleNetworkAgentMessage(msg);
// must be stateless - things change under us.
private class NetworkStateTrackerHandler extends Handler
public NetworkStateTrackerHandler(Looper looper)
super(looper);
private boolean maybeHandleAsyncChannelMessage(Message msg)
switch (msg.what)
default:
return false;
case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
handleAsyncChannelHalfConnect(msg);
break;
case AsyncChannel.CMD_CHANNEL_DISCONNECT:
NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo);
if (nai != null) nai.asyncChannel.disconnect();
break;
case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
handleAsyncChannelDisconnected(msg);
break;
return true;
private void maybeHandleNetworkAgentMessage(Message msg)
NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo);
if (nai == null)
if (VDBG)
log(String.format("%s from unknown NetworkAgent", eventName(msg.what)));
return;
switch (msg.what)
case NetworkAgent.EVENT_NETWORK_CAPABILITIES_CHANGED:
final NetworkCapabilities networkCapabilities = (NetworkCapabilities) msg.obj;
if (networkCapabilities.hasCapability(NET_CAPABILITY_CAPTIVE_PORTAL) ||
networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED) ||
networkCapabilities.hasCapability(NET_CAPABILITY_FOREGROUND))
Slog.wtf(TAG, "BUG: " + nai + " has CS-managed capability.");
updateCapabilities(nai.getCurrentScore(), nai, networkCapabilities);
break;
case NetworkAgent.EVENT_NETWORK_PROPERTIES_CHANGED:
handleUpdateLinkProperties(nai, (LinkProperties) msg.obj);
break;
case NetworkAgent.EVENT_NETWORK_INFO_CHANGED:
NetworkInfo info = (NetworkInfo) msg.obj;
updateNetworkInfo(nai, info);
break;
case NetworkAgent.EVENT_NETWORK_SCORE_CHANGED:
Integer score = (Integer) msg.obj;
if (score != null) updateNetworkScore(nai, score.intValue());
break;
case NetworkAgent.EVENT_SET_EXPLICITLY_SELECTED:
if (nai.everConnected && !nai.networkMisc.explicitlySelected)
loge("ERROR: already-connected network explicitly selected.");
nai.networkMisc.explicitlySelected = true;
nai.networkMisc.acceptUnvalidated = (boolean) msg.obj;
break;
case NetworkAgent.EVENT_PACKET_KEEPALIVE:
mKeepaliveTracker.handleEventPacketKeepalive(nai, msg);
break;
private boolean maybeHandleNetworkMonitorMessage(Message msg)
switch (msg.what)
default:
return false;
case NetworkMonitor.EVENT_NETWORK_TESTED:
final NetworkAgentInfo nai = getNetworkAgentInfoForNetId(msg.arg2);
if (nai == null) break;
final boolean valid = (msg.arg1 == NetworkMonitor.NETWORK_TEST_RESULT_VALID);
final boolean wasValidated = nai.lastValidated;
final boolean wasDefault = isDefaultNetwork(nai);
final String redirectUrl = (msg.obj instanceof String) ? (String) msg.obj : "";
if (DBG)
final String logMsg = !TextUtils.isEmpty(redirectUrl)
? " with redirect to " + redirectUrl
: "";
log(nai.name() + " validation " + (valid ? "passed" : "failed") + logMsg);
if (valid != nai.lastValidated)
if (wasDefault)
metricsLogger().defaultNetworkMetrics().logDefaultNetworkValidity(
SystemClock.elapsedRealtime(), valid);
final int oldScore = nai.getCurrentScore();
nai.lastValidated = valid;
nai.everValidated |= valid;
updateCapabilities(oldScore, nai, nai.networkCapabilities);
// If score has changed, rebroadcast to NetworkFactories. b/17726566
if (oldScore != nai.getCurrentScore()) sendUpdatedScoreToFactories(nai);
if (valid) handleFreshlyValidatedNetwork(nai);
updateInetCondition(nai);
// Let the NetworkAgent know the state of its network
Bundle redirectUrlBundle = new Bundle();
redirectUrlBundle.putString(NetworkAgent.REDIRECT_URL_KEY, redirectUrl);
nai.asyncChannel.sendMessage(
NetworkAgent.CMD_REPORT_NETWORK_STATUS,
(valid ? NetworkAgent.VALID_NETWORK : NetworkAgent.INVALID_NETWORK),
0, redirectUrlBundle);
if (wasValidated && !nai.lastValidated)
nai.networkInfo.setDetailedState(NetworkInfo.DetailedState.SUSPENDED, null, null);
handleNetworkUnvalidated(nai);
else if(!wasValidated && nai.lastValidated)
nai.networkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null, null);
handleNetworkValidated(nai);
else if(!wasValidated && !nai.lastValidated)
if(!nai.everFirstUnvalidated)
log(nai.name() + " ever FRIST Unvalidated and notify SUSPENDED.");
nai.networkInfo.setDetailedState(NetworkInfo.DetailedState.SUSPENDED, null, null);
handleNetworkUnvalidated(nai);
nai.everFirstUnvalidated = true;
break;
case NetworkMonitor.EVENT_PROVISIONING_NOTIFICATION:
final int netId = msg.arg2;
final boolean visible = toBool(msg.arg1);
final NetworkAgentInfo nai = getNetworkAgentInfoForNetId(netId);
// If captive portal status has changed, update capabilities or disconnect.
if (nai != null && (visible != nai.lastCaptivePortalDetected))
final int oldScore = nai.getCurrentScore();
nai.lastCaptivePortalDetected = visible;
nai.everCaptivePortalDetected |= visible;
if (nai.lastCaptivePortalDetected &&
Settings.Global.CAPTIVE_PORTAL_MODE_AVOID == getCaptivePortalMode())
if (DBG) log("Avoiding captive portal network: " + nai.name());
nai.asyncChannel.sendMessage(
NetworkAgent.CMD_PREVENT_AUTOMATIC_RECONNECT);
teardownUnneededNetwork(nai);
break;
updateCapabilities(oldScore, nai, nai.networkCapabilities);
if (!visible)
mNotifier.clearNotification(netId);
else
if (nai == null)
loge("EVENT_PROVISIONING_NOTIFICATION from unknown NetworkMonitor");
break;
if (!nai.networkMisc.provisioningNotificationDisabled)
mNotifier.showNotification(netId, NotificationType.SIGN_IN, nai, null,
(PendingIntent) msg.obj, nai.networkMisc.explicitlySelected);
break;
case NetworkMonitor.EVENT_PRIVATE_DNS_CONFIG_RESOLVED:
final NetworkAgentInfo nai = getNetworkAgentInfoForNetId(msg.arg2);
if (nai == null) break;
updatePrivateDns(nai, (PrivateDnsConfig) msg.obj);
break;
return true;
private int getCaptivePortalMode()
return Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.CAPTIVE_PORTAL_MODE,
Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT);
private boolean maybeHandleNetworkAgentInfoMessage(Message msg)
switch (msg.what)
default:
return false;
case NetworkAgentInfo.EVENT_NETWORK_LINGER_COMPLETE:
NetworkAgentInfo nai = (NetworkAgentInfo) msg.obj;
if (nai != null && isLiveNetworkAgent(nai, msg.what))
handleLingerComplete(nai);
break;
return true;
@Override
public void handleMessage(Message msg)
if (!maybeHandleAsyncChannelMessage(msg) &&
!maybeHandleNetworkMonitorMessage(msg) &&
!maybeHandleNetworkAgentInfoMessage(msg))
maybeHandleNetworkAgentMessage(msg);
博客链接:https://blog.csdn.net/u010961631/article/details/48971431
以上是关于Android 9.0 网络评分之---NetworkFactory的主要内容,如果未能解决你的问题,请参考以下文章
Android 9.0 网络评分之---NetworkFactory
Android 9.0 网络评分之--NetworkAgent
Android 9.0 网络评分之--NetworkAgent
Android 9.0 网络评分之--NetworkAgent