(一百五十八)android P WifiStateMachine中WifiNetworkAgent是干什么的?
1.流程梳理1.1 初始化1.1.1 WifiStateMachine// CHECKSTYLE:OFF IndentationCheckaddState(mDefaultState);addState(mConnectModeState, mDefaultState);addState(m...
1.流程梳理
1.1 初始化
1.1.1 WifiStateMachine
// CHECKSTYLE:OFF IndentationCheck
addState(mDefaultState);
addState(mConnectModeState, mDefaultState);
addState(mL2ConnectedState, mConnectModeState);
addState(mObtainingIpState, mL2ConnectedState);
addState(mConnectedState, mL2ConnectedState);
addState(mRoamingState, mL2ConnectedState);
addState(mDisconnectingState, mConnectModeState);
addState(mDisconnectedState, mConnectModeState);
// CHECKSTYLE:ON IndentationCheck
class L2ConnectedState extends State {
class RssiEventHandler implements WifiNative.WifiRssiEventHandler {
@Override
public void onRssiThresholdBreached(byte curRssi) {
if (mVerboseLoggingEnabled) {
Log.e(TAG, "onRssiThresholdBreach event. Cur Rssi = " + curRssi);
}
sendMessage(CMD_RSSI_THRESHOLD_BREACHED, curRssi);
}
}
RssiEventHandler mRssiEventHandler = new RssiEventHandler();
@Override
public void enter() {
mRssiPollToken++;
if (mEnableRssiPolling) {
sendMessage(CMD_RSSI_POLL, mRssiPollToken, 0);
}
if (mNetworkAgent != null) {
loge("Have NetworkAgent when entering L2Connected");
setNetworkDetailedState(DetailedState.DISCONNECTED);
}
setNetworkDetailedState(DetailedState.CONNECTING);
final NetworkCapabilities nc;
if (mWifiInfo != null && !mWifiInfo.getSSID().equals(WifiSsid.NONE)) {
nc = new NetworkCapabilities(mNetworkCapabilitiesFilter);
nc.setSSID(mWifiInfo.getSSID());
} else {
nc = mNetworkCapabilitiesFilter;
}
mNetworkAgent = new WifiNetworkAgent(getHandler().getLooper(), mContext,
"WifiNetworkAgent", mNetworkInfo, nc, mLinkProperties, 60, mNetworkMisc);
// We must clear the config BSSID, as the wifi chipset may decide to roam
// from this point on and having the BSSID specified in the network block would
// cause the roam to faile and the device to disconnect
clearTargetBssid("L2ConnectedState");
mCountryCode.setReadyForChange(false);
mWifiMetrics.setWifiState(WifiMetricsProto.WifiLog.WIFI_ASSOCIATED);
}
从状态机变化来说应该是在 WiFi DisconnectedState 收到WifiMonitor.NETWORK_CONNECTION_EVENT消息即WiFi进入到competed状态继而进入到ObtainingIpState状态的时候,先进入其父状态ConnectModeState的enter方法时初始化的
看下构造函数及传参
private class WifiNetworkAgent extends NetworkAgent {
public WifiNetworkAgent(Looper l, Context c, String TAG, NetworkInfo ni,
NetworkCapabilities nc, LinkProperties lp, int score, NetworkMisc misc) {
super(l, c, TAG, ni, nc, lp, score, misc);
}
WifiNetworkAgent是WifiStateMachine的内部类,继承的NetworkAgent,构造方法是调用的父类的构造方法
1.1.2 NetworkAgent
/**
* A Utility class for handling for communicating between bearer-specific
* code and ConnectivityService.
*
* A bearer may have more than one NetworkAgent if it can simultaneously
* support separate networks (IMS / Internet / MMS Apns on cellular, or
* perhaps connections with different SSID or P2P for Wi-Fi).
*
* @hide
*/
public abstract class NetworkAgent extends Handler {
NetworkAgent如上面注释:
用于处理特定于承载的代码和ConnectivityService之间的通信的Utility类。
如果承载可以同时支持单独的网络(蜂窝上的IMS / Internet / MMS Apns,或者可能具有用于Wi-Fi的不同SSID或P2P的连接),则承载可以具有多于一个NetworkAgent。
个人理解为业务代码和ConnectivityService之间通信的桥梁,如名称所示,网络代理,本质上是个以AsyncChannel方式跨进程通信的handler。
public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni,
NetworkCapabilities nc, LinkProperties lp, int score) {
this(looper, context, logTag, ni, nc, lp, score, null);
}
public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni,
NetworkCapabilities nc, LinkProperties lp, int score, NetworkMisc misc) {
super(looper);
LOG_TAG = logTag;
mContext = context;
if (ni == null || nc == null || lp == null) {
throw new IllegalArgumentException();
}
if (VDBG) log("Registering NetworkAgent");
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);
}
从构造方法里可以看出大部分参数都传递给了ConnectivityService,看下ConnectivityManager的registerNetworkAgent
1.1.3 ConnectivityService
/**
* @hide
* Register a NetworkAgent with ConnectivityService.
* @return NetID corresponding to NetworkAgent.
*/
public int registerNetworkAgent(Messenger messenger, NetworkInfo ni, LinkProperties lp,
NetworkCapabilities nc, int score, NetworkMisc misc) {
try {
return mService.registerNetworkAgent(messenger, ni, lp, nc, score, misc);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
看下ConnectivityService的实现
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,从名称来看是储存网络代理信息的。
1.1.4 NetworkAgentInfo
/**
* A bag class used by ConnectivityService for holding a collection of most recent
* information published by a particular NetworkAgent as well as the
* AsyncChannel/messenger for reaching that NetworkAgent and lists of NetworkRequests
* interested in using it. Default sort order is descending by score.
*/
// States of a network:
// --------------------
// 1. registered, uncreated, disconnected, unvalidated
// This state is entered when a NetworkFactory registers a NetworkAgent in any state except
// the CONNECTED state.
// 2. registered, uncreated, connecting, unvalidated
// This state is entered when a registered NetworkAgent for a VPN network transitions to the
// CONNECTING state (TODO: go through this state for every network, not just VPNs).
// ConnectivityService will tell netd to create the network early in order to add extra UID
// routing rules referencing the netID. These rules need to be in place before the network is
// connected to avoid racing against client apps trying to connect to a half-setup network.
// 3. registered, uncreated, connected, unvalidated
// This state is entered when a registered NetworkAgent transitions to the CONNECTED state.
// ConnectivityService will tell netd to create the network if it was not already created, and
// immediately transition to state #4.
// 4. registered, created, connected, unvalidated
// If this network can satisfy the default NetworkRequest, then NetworkMonitor will
// probe for Internet connectivity.
// If this network cannot satisfy the default NetworkRequest, it will immediately be
// transitioned to state #5.
// A network may remain in this state if NetworkMonitor fails to find Internet connectivity,
// for example:
// a. a captive portal is present, or
// b. a WiFi router whose Internet backhaul is down, or
// c. a wireless connection stops transfering packets temporarily (e.g. device is in elevator
// or tunnel) but does not disconnect from the AP/cell tower, or
// d. a stand-alone device offering a WiFi AP without an uplink for configuration purposes.
// 5. registered, created, connected, validated
//
// The device's default network connection:
// ----------------------------------------
// Networks in states #4 and #5 may be used as a device's default network connection if they
// satisfy the default NetworkRequest.
// A network, that satisfies the default NetworkRequest, in state #5 should always be chosen
// in favor of a network, that satisfies the default NetworkRequest, in state #4.
// When deciding between two networks, that both satisfy the default NetworkRequest, to select
// for the default network connection, the one with the higher score should be chosen.
//
// When a network disconnects:
// ---------------------------
// If a network's transport disappears, for example:
// a. WiFi turned off, or
// b. cellular data turned off, or
// c. airplane mode is turned on, or
// d. a wireless connection disconnects from AP/cell tower entirely (e.g. device is out of range
// of AP for an extended period of time, or switches to another AP without roaming)
// then that network can transition from any state (#1-#5) to unregistered. This happens by
// the transport disconnecting their NetworkAgent's AsyncChannel with ConnectivityManager.
// ConnectivityService also tells netd to destroy the network.
//
// When ConnectivityService disconnects a network:
// -----------------------------------------------
// If a network has no chance of satisfying any requests (even if it were to become validated
// and enter state #5), ConnectivityService will disconnect the NetworkAgent's AsyncChannel.
//
// If the network was satisfying a foreground NetworkRequest (i.e. had been the highest scoring that
// satisfied the NetworkRequest's constraints), but is no longer the highest scoring network for any
// foreground NetworkRequest, then there will be a 30s pause to allow network communication to be
// wrapped up rather than abruptly terminated. During this pause the network is said to be
// "lingering". During this pause if the network begins satisfying a foreground NetworkRequest,
// ConnectivityService will cancel the future disconnection of the NetworkAgent's AsyncChannel, and
// the network is no longer considered "lingering". After the linger timer expires, if the network
// is satisfying one or more background NetworkRequests it is kept up in the background. If it is
// not, ConnectivityService disconnects the NetworkAgent's AsyncChannel.
public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
注释讲了一堆
- 概要
- 状态
- 网络选择基于评分
- 断开及保持
1.1.5 WSM与CS的桥梁
注册网络代理后续会发出一个EVENT_REGISTER_NETWORK_AGENT消息,这会通过asyncChannel建立起WifiStateMachine和ConnectivitySerivce通信的桥梁
mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_AGENT, nai));
case EVENT_REGISTER_NETWORK_AGENT: {
handleRegisterNetworkAgent((NetworkAgentInfo)msg.obj);
break;
}
private void handleRegisterNetworkAgent(NetworkAgentInfo nai) {
if (VDBG) log("Got NetworkAgent Messenger");
mNetworkAgentInfos.put(nai.messenger, nai);
synchronized (mNetworkForNetId) {
mNetworkForNetId.put(nai.network.netId, nai);
}
nai.asyncChannel.connect(mContext, mTrackerHandler, nai.messenger);
NetworkInfo networkInfo = nai.networkInfo;
nai.networkInfo = null;
updateNetworkInfo(nai, networkInfo);
updateUids(nai, null, nai.networkCapabilities);
}
1.1.6 WifiNetworkAgent的参数概要
mNetworkAgent = new WifiNetworkAgent(getHandler().getLooper(), mContext,
"WifiNetworkAgent", mNetworkInfo, nc, mLinkProperties, 60, mNetworkMisc);
NetworkInfo
mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, NETWORKTYPE, "");
/**
* Describes the status of a network interface.
* <p>Use {@link ConnectivityManager#getActiveNetworkInfo()} to get an instance that represents
* the current network connection.
*/
public class NetworkInfo implements Parcelable {
NetworkCapabilities
/**
* Representation of the capabilities of an active network. Instances are
* typically obtained through
* {@link NetworkCallback#onCapabilitiesChanged(Network, NetworkCapabilities)}
* or {@link ConnectivityManager#getNetworkCapabilities(Network)}.
* <p>
* This replaces the old {@link ConnectivityManager#TYPE_MOBILE} method of
* network selection. Rather than indicate a need for Wi-Fi because an
* application needs high bandwidth and risk obsolescence when a new, fast
* network appears (like LTE), the application should specify it needs high
* bandwidth. Similarly if an application needs an unmetered network for a bulk
* transfer it can specify that rather than assuming all cellular based
* connections are metered and all Wi-Fi based connections are not.
*/
public final class NetworkCapabilities implements Parcelable {
// Used to filter out requests we couldn't possibly satisfy.
private final NetworkCapabilities mNetworkCapabilitiesFilter = new NetworkCapabilities();
mNetworkCapabilitiesFilter.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
mNetworkCapabilitiesFilter.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
mNetworkCapabilitiesFilter.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
mNetworkCapabilitiesFilter.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING);
mNetworkCapabilitiesFilter.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED);
mNetworkCapabilitiesFilter.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
mNetworkCapabilitiesFilter.setLinkUpstreamBandwidthKbps(1024 * 1024);
mNetworkCapabilitiesFilter.setLinkDownstreamBandwidthKbps(1024 * 1024);
LinkProperties
/**
* The link properties of the wifi interface.
* Do not modify this directly; use updateLinkProperties instead.
*/
private LinkProperties mLinkProperties;
/**
* Describes the properties of a network link.
*
* A link represents a connection to a network.
* It may have multiple addresses and multiple gateways,
* multiple dns servers but only one http proxy and one
* network interface.
*
* Note that this is just a holder of data. Modifying it
* does not affect live networks.
*
*/
public final class LinkProperties implements Parcelable {
链路属性看起来是在dhcp完成后更新并广播出来,并发给ConnectivityService
NetworkMisc
// Provide packet filter capabilities to ConnectivityService.
private final NetworkMisc mNetworkMisc = new NetworkMisc();
/**
* A grab-bag of information (metadata, policies, properties, etc) about a
* {@link Network}. Since this contains PII, it should not be sent outside the
* system.
*
* @hide
*/
public class NetworkMisc implements Parcelable {
Score
// This represents the last score received from the NetworkAgent.
private int currentScore;
1.2 更新LinkProperties
private void updateLinkProperties(LinkProperties newLp) {
if (mVerboseLoggingEnabled) {
log("Link configuration changed for netId: " + mLastNetworkId
+ " old: " + mLinkProperties + " new: " + newLp);
}
// We own this instance of LinkProperties because IpClient passes us a copy.
mLinkProperties = newLp;
if (mNetworkAgent != null) {
mNetworkAgent.sendLinkProperties(mLinkProperties);
}
if (getNetworkDetailedState() == DetailedState.CONNECTED) {
// If anything has changed and we're already connected, send out a notification.
// TODO: Update all callers to use NetworkCallbacks and delete this.
sendLinkConfigurationChangedBroadcast();
}
if (mVerboseLoggingEnabled) {
StringBuilder sb = new StringBuilder();
sb.append("updateLinkProperties nid: " + mLastNetworkId);
sb.append(" state: " + getNetworkDetailedState());
if (mLinkProperties != null) {
sb.append(" ");
sb.append(getLinkPropertiesSummary(mLinkProperties));
}
logd(sb.toString());
}
}
NetworkAgent
/**
* Sent by the NetworkAgent to ConnectivityService to pass the current
* NetworkProperties.
* obj = NetworkProperties
*/
public static final int EVENT_NETWORK_PROPERTIES_CHANGED = BASE + 3;
/**
* Called by the bearer code when it has new LinkProperties data.
*/
public void sendLinkProperties(LinkProperties linkProperties) {
queueOrSendMessage(EVENT_NETWORK_PROPERTIES_CHANGED, new LinkProperties(linkProperties));
}
ConnectivityService
case NetworkAgent.EVENT_NETWORK_PROPERTIES_CHANGED: {
handleUpdateLinkProperties(nai, (LinkProperties) msg.obj);
break;
}
public void handleUpdateLinkProperties(NetworkAgentInfo nai, LinkProperties newLp) {
if (getNetworkAgentInfoForNetId(nai.network.netId) != nai) {
// Ignore updates for disconnected networks
return;
}
// newLp is already a defensive copy.
newLp.ensureDirectlyConnectedRoutes();
if (VDBG) {
log("Update of LinkProperties for " + nai.name() +
"; created=" + nai.created +
"; everConnected=" + nai.everConnected);
}
LinkProperties oldLp = nai.linkProperties;
synchronized (nai) {
nai.linkProperties = newLp;
}
if (nai.everConnected) {
updateLinkProperties(nai, oldLp);
}
}
1.3 更新NetworkInfo
mNetworkAgent.sendNetworkInfo(mNetworkInfo);
NetworAgent
/**
* Called by the bearer code when it has new NetworkInfo data.
*/
public void sendNetworkInfo(NetworkInfo networkInfo) {
queueOrSendMessage(EVENT_NETWORK_INFO_CHANGED, new NetworkInfo(networkInfo));
}
/**
* Sent by the NetworkAgent (note the EVENT vs CMD prefix) to
* ConnectivityService to pass the current NetworkInfo (connection state).
* Sent when the NetworkInfo changes, mainly due to change of state.
* obj = NetworkInfo
*/
public static final int EVENT_NETWORK_INFO_CHANGED = BASE + 1;
ConnectivityService
case NetworkAgent.EVENT_NETWORK_INFO_CHANGED: {
NetworkInfo info = (NetworkInfo) msg.obj;
updateNetworkInfo(nai, info);
break;
}
这边接了(一百五十七)Android P 梳理网络校验后续结果上报 的updateNetworkInfo的流程
1.4 更新NetworkCapabilities
private void updateCapabilities(WifiConfiguration config) {
if (mNetworkAgent == null) {
return;
}
final NetworkCapabilities result = new NetworkCapabilities(mDfltNetworkCapabilities);
if (mWifiInfo != null && !mWifiInfo.isEphemeral()) {
result.addCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED);
} else {
result.removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED);
}
if (mWifiInfo != null && !WifiConfiguration.isMetered(config, mWifiInfo)) {
result.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
} else {
result.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
}
if (mWifiInfo != null && mWifiInfo.getRssi() != WifiInfo.INVALID_RSSI) {
result.setSignalStrength(mWifiInfo.getRssi());
} else {
result.setSignalStrength(NetworkCapabilities.SIGNAL_STRENGTH_UNSPECIFIED);
}
if (mWifiInfo != null && !mWifiInfo.getSSID().equals(WifiSsid.NONE)) {
result.setSSID(mWifiInfo.getSSID());
} else {
result.setSSID(null);
}
mNetworkAgent.sendNetworkCapabilities(result);
}
后续略
2.总结
NetworkAgent为网络相关业务代码和ConnectivityService之间通信的桥梁,如名称所示,网络代理,本质上是个以AsyncChannel方式实现跨进程通信的handler。
更多推荐
所有评论(0)