Android9.0 网络评分之--NetworkMonitor
Posted Mrsongs的心情杂货铺
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android9.0 网络评分之--NetworkMonitor相关的知识,希望对你有一定的参考价值。
一、NetworkMonitor的初始化流程
ConnectivityService 中registerNetworkAgent 会创建一个NetworkAgentInfo ,而在NetworkAgentInfo 的构造函数中会创建NetworkMonitor
public int registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo,
LinkProperties linkProperties, NetworkCapabilities networkCapabilities,
int currentScore, NetworkMisc networkMisc)
enforceConnectivityInternalPermission();
LinkProperties lp = new LinkProperties(linkProperties);
lp.ensureDirectlyConnectedRoutes();
// TODO: Instead of passing mDefaultRequest, provide an API to determine whether a Network
// satisfies mDefaultRequest.
final NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities);
final NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(),
new Network(reserveNetId()), new NetworkInfo(networkInfo), lp, nc, currentScore,
mContext, mTrackerHandler, new NetworkMisc(networkMisc), mDefaultRequest, this);
// Make sure the network capabilities reflect what the agent info says.
nai.networkCapabilities = mixInCapabilities(nai, nc);
synchronized (this)
nai.networkMonitor.systemReady = mSystemReady;
final String extraInfo = networkInfo.getExtraInfo();
final String name = TextUtils.isEmpty(extraInfo)
? nai.networkCapabilities.getSSID() : extraInfo;
addValidationLogs(nai.networkMonitor.getValidationLogs(), nai.network, name);
if (DBG) log("registerNetworkAgent " + nai);
mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_AGENT, nai));
return nai.network.netId;
NetworkAgentInfo的构造函数中会调用mConnService.createNetworkMonitor创建Monitor
public NetworkAgentInfo(Messenger messenger, AsyncChannel ac, Network net, NetworkInfo info,
LinkProperties lp, NetworkCapabilities nc, int score, Context context, Handler handler,
NetworkMisc misc, NetworkRequest defaultRequest, ConnectivityService connService)
this.messenger = messenger;
asyncChannel = ac;
network = net;
networkInfo = info;
linkProperties = lp;
networkCapabilities = nc;
currentScore = score;
mConnService = connService;
mContext = context;
mHandler = handler;
networkMonitor = mConnService.createNetworkMonitor(context, handler, this, defaultRequest);
networkMisc = misc;
ConnectivityService中createNetworkMonitor
@VisibleForTesting
public NetworkMonitor createNetworkMonitor(Context context, Handler handler,
NetworkAgentInfo nai, NetworkRequest defaultRequest)
return new NetworkMonitor(context, handler, nai, defaultRequest);
NetwrokMonitor的构造函数中会添加各个状态
@VisibleForTesting
protected NetworkMonitor(Context context, Handler handler, NetworkAgentInfo networkAgentInfo,
NetworkRequest defaultRequest, IpConnectivityLog logger,
NetworkMonitorSettings settings)
// Add suffix indicating which NetworkMonitor we’re talking about.
super(TAG + networkAgentInfo.name());
// Logs with a tag of the form given just above, e.g.
// <timestamp> 862 2402 D NetworkMonitor/NetworkAgentInfo [WIFI () - 100]: ...
setDbg(VDBG);
mContext = context;
mMetricsLog = logger;
mConnectivityServiceHandler = handler;
mSettings = settings;
mNetworkAgentInfo = networkAgentInfo;
mNetwork = new OneAddressPerFamilyNetwork(networkAgentInfo.network());
mNetId = mNetwork.netId;
mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
mDefaultRequest = defaultRequest;
addState(mDefaultState);
addState(mMaybeNotifyState, mDefaultState);
addState(mEvaluatingState, mMaybeNotifyState);
addState(mCaptivePortalState, mMaybeNotifyState);
addState(mEvaluatingPrivateDnsState, mDefaultState);
addState(mValidatedState, mDefaultState);
setInitialState(mDefaultState);
mIsCaptivePortalCheckEnabled = getIsCaptivePortalCheckEnabled();
mUseHttps = getUseHttpsValidation();
mCaptivePortalUserAgent = getCaptivePortalUserAgent();
mCaptivePortalHttpsUrl = makeURL(getCaptivePortalServerHttpsUrl());
mCaptivePortalHttpUrl = makeURL(getCaptivePortalServerHttpUrl(settings, context));
mCaptivePortalFallbackUrls = makeCaptivePortalFallbackUrls();
mCaptivePortalFallbackSpecs = makeCaptivePortalFallbackProbeSpecs();
start();
NetworkMonitor 的各个状态
NetworkMonitor共有七个状态机,分别是:DefaultState、OfflineState、ValidatedState、EvaluatingState、UserPromptedState、CaptivePortalState、LingeringState。他们的作用是:
DefaultState
----这是默认的状态机,也是其他所有状态机的父状态,主要处理网络连接的主要状态变化,包括连接、断开、测试、延时等模式。
EvaluatingState
----验证状态,网络连上时,将会进入该状态,然后会Ping网络,判断当前网络有效性,并决定下一步是进入ValidatedState还是OfflineState或者UserPromptedState。
OfflineState
----脱机状态,当Ping网络时,始终没有任何回应时,就会进入该状态。
ValidatedState
----验证通过的状态,当Ping通网络时,说明当前的网络是通畅的,将会进入该状态。
UserPromptedState
----验证失败状态,当Ping网络时,网络给出了重定向异常,比如接入中国移动时会跳入移动的帐号认证页面,需要用户进行网络登录后才可以继续上网。此时一般需要在界面上提示用户。
CaptivePortalState
----当网络被测试失败时进入UserPromptedState后,用户可以通过发送ACTION_SIGN_IN_REQUESTED的消息来进入CaptivePortalState状态,该状态中将会监听ACTION_CAPTIVE_PORTAL_LOGGED_IN消息,并可直接由该消息指定进入ValidatedState或者OfflineState模式。
二、NetworkMonitor的工作流程:
首先在ConnectivityService中的UpdateNetworkInfo中,调用networkMonitor 发送CMD_NETWORK_CONNECTED
if (!networkAgent.everConnected && state == NetworkInfo.State.CONNECTED)
networkAgent.everConnected = true;
handlePerNetworkPrivateDnsConfig(networkAgent, mDnsManager.getPrivateDnsConfig());
updateLinkProperties(networkAgent, null);
notifyIfacesChangedForNetworkStats();
networkAgent.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_CONNECTED);
scheduleUnvalidatedPrompt(networkAgent);
然后我们看到NetworkMonitor中由DefaultState 进入了 EvaluatingState 状态
private class DefaultState extends State
@Override
public boolean processMessage(Message message)
switch (message.what)
case CMD_NETWORK_CONNECTED:
logNetworkEvent(NetworkEvent.NETWORK_CONNECTED);
transitionTo(mEvaluatingState);
return HANDLED;
在进入EvaluatingState 状态的时候会发送 CMD_REEVALUATE消息在内部处理我们,这个地方是ping网络的,原生的是ping WWW.Google.com ,这里定制ping的是8.8.8.8 。
private class EvaluatingState extends State
private int mReevaluateDelayMs;
private int mAttempts;
@Override
public void enter()
// If we have already started to track time spent in EvaluatingState
// don't reset the timer due simply to, say, commands or events that
// cause us to exit and re-enter EvaluatingState.
if (!mEvaluationTimer.isStarted())
mEvaluationTimer.start();
sendMessage(CMD_REEVALUATE, ++mReevaluateToken, 0);
if (mUidResponsibleForReeval != INVALID_UID)
TrafficStats.setThreadStatsUid(mUidResponsibleForReeval);
mUidResponsibleForReeval = INVALID_UID;
mReevaluateDelayMs = INITIAL_REEVALUATE_DELAY_MS;
mAttempts = 0;
@Override
public boolean processMessage(Message message)
switch (message.what)
case CMD_REEVALUATE:
if (message.arg1 != mReevaluateToken || mUserDoesNotWant)
return HANDLED;
// Don't bother validating networks that don't satisfy the default request.
// This includes:
// - VPNs which can be considered explicitly desired by the user and the
// user's desire trumps whether the network validates.
// - Networks that don't provide Internet access. It's unclear how to
// validate such networks.
// - Untrusted networks. It's unsafe to prompt the user to sign-in to
// such networks and the user didn't express interest in connecting to
// such networks (an app did) so the user may be unhappily surprised when
// asked to sign-in to a network they didn't want to connect to in the
// first place. Validation could be done to adjust the network scores
// however these networks are app-requested and may not be intended for
// general usage, in which case general validation may not be an accurate
// measure of the network's quality. Only the app knows how to evaluate
// the network so don't bother validating here. Furthermore sending HTTP
// packets over the network may be undesirable, for example an extremely
// expensive metered network, or unwanted leaking of the User Agent string.
if (!isValidationRequired())
validationLog("Network would not satisfy default request, not validating");
transitionTo(mValidatedState);
return HANDLED;
CaptivePortalProbeResult probeResult = isCaptivePortal();
if (probeResult.isSuccessful())
// Transit EvaluatingPrivateDnsState to get to Validated
// state (even if no Private DNS validation required).
transitionTo(mEvaluatingPrivateDnsState);
这里面会根据isCaptivePortal()的结果,最终会进入EvaluatingPrivateDnsState状态。
进入的时候会发送CMD_EVALUATE_PRIVATE_DNS消息,
private class EvaluatingPrivateDnsState extends State
private int mPrivateDnsReevalDelayMs;
private PrivateDnsConfig mPrivateDnsConfig;
@Override
public void enter()
mPrivateDnsReevalDelayMs = INITIAL_REEVALUATE_DELAY_MS;
mPrivateDnsConfig = null;
sendMessage(CMD_EVALUATE_PRIVATE_DNS);
@Override
public boolean processMessage(Message msg)
switch (msg.what)
case CMD_EVALUATE_PRIVATE_DNS:
if (inStrictMode())
//if (!isStrictModeHostnameResolved())
//resolveStrictModeHostname();
Log.d(TAG, "Evaluating [usb0] network availability.");
if (isStrictModeHostnameResolved())
Log.d(TAG, "Evaluating [usb0] network availability - [OK]");
//notifyPrivateDnsConfigResolved();
handlePrivateDnsEvaluationSuccess();
else
Log.d(TAG, "Evaluating [usb0] network availability - [NOK]");
handlePrivateDnsEvaluationFailure();
break;
//
// Look up a one-time hostname, to bypass caching.
//
// Note that this will race with ConnectivityService
// code programming the DNS-over-TLS server IP addresses
// into netd (if invoked, above). If netd doesn't know
// the IP addresses yet, or if the connections to the IP
// addresses haven't yet been validated, netd will block
// for up to a few seconds before failing the lookup.
//if (!sendPrivateDnsProbe())
//handlePrivateDnsEvaluationFailure();
//break;
//
// All good!
transitionTo(mValidatedState);
break;
default:
return NOT_HANDLED;
return HANDLED;
isStrictModeHostnameResolved 主要是ping 8.8.8.8和百度,原生的是ping Google ,这里被修改了
private boolean isStrictModeHostnameResolved()
// here check the sysprop for tbox internet avaliablity
// this prop is set-unset by tbox service by which will manage tbox connectivity
boolean status = false;
for (int i = 0; i < DNS_PROBE_TIMES; i ++)
try
status = InetAddress.getByName(GOOGLE_DNS).isReachable(DNS_PROBE_TIMEOUT);
catch (IOException e)
status = false;
if (status)
Log.d(TAG, “isStrictModeHostnameResolved: Host [” + GOOGLE_DNS + “] is REACHABLE.”);
break;
else
Log.d(TAG, “isStrictModeHostnameResolved: Host [” + GOOGLE_DNS + “] is UN-REACHABLE.”);
try
status = InetAddress.getByName(BAIDU_DNS).isReachable(DNS_PROBE_TIMEOUT);
catch (IOException e)
status = false;
if (status)
Log.d(TAG, “isStrictModeHostnameResolved: Host [” + BAIDU_DNS + “] is REACHABLE.”);
break;
else
Log.d(TAG, “isStrictModeHostnameResolved: Host [” + BAIDU_DNS + “] is UN-REACHABLE.”);
return status;
成功后调用handlePrivateDnsEvaluationSuccess进入循环,然后接着进入。ValidatedState状态之后发送EVENT_NETWORK_TESTED 通知ConnectivityService 更新网络状态
private class ValidatedState extends State
@Override
public void enter()
maybeLogEvaluationResult(
networkEventType(validationStage(), EvaluationResult.VALIDATED));
mConnectivityServiceHandler.sendMessage(obtainMessage(EVENT_NETWORK_TESTED,
NETWORK_TEST_RESULT_VALID, mNetId, null));
mValidations++;
@Override
public boolean processMessage(Message message)
switch (message.what)
case CMD_NETWORK_CONNECTED:
transitionTo(mValidatedState);
break;
case CMD_EVALUATE_PRIVATE_DNS:
transitionTo(mEvaluatingPrivateDnsState);
break;
default:
return NOT_HANDLED;
return HANDLED;
ConnectivityService根据 EVENT_NETWORK_TESTED更新网络状态:
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;
以上是关于Android9.0 网络评分之--NetworkMonitor的主要内容,如果未能解决你的问题,请参考以下文章
Android9.0 网络框架之--Tethering 热点
Android9.0 网络框架之--Tethering 热点
Android之网络请求提示Cleartext HTTP traffic to dev*******.com not permitted
Android之网络请求提示Cleartext HTTP traffic to dev*******.com not permitted