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/


发布评论