前言: 之前在(五十五)Android O 连接WiFi AP流程梳理 梳理连接流程梳理到SupplicantStaNetworkHal 然后没梳理的下去,现在继续梳理下。
之前梳理的时序图
1.流程梳理-保存网络
现在重新梳理了下流程发现漏了些细节,完善一下。
1.1 Settings
/* package */ void submit(WifiConfigController configController) {
final WifiConfiguration config = configController.getConfig();
if (config == null) {
if (mSelectedAccessPoint != null
&& mSelectedAccessPoint.isSaved()) {
connect(mSelectedAccessPoint.getConfig(), true /* isSavedNetwork */);
}
} else if (configController.getMode() == WifiConfigUiBase.MODE_MODIFY) {
mWifiManager.save(config, mSaveListener);
} else {
mWifiManager.save(config, mSaveListener);
if (mSelectedAccessPoint != null) { // Not an "Add network"
connect(config, false /* isSavedNetwork */);
}
}
mWifiTracker.resumeScanning();
}
在第一次连接WiFi的时候,我们一般先输入密码,然后连接,之后的过程是先调用WifiManager保存该网络,可以观察到我们连接过的网络都会在已保存网络里有所显示,之后才是连接网络。而其中的参数WifiConfiguration是从WifiConfigController中获取的,这其实就是将用户输入转换为对象。
/* package */ WifiConfiguration getConfig() {
if (mMode == WifiConfigUiBase.MODE_VIEW) {
return null;
}
WifiConfiguration config = new WifiConfiguration();
if (mAccessPoint == null) {
config.SSID = AccessPoint.convertToQuotedString(
mSsidView.getText().toString());
// If the user adds a network manually, assume that it is hidden.
config.hiddenSSID = true;
} else if (!mAccessPoint.isSaved()) {
config.SSID = AccessPoint.convertToQuotedString(
mAccessPoint.getSsidStr());
} else {
config.networkId = mAccessPoint.getConfig().networkId;
config.hiddenSSID = mAccessPoint.getConfig().hiddenSSID;
}
config.shared = mSharedCheckBox.isChecked();
switch (mAccessPointSecurity) {
case AccessPoint.SECURITY_NONE:
config.allowedKeyManagement.set(KeyMgmt.NONE);
break;
case AccessPoint.SECURITY_WEP:
...
break;
case AccessPoint.SECURITY_PSK:
config.allowedKeyManagement.set(KeyMgmt.WPA_PSK);
if (mPasswordView.length() != 0) {
String password = mPasswordView.getText().toString();
if (password.matches("[0-9A-Fa-f]{64}")) {
config.preSharedKey = password;
} else {
config.preSharedKey = '"' + password + '"';
}
}
break;
case AccessPoint.SECURITY_EAP:
...
break;
default:
return null;
}
config.setIpConfiguration(
new IpConfiguration(mIpAssignment, mProxySettings,
mStaticIpConfiguration, mHttpProxy));
return config;
}
先添加的wpa/wpa2类型的网络 config一般就初始化SSID、hiddenSSID、shared、allowedKeyManagement、preSharedKey和setIpConfiguration。
1.2 WifiManager
/**
* Save the given network to the list of configured networks for the
* foreground user. If the network already exists, the configuration
* is updated. Any new network is enabled by default.
*
* For a new network, this function is used instead of a
* sequence of addNetwork(), enableNetwork() and saveConfiguration().
*
* For an existing network, it accomplishes the task of updateNetwork()
* and saveConfiguration()
*
* @param config the set of variables that describe the configuration,
* contained in a {@link WifiConfiguration} object.
* @param listener for callbacks on success or failure. Can be null.
* @throws IllegalStateException if the WifiManager instance needs to be
* initialized again
* @hide
*/
public void save(WifiConfiguration config, ActionListener listener) {
if (config == null) throw new IllegalArgumentException("config cannot be null");
getChannel().sendMessage(SAVE_NETWORK, 0, putListener(listener), config);
}
从注释我们看到了save是一系列方法的封装。
对于新网络:save完成addNetwork(), enableNetwork() and saveConfiguration()
对于已保存网络:save完成updateNetwork() and saveConfiguration()
1.3 WifiServiceImpl
case WifiManager.SAVE_NETWORK: {
if (checkChangePermissionAndReplyIfNotAuthorized(
msg, WifiManager.SAVE_NETWORK_FAILED)) {
WifiConfiguration config = (WifiConfiguration) msg.obj;
int networkId = msg.arg1;
Slog.d(TAG, "SAVE"
+ " nid=" + Integer.toString(networkId)
+ " uid=" + msg.sendingUid
+ " name="
+ mContext.getPackageManager().getNameForUid(msg.sendingUid));
if (config != null) {
if (DBG) Slog.d(TAG, "Save network with config " + config);
/* Command is forwarded to state machine */
mWifiStateMachine.sendMessage(Message.obtain(msg));
} else {
Slog.e(TAG, "ClientHandler.handleMessage ignoring invalid msg=" + msg);
replyFailed(msg, WifiManager.SAVE_NETWORK_FAILED,
WifiManager.INVALID_ARGS);
}
}
break;
}
1.4 WifiStateMachine
case WifiManager.SAVE_NETWORK:
result = saveNetworkConfigAndSendReply(message);
netId = result.getNetworkId();
if (result.isSuccess() && mWifiInfo.getNetworkId() == netId) {
mWifiConnectionStatistics.numWifiManagerJoinAttempt++;
if (result.hasCredentialChanged()) {
config = (WifiConfiguration) message.obj;
// The network credentials changed and we're connected to this network,
// start a new connection with the updated credentials.
logi("SAVE_NETWORK credential changed for config=" + config.configKey()
+ ", Reconnecting.");
startConnectToNetwork(netId, message.sendingUid, SUPPLICANT_BSSID_ANY);
} else {
if (result.hasProxyChanged()) {
log("Reconfiguring proxy on connection");
mIpClient.setHttpProxy(
getCurrentWifiConfiguration().getHttpProxy());
}
if (result.hasIpChanged()) {
// The current connection configuration was changed
// We switched from DHCP to static or from static to DHCP, or the
// static IP address has changed.
log("Reconfiguring IP on connection");
// TODO(b/36576642): clear addresses and disable IPv6
// to simplify obtainingIpState.
transitionTo(mObtainingIpState);
}
}
}
break;
/**
* Private method to handle calling WifiConfigManager to add