2023年12月6日发(作者:)

Android之WIFI-网络可用性校验(NetworkMonitor)

流程框架

WifiStateMachine(L2ConnectedState)

NetworkAgent

|

通信:服务

|

ConnectivityService

NetworkAgentInfo

NeworkMonitor

注:

7.1

基础知识

StateMachine即状态机运用

AsyncChannel即双Handler通信机制运用

源码

frameworks/base/services/core/java/com/android/server/

frameworks/base/services/core/java/com/android/server/connectivity/

frameworks/base/services/core/java/com/android/server/connectivity/

frameworks/base/core/java/com/android/net/

frameworks/opt/net/wifi/services/core/java/com/android/server/wifi/

frameworks/base/core/java/com/android/internal/util/

frameworks/base/core/java/com/android/internal/util/

细节

ateMachine在状态L2ConnectedState时,进行NetworkAgent初始化。

NetworkAgent初始化的过程建立与ConnectivityService通信

WifiStateMachine.L2ConnectedState

class L2ConnectedState extends State {

@Override

public void enter() {

······

mNetworkAgent = new WifiNetworkAgent(getHandler().getLooper(), mContext,

"WifiNetworkAgent", mNetworkInfo, mNetworkCapabilitiesFilter,

mLinkProperties, 60, mNetworkMisc);

······

}

}

WifiNetworkAgent(extends NetworkAgent)

public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni,

NetworkCapabilities nc, LinkProperties lp, int score, NetworkMisc misc) {

······

ConnectivityManager cm = (ConnectivityManager)temService(

TIVITY_SERVICE);

netId = erNetworkAgent(new Messenger(this), new NetworkInfo(ni),

new LinkProperties(lp), new NetworkCapabilities(nc), score, misc);

//erNetworkAgent把NetworkAgent和ConnectivityService建立连接

//更多的细节方向,在于双handler跨进程通信,重点关注Messenger

}

tivityService的registerNetworkAgent创建NetworkAgentInfo

erNetworkAgent

public int registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo,

LinkProperties linkProperties, NetworkCapabilities networkCapabilities,

int currentScore, NetworkMisc networkMisc) {

······

final NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(),

new Network(reserveNetId()), new NetworkInfo(networkInfo), new LinkProperties(

linkProperties), new NetworkCapabilities(networkCapabilities), currentScore,

mContext, mTrackerHandler, new NetworkMisc(networkMisc), mDefaultRequest, this);//NetworkAgent的messenger注入到NetworkAgentInfo,这样NetworkAgent与N

···

ssage(Message(EVENT_REGISTER_NETWORK_AGENT, nai));//走到handleRegisterNetworkAgent

······

}

private void handleRegisterNetworkAgent(NetworkAgentInfo na) {

if (VDBG) log("Got NetworkAgent Messenger");

(ger, na);

synchronized (mNetworkForNetId) {

(, na);

}

t(mContext, mTrackerHandler, ger);//NetworkAgentInfo的asyncChannel把ConnectivityService中mTrackerHandler和NetworkAgent中

NetworkInfo networkInfo = kInfo;

kInfo = null;

updateNetworkInfo(na, networkInfo);

}

private void updateNetworkInfo(NetworkAgentInfo networkAgent, NetworkInfo newInfo) {

···

if (!nnected && state == TED) {

···

ssage(_NETWORK_CONNECTED);

···

}

}

kAgentInfo的初始化,创建NetworkMonitor,而NetworkMonitor则是监听网络的可用性

1)来源介绍

NetworkAgentInfo

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) {

······

mHandler = handler;//handler是erHandler

networkMonitor = NetworkMonitor(context, handler, this, defaultRequest);

····

}

NetworkMonitor // NetworkMonitor extends StateMachine即NetworkMonitor为状态机

protected NetworkMonitor(Context context, Handler handler, NetworkAgentInfo networkAgentInfo,

NetworkRequest defaultRequest, IpConnectivityLog logger) {

···

mConnectivityServiceHandler = handler;//ConnectivityServiceHandler是erHandler

···

addState(mDefaultState);

addState(mValidatedState, mDefaultState);

addState(mMaybeNotifyState, mDefaultState);

addState(mEvaluatingState, mMaybeNotifyState);

addState(mCaptivePortalState, mMaybeNotifyState);

setInitialState(mDefaultState);

····

start();

}

2)ConnectivityService和NetworkMonitor通信介绍

tivityService更新数据时,通过NetworkAgent通知NetworkMonitor。例如:

NetworkInfo

ssage(_NETWORK_CONNECTED);

kMonitor收到数据时更新后,通过erHandler通知ConnectivityService。例如:

ssage(obtainMessage(EVENT_NETWORK_TESTED,

NETWORK_TEST_RESULT_INVALID, mNetId, ctUrl));

3)ConnectivityService和WifiStateMachine通信介绍

hannel实现了跨服务通信

RegisterNetworkAgent建立连接

t(mContext, mTrackerHandler, ger);//这里把双方通信建立起来

tivityService更新数据给WifiStateMachine,通过如下方式实现

ssage(

_REPORT_NETWORK_STATUS,

(valid ? _NETWORK : D_NETWORK),

0, redirectUrlBundle);

这是通知给WifiStateMachine的NetworkAgent

ateMachine更新数据给ConnectivityService,通过如下方式实现

workDetailedState

tworkInfo(mNetworkInfo);

rSendMessage

例如

private void queueOrSendMessage(Message msg) {

synchronized (mPreConnectedQueue) {

if (mAsyncChannel != null) {

ssage(msg);

} else {

(msg);

}

}

}

kMonitor

1)NetworkMonitor为状态机,默认状态为mDefaultState

2)当ConnectivityService的更新指令时,做状态切换

NetworkInfo

ssage(_NETWORK_CONNECTED);

ssage(_NETWORK_CONNECTED);

private class DefaultState extends State {

@Override

public boolean processMessage(Message message) {

switch () {

case CMD_NETWORK_CONNECTED:

logNetworkEvent(K_CONNECTED);

transitionTo(mEvaluatingState);//切换到mEvaluatingState状态

return HANDLED;

···

}

···

}

private class EvaluatingState extends State {

···

@Override

public void enter() {

···

sendMessage(CMD_REEVALUATE, ++mReevaluateToken, 0);

···

}

@Override

public boolean processMessage(Message message) {

switch () {

case CMD_REEVALUATE:

···

//关键方法,ping网络

//根据结果切换状态或更新数据

//关注isCaptivePortal

CaptivePortalProbeResult probeResult = isCaptivePortal();

if (essful()) {

transitionTo(mValidatedState);

} else if (al()) {

ssage(obtainMessage(EVENT_NETWORK_TESTED,

NETWORK_TEST_RESULT_INVALID, mNetId, ctUrl));

···

transitionTo(mCaptivePortalState);

} else {

···

ssage(obtainMessage(

EVENT_NETWORK_TESTED, NETWORK_TEST_RESULT_INVALID, mNetId,

ctUrl));

}

return HANDLED;

···

}

···

}

···

}

protected CaptivePortalProbeResult isCaptivePortal() {//以http通信认证为主

···

URL pacUrl = null, httpsUrl = null, httpUrl = null, fallbackUrl = null;

···

final CaptivePortalProbeResult result;

if (pacUrl != null) {

result = sendDnsAndHttpProbes(null, pacUrl, _PAC);

} else if (mUseHttps) {

result = sendParallelHttpProbes(proxyInfo, httpsUrl, httpUrl, fallbackUrl);

} else {

result = sendDnsAndHttpProbes(proxyInfo, httpUrl, _HTTP);//请求http

}

···

return result;

}

private CaptivePortalProbeResult sendDnsAndHttpProbes(ProxyInfo proxy, URL url, int probeType) {

··· ··· return sendHttpProbe(url, probeType); }

protected CaptivePortalProbeResult sendHttpProbe(URL url, int probeType) {//ping即通过HttpURLConnection验证 HttpURLConnection urlConnection = null; int httpResponseCode = 599; String redirectUrl = null; final Stopwatch probeTimer = new Stopwatch().start(); try { urlConnection = (HttpURLConnection) nnection(url); tanceFollowRedirects(probeType == _PAC); nectTimeout(SOCKET_TIMEOUT_MS); dTimeout(SOCKET_TIMEOUT_MS); Caches(false); final String userAgent = getCaptivePortalUserAgent(mContext); if (userAgent != null) { uestProperty("User-Agent", userAgent); } // Time how long it takes to get a response to our request long requestTimestamp = dRealtime(); httpResponseCode = ponseCode(); redirectUrl = derField("location"); // Time how long it takes to get a response to our request long responseTimestamp = dRealtime(); validationLog(beName(probeType) + " " + url + " time=" + (responseTimestamp - requestTimestamp) + "ms" + " ret=" + httpResponseCode + " headers=" + derFields()); // NOTE: We may want to consider an "HTTP/1.0 204" response to be a captive // portal. The only example of this seen so far was a captive portal. For // the time being go with prior behavior of assuming it's not a captive // portal. If it is considered a captive portal, a different sign-in URL // is needed (i.e. can't browse a 204). This could be the result of an HTTP // proxy server. if (httpResponseCode == 200) { if (probeType == _PAC) { validationLog("PAC fetch 200 response interpreted as 204 response."); httpResponseCode = 204; } else if (tentLengthLong() == 0) { // Consider 200 response with "Content-length=0" to not be a captive portal. // There's no point in considering this a captive portal as the user cannot // sign-in to an empty page. Probably the result of a broken transparent proxy. // See b/9972012. validationLog( "200 response with Content-length=0 interpreted as 204 response."); httpResponseCode = 204; } else if (tentLengthLong() == -1) { // When no Content-length (default value == -1), attempt to read a byte from the // response. Do not use available() as it is unreliable. See b/33498325. if (utStream().read() == -1) { validationLog("Empty 200 response interpreted as 204 response."); httpResponseCode = 204; } } } } catch (IOException e) { validationLog("Probably not a portal: exception " + e); if (httpResponseCode == 599) { // TODO: Ping gateway and DNS server and log results. } } finally { if (urlConnection != null) { nect(); } } logValidationProbe((), probeType, httpResponseCode); return new CaptivePortalProbeResult(httpResponseCode, redirectUrl, ng()); }

adb控制

1)ping对应的网址自定义

adb shell settings put global captive_portal_use_https 0 //采用http, 关闭https

adb shell settings put global captive_portal_detection_enabled 1 //打开可用性

adb shell settings put global captive_portal_http_url /generate_204 //http访问网址

2)ConnectivityService

adb shell dumpsys connectivity //可查看当前网络的对应信息

例如:

C:Users99418>adb shell dumpsys connectivity

NetworkFactories for: WIFI_UT WIFI Ethernet

Active default network: 104

Current Networks:

Requests: REQUEST:1 LISTEN:2 BACKGROUND_REQUEST:0 total:3

NetworkRequest [ REQUEST id=1, [ Capabilities: INTERNET&NOT_RESTRICTED&TRUSTED&NOT_VPN] ]

NetworkRequest [ LISTEN id=3, [] ]

NetworkRequest [ LISTEN id=4, [] ]

Lingered:

NetworkAgentInfo{ ni{[type: WIFI[], state: CONNECTED/CONNECTED, reason: (unspecified), extra: "Galanz_Office", failover: false, available: true, roaming: false, metered: fa

3)WifiStateMachine

adb shell dumpsys wifi //可查WifiStateMachine具体信息

问题

TIVITY_ACTION 跟wifi怎么关联起来?

NetworkInfo 接收来自WifiStateMachine的更新

而updateNetworkInfo包含了rematchNetworkAndRequests的调用

关键点在于mLegacyTypeTracker的addupdateremove中关联了TIVITY_ACTION的处理

参考学习

/u010961631/article/details/48971823

/u010961631/article/details/48629601

/ziyouchutuwenwu/p/

/asahinokawa/article/details/80722178

/qiqi715/p/