流程框架
WifiStateMachine(L2ConnectedState)
NetworkAgent
|
通信:服务
|
ConnectivityService
NetworkAgentInfo
NeworkMonitor
注:
7.1
基础知识
StateMachine即状态机运用
AsyncChannel即双Handler通信机制运用
源码
frameworks/base/services/core/java/com/android/server/ConnectivityService.java
frameworks/base/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
frameworks/base/services/core/java/com/android/server/connectivity/NetworkMonitor.java
frameworks/base/core/java/com/android/net/NetworkAgent.java
frameworks/opt/net/wifi/services/core/java/com/android/server/wifi/WifiStateMachine.java
frameworks/base/core/java/com/android/internal/util/StateMachine.java
frameworks/base/core/java/com/android/internal/util/AsyncChannel.java
细节
1.WifiStateMachine在状态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)mContext.getSystemService(
Context.CONNECTIVITY_SERVICE);
netId = cm.registerNetworkAgent(new Messenger(this), new NetworkInfo(ni),
new LinkProperties(lp), new NetworkCapabilities(nc), score, misc);
//cm.registerNetworkAgent把NetworkAgent和ConnectivityService建立连接
//更多的细节方向,在于双handler跨进程通信,重点关注Messenger
}
2.ConnectivityService的registerNetworkAgent创建NetworkAgentInfo
ConnectivityService.registerNetworkAgent
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与NetworkAgentInfo建立联系,注:双handler通信关注AsyncChannel
···
mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_AGENT, nai));//走到handleRegisterNetworkAgent
······
}
private void handleRegisterNetworkAgent(NetworkAgentInfo na) {
if (VDBG) log("Got NetworkAgent Messenger");
mNetworkAgentInfos.put(na.messenger, na);
synchronized (mNetworkForNetId) {
mNetworkForNetId.put(na.network.netId, na);
}
na.asyncChannel.connect(mContext, mTrackerHandler, na.messenger);//NetworkAgentInfo的asyncChannel把ConnectivityService中mTrackerHandler和NetworkAgent中messenger建立连接
NetworkInfo networkInfo = na.networkInfo;
na.networkInfo = null;
updateNetworkInfo(na, networkInfo);
}
private void updateNetworkInfo(NetworkAgentInfo networkAgent, NetworkInfo newInfo) {
···
if (!networkAgent.everConnected && state == NetworkInfo.State.CONNECTED) {
···
networkAgent.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_CONNECTED);
···
}
}
3.NetworkAgentInfo的初始化,创建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是ConnectivityService.mTrackerHandler
networkMonitor = mConnService.createNetworkMonitor(context, handler, this, defaultRequest);
····
}
NetworkMonitor // NetworkMonitor extends StateMachine即NetworkMonitor为状态机
protected NetworkMonitor(Context context, Handler handler, NetworkAgentInfo networkAgentInfo,
NetworkRequest defaultRequest, IpConnectivityLog logger) {
···
mConnectivityServiceHandler = handler;//ConnectivityServiceHandler是ConnectivityService.mTrackerHandler
···
addState(mDefaultState);
addState(mValidatedState, mDefaultState);
addState(mMaybeNotifyState, mDefaultState);
addState(mEvaluatingState, mMaybeNotifyState);
addState(mCaptivePortalState, mMaybeNotifyState);
setInitialState(mDefaultState);
····
start();
}
2)ConnectivityService和NetworkMonitor通信介绍
a.ConnectivityService更新数据时,通过NetworkAgent通知NetworkMonitor。例如:
ConnectivityService.updateNetworkInfo
networkAgent.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_CONNECTED);
b.NetworkMonitor收到数据时更新后,通过ConnectivityService.mTrackerHandler通知ConnectivityService。例如:
mConnectivityServiceHandler.sendMessage(obtainMessage(EVENT_NETWORK_TESTED,
NETWORK_TEST_RESULT_INVALID, mNetId, probeResult.redirectUrl));
3)ConnectivityService和WifiStateMachine通信介绍
a.AsyncChannel实现了跨服务通信
b.ConnectivityService.handleRegisterNetworkAgent建立连接
na.asyncChannel.connect(mContext, mTrackerHandler, na.messenger);//这里把双方通信建立起来
c.ConnectivityService更新数据给WifiStateMachine,通过如下方式实现
nai.asyncChannel.sendMessage(
NetworkAgent.CMD_REPORT_NETWORK_STATUS,
(valid ? NetworkAgent.VALID_NETWORK : NetworkAgent.INVALID_NETWORK),
0, redirectUrlBundle);
这是通知给WifiStateMachine的NetworkAgent
d.WifiStateMachine更新数据给ConnectivityService,通过如下方式实现
WifiStateMachine.setNetworkDetailedState
mNetworkAgent.sendNetworkInfo(mNetworkInfo);
NetworkAgent.queueOrSendMessage
例如
private void queueOrSendMessage(Message msg) {
synchronized (mPreConnectedQueue) {
if (mAsyncChannel != null) {
mAsyncChannel.sendMessage(msg);
} else {
mPreConnectedQueue.add(msg);
}
}
}
4.NetworkMonitor
1)NetworkMonitor为状态机,默认状态为mDefaultState
2)当ConnectivityService的更新指令时,做状态切换
ConnectivityService.updateNetworkInfo
networkAgent.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_CONNECTED);
private class DefaultState extends State {
@Override
public boolean processMessage(Message message) {
switch (message.what) {
case CMD_NETWORK_CONNECTED:
logNetworkEvent(NetworkEvent.NETWORK_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 (message.what) {
case CMD_REEVALUATE:
···
//关键方法,ping网络
//根据结果切换状态或更新数据
//关注isCaptivePortal
CaptivePortalProbeResult probeResult = isCaptivePortal();
if (probeResult.isSuccessful()) {
transitionTo(mValidatedState);
} else if (probeResult.isPortal()) {
mConnectivityServiceHandler.sendMessage(obtainMessage(EVENT_NETWORK_TESTED,
NETWORK_TEST_RESULT_INVALID, mNetId, probeResult.redirectUrl));
···
transitionTo(mCaptivePortalState);
} else {
···
mConnectivityServiceHandler.sendMessage(obtainMessage(
EVENT_NETWORK_TESTED, NETWORK_TEST_RESULT_INVALID, mNetId,
probeResult.redirectUrl));
}
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, ValidationProbeEvent.PROBE_PAC);
} else if (mUseHttps) {
result = sendParallelHttpProbes(proxyInfo, httpsUrl, httpUrl, fallbackUrl);
} else {
result = sendDnsAndHttpProbes(proxyInfo, httpUrl, ValidationProbeEvent.PROBE_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) mNetworkAgentInfo.network.openConnection(url);
urlConnection.setInstanceFollowRedirects(probeType == ValidationProbeEvent.PROBE_PAC);
urlConnection.setConnectTimeout(SOCKET_TIMEOUT_MS);
urlConnection.setReadTimeout(SOCKET_TIMEOUT_MS);
urlConnection.setUseCaches(false);
final String userAgent = getCaptivePortalUserAgent(mContext);
if (userAgent != null) {
urlConnection.setRequestProperty("User-Agent", userAgent);
}
// Time how long it takes to get a response to our request
long requestTimestamp = SystemClock.elapsedRealtime();
httpResponseCode = urlConnection.getResponseCode();
redirectUrl = urlConnection.getHeaderField("location");
// Time how long it takes to get a response to our request
long responseTimestamp = SystemClock.elapsedRealtime();
validationLog(ValidationProbeEvent.getProbeName(probeType) + " " + url +
" time=" + (responseTimestamp - requestTimestamp) + "ms" +
" ret=" + httpResponseCode +
" headers=" + urlConnection.getHeaderFields());
// 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 == ValidationProbeEvent.PROBE_PAC) {
validationLog("PAC fetch 200 response interpreted as 204 response.");
httpResponseCode = 204;
} else if (urlConnection.getContentLengthLong() == 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 http://b/9972012.
validationLog(
"200 response with Content-length=0 interpreted as 204 response.");
httpResponseCode = 204;
} else if (urlConnection.getContentLengthLong() == -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 http://b/33498325.
if (urlConnection.getInputStream().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) {
urlConnection.disconnect();
}
}
logValidationProbe(probeTimer.stop(), probeType, httpResponseCode);
return new CaptivePortalProbeResult(httpResponseCode, redirectUrl, url.toString());
}
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 http://connect.rom.miui.com/generate_204 //http访问网址
2)ConnectivityService
adb shell dumpsys connectivity //可查看当前网络的对应信息
例如:
C:\Users\99418>adb shell dumpsys connectivity
NetworkFactories for: WIFI_UT WIFI Ethernet
Active default network: 104
Current Networks:
NetworkAgentInfo{ ni{[type: WIFI[], state: CONNECTED/CONNECTED, reason: (unspecified), extra: "Galanz_Office", failover: false, available: true, roaming: false, metered: false]} network{104} nethandle{446693034718} lp{{InterfaceName: wlan0 LinkAddresses: [fe80::ce4b:73ff:fed2:71a8/64,10.100.3.142/24,] Routes: [fe80::/64 -> :: wlan0,10.100.3.0/24 -> 0.0.0.0 wlan0,0.0.0.0/0 -> 10.100.3.1 wlan0,] DnsAddresses: [172.1.1.20,114.114.114.114,] Domains: null MTU: 0 TcpBufferSizes: 524288,1048576,2097152,262144,524288,1048576}} nc{[ Transports: WIFI Capabilities: NOT_METERED&INTERNET&NOT_RESTRICTED&TRUSTED&NOT_VPN&VALIDATED&FOREGROUND LinkUpBandwidth>=1048576Kbps LinkDnBandwidth>=1048576Kbps SignalStrength: -66]} Score{56} everValidated{true} lastValidated{true} created{true} lingering{false} explicitlySelected{false} acceptUnvalidated{false} everCaptivePortalDetected{false} lastCaptivePortalDetected{false} }
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:
3)WifiStateMachine
adb shell dumpsys wifi //可查WifiStateMachine具体信息
问题
1.ConnectivityManager.CONNECTIVITY_ACTION 跟wifi怎么关联起来?
ConnectivityService.updateNetworkInfo 接收来自WifiStateMachine的更新
而updateNetworkInfo包含了rematchNetworkAndRequests的调用
关键点在于mLegacyTypeTracker的add\update\remove中关联了ConnectivityManager.CONNECTIVITY_ACTION的处理
参考学习
https://blog.csdn.net/u010961631/article/details/48971823
https://blog.csdn.net/u010961631/article/details/48629601
https://www.cnblogs.com/ziyouchutuwenwu/p/11429284.html
https://blog.csdn.net/asahinokawa/article/details/80722178
https://www.cnblogs.com/qiqi715/p/9338699.html
网友评论