前言: 之前在(五十五)Android O 连接WiFi AP流程梳理 梳理连接流程梳理到SupplicantStaNetworkHal 然后没梳理的下去,现在继续梳理下。
之前梳理的时序图
现在重新梳理了下流程发现漏了些细节,完善一下。
/* 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。
/**
* 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()
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;
}
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 & enable network configs and reply
* to the message from the sender of the outcome.
*
* @return NetworkUpdateResult with networkId of the added/updated configuration. Will return
* {@link WifiConfiguration#INVALID_NETWORK_ID} in case of error.
*/
private NetworkUpdateResult saveNetworkConfigAndSendReply(Message message) {
WifiConfiguration config = (WifiConfiguration) message.obj;
if (config == null) {
loge("SAVE_NETWORK with null configuration "
+ mSupplicantStateTracker.getSupplicantStateName()
+ " my state " + getCurrentState().getName());
messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, WifiManager.ERROR);
return new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID);
}
NetworkUpdateResult result =
mWifiConfigManager.addOrUpdateNetwork(config, message.sendingUid);
if (!result.isSuccess()) {
loge("SAVE_NETWORK adding/updating config=" + config + " failed");
messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, WifiManager.ERROR);
return result;
}
if (!mWifiConfigManager.enableNetwork(
result.getNetworkId(), false, message.sendingUid)) {
loge("SAVE_NETWORK enabling config=" + config + " failed");
messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, WifiManager.ERROR);
return new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID);
}
broadcastWifiCredentialChanged(WifiManager.WIFI_CREDENTIAL_SAVED, config);
replyToMessage(message, WifiManager.SAVE_NETWORK_SUCCEEDED);
return result;
}
保存网络第一步:添加网络
/**
* Add a network or update a network configuration to our database.
* If the supplied networkId is INVALID_NETWORK_ID, we create a new empty
* network configuration. Otherwise, the networkId should refer to an existing configuration.
*
* @param config provided WifiConfiguration object.
* @param uid UID of the app requesting the network addition/modification.
* @return NetworkUpdateResult object representing status of the update.
*/
public NetworkUpdateResult addOrUpdateNetwork(WifiConfiguration config, int uid) {
if (!doesUidBelongToCurrentUser(uid)) {
Log.e(TAG, "UID " + uid + " not visible to the current user");
return new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID);
}
if (config == null) {
Log.e(TAG, "Cannot add/update network with null config");
return new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID);
}
if (mPendingStoreRead) {
Log.e(TAG, "Cannot add/update network before store is read!");
return new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID);
}
NetworkUpdateResult result = addOrUpdateNetworkInternal(config, uid);
if (!result.isSuccess()) {
Log.e(TAG, "Failed to add/update network " + config.getPrintableSsid());
return result;
}
WifiConfiguration newConfig = getInternalConfiguredNetwork(result.getNetworkId());
sendConfiguredNetworkChangedBroadcast(
newConfig,
result.isNewNetwork()
? WifiManager.CHANGE_REASON_ADDED
: WifiManager.CHANGE_REASON_CONFIG_CHANGE);
// Unless the added network is ephemeral or Passpoint, persist the network update/addition.
if (!config.ephemeral && !config.isPasspoint()) {
saveToStore(true);
if (mListener != null) {
if (result.isNewNetwork()) {
mListener.onSavedNetworkAdded(newConfig.networkId);
} else {
mListener.onSavedNetworkUpdated(newConfig.networkId);
}
}
}
return result;
}
/**
* Add a network or update a network configuration to our database.
* If the supplied networkId is INVALID_NETWORK_ID, we create a new empty
* network configuration. Otherwise, the networkId should refer to an existing configuration.
*
* @param config provided WifiConfiguration object.
* @param uid UID of the app requesting the network addition/deletion.
* @return NetworkUpdateResult object representing status of the update.
*/
private NetworkUpdateResult addOrUpdateNetworkInternal(WifiConfiguration config, int uid) {
if (mVerboseLoggingEnabled) {
Log.v(TAG, "Adding/Updating network " + config.getPrintableSsid());
}
WifiConfiguration newInternalConfig = null;
// First check if we already have a network with the provided network id or configKey.
WifiConfiguration existingInternalConfig = getInternalConfiguredNetwork(config);
// No existing network found. So, potentially a network add.
if (existingInternalConfig == null) {
if (!WifiConfigurationUtil.validate(config, WifiConfigurationUtil.VALIDATE_FOR_ADD)) {
Log.e(TAG, "Cannot add network with invalid config");
return new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID);
}
newInternalConfig = createNewInternalWifiConfigurationFromExternal(config, uid);
// Since the original config provided may have had an empty
// {@link WifiConfiguration#allowedKeyMgmt} field, check again if we already have a
// network with the the same configkey.
existingInternalConfig = getInternalConfiguredNetwork(newInternalConfig.configKey());
}
// Existing network found. So, a network update.
if (existingInternalConfig != null) {
if (!WifiConfigurationUtil.validate(
config, WifiConfigurationUtil.VALIDATE_FOR_UPDATE)) {
Log.e(TAG, "Cannot update network with invalid config");
return new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID);
}
// Check for the app's permission before we let it update this network.
if (!canModifyNetwork(existingInternalConfig, uid, DISALLOW_LOCKDOWN_CHECK_BYPASS)) {
Log.e(TAG, "UID " + uid + " does not have permission to update configuration "
+ config.configKey());
return new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID);
}
newInternalConfig =
updateExistingInternalWifiConfigurationFromExternal(
existingInternalConfig, config, uid);
}
// Only add networks with proxy settings if the user has permission to
if (WifiConfigurationUtil.hasProxyChanged(existingInternalConfig, newInternalConfig)
&& !canModifyProxySettings(uid)) {
Log.e(TAG, "UID " + uid + " does not have permission to modify proxy Settings "
+ config.configKey() + ". Must have NETWORK_SETTINGS,"
+ " or be device or profile owner.");
return new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID);
}
// Update the keys for non-Passpoint enterprise networks. For Passpoint, the certificates
// and keys are installed at the time the provider is installed.
if (config.enterpriseConfig != null
&& config.enterpriseConfig.getEapMethod() != WifiEnterpriseConfig.Eap.NONE
&& !config.isPasspoint()) {
if (!(mWifiKeyStore.updateNetworkKeys(newInternalConfig, existingInternalConfig))) {
return new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID);
}
}
boolean newNetwork = (existingInternalConfig == null);
// This is needed to inform IpClient about any IP configuration changes.
boolean hasIpChanged =
newNetwork || WifiConfigurationUtil.hasIpChanged(
existingInternalConfig, newInternalConfig);
boolean hasProxyChanged =
newNetwork || WifiConfigurationUtil.hasProxyChanged(
existingInternalConfig, newInternalConfig);
// Reset the |hasEverConnected| flag if the credential parameters changed in this update.
boolean hasCredentialChanged =
newNetwork || WifiConfigurationUtil.hasCredentialChanged(
existingInternalConfig, newInternalConfig);
if (hasCredentialChanged) {
newInternalConfig.getNetworkSelectionStatus().setHasEverConnected(false);
}
// Add it to our internal map. This will replace any existing network configuration for
// updates.
try {
mConfiguredNetworks.put(newInternalConfig);
} catch (IllegalArgumentException e) {
Log.e(TAG, "Failed to add network to config map", e);
return new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID);
}
if (mDeletedEphemeralSSIDs.remove(config.SSID)) {
if (mVerboseLoggingEnabled) {
Log.v(TAG, "Removed from ephemeral blacklist: " + config.SSID);
}
}
// Stage the backup of the SettingsProvider package which backs this up.
mBackupManagerProxy.notifyDataChanged();
NetworkUpdateResult result =
new NetworkUpdateResult(hasIpChanged, hasProxyChanged, hasCredentialChanged);
result.setIsNewNetwork(newNetwork);
result.setNetworkId(newInternalConfig.networkId);
localLog("addOrUpdateNetworkInternal: added/updated config."
+ " netId=" + newInternalConfig.networkId
+ " configKey=" + newInternalConfig.configKey()
+ " uid=" + Integer.toString(newInternalConfig.creatorUid)
+ " name=" + newInternalConfig.creatorName);
return result;
}
1)这次梳理的保存网络是针对新网络添加,新网络添加会对Settings传来的如下参数进行校验,这和之前梳理的是正好对上的。
public static boolean validate(WifiConfiguration config, boolean isAdd) {
if (!validateSsid(config.SSID, isAdd)) {
return false;
}
if (!validateKeyMgmt(config.allowedKeyManagement)) {
return false;
}
if (config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_PSK)
&& !validatePsk(config.preSharedKey, isAdd)) {
return false;
}
if (!validateIpConfiguration(config.getIpConfiguration())) {
return false;
}
// TBD: Validate some enterprise params as well in the future here.
return true;
}
2)校验成功以后会将外部配置转换为内部配置
/**
* Create a new internal WifiConfiguration object by copying over parameters from the provided
* external configuration and set defaults for the appropriate parameters.
*
* @param externalConfig WifiConfiguration object provided from the external API.
* @return New WifiConfiguration object with parameters merged from the provided external
* configuration.
*/
private WifiConfiguration createNewInternalWifiConfigurationFromExternal(
WifiConfiguration externalConfig, int uid) {
WifiConfiguration newInternalConfig = new WifiConfiguration();
// First allocate a new network ID for the configuration.
newInternalConfig.networkId = mNextNetworkId++;
// First set defaults in the new configuration created.
setDefaultsInWifiConfiguration(newInternalConfig);
// Copy over all the public elements from the provided configuration.
mergeWithInternalWifiConfiguration(newInternalConfig, externalConfig);
// Copy over the hidden configuration parameters. These are the only parameters used by
// system apps to indicate some property about the network being added.
// These are only copied over for network additions and ignored for network updates.
newInternalConfig.requirePMF = externalConfig.requirePMF;
newInternalConfig.noInternetAccessExpected = externalConfig.noInternetAccessExpected;
newInternalConfig.ephemeral = externalConfig.ephemeral;
newInternalConfig.useExternalScores = externalConfig.useExternalScores;
newInternalConfig.shared = externalConfig.shared;
// Add debug information for network addition.
newInternalConfig.creatorUid = newInternalConfig.lastUpdateUid = uid;
newInternalConfig.creatorName = newInternalConfig.lastUpdateName =
mContext.getPackageManager().getNameForUid(uid);
newInternalConfig.creationTime = newInternalConfig.updateTime =
createDebugTimeStampString(mClock.getWallClockMillis());
return newInternalConfig;
}
3)初始化NetworkUpdateResult,由于是newNetwork,所以以下参数都是true。
boolean newNetwork = (existingInternalConfig == null);
// This is needed to inform IpClient about any IP configuration changes.
boolean hasIpChanged =
newNetwork || WifiConfigurationUtil.hasIpChanged(
existingInternalConfig, newInternalConfig);
boolean hasProxyChanged =
newNetwork || WifiConfigurationUtil.hasProxyChanged(
existingInternalConfig, newInternalConfig);
// Reset the |hasEverConnected| flag if the credential parameters changed in this update.
boolean hasCredentialChanged =
newNetwork || WifiConfigurationUtil.hasCredentialChanged(
existingInternalConfig, newInternalConfig);
if (hasCredentialChanged) {
newInternalConfig.getNetworkSelectionStatus().setHasEverConnected(false);
}
// Add it to our internal map. This will replace any existing network configuration for
// updates.
try {
mConfiguredNetworks.put(newInternalConfig);
} catch (IllegalArgumentException e) {
Log.e(TAG, "Failed to add network to config map", e);
return new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID);
}
if (mDeletedEphemeralSSIDs.remove(config.SSID)) {
if (mVerboseLoggingEnabled) {
Log.v(TAG, "Removed from ephemeral blacklist: " + config.SSID);
}
}
// Stage the backup of the SettingsProvider package which backs this up.
mBackupManagerProxy.notifyDataChanged();
NetworkUpdateResult result =
new NetworkUpdateResult(hasIpChanged, hasProxyChanged, hasCredentialChanged);
result.setIsNewNetwork(newNetwork);
result.setNetworkId(newInternalConfig.networkId);
localLog("addOrUpdateNetworkInternal: added/updated config."
+ " netId=" + newInternalConfig.networkId
+ " configKey=" + newInternalConfig.configKey()
+ " uid=" + Integer.toString(newInternalConfig.creatorUid)
+ " name=" + newInternalConfig.creatorName);
4)保存数据
mWifiConfigStore.registerStoreData(mNetworkListStoreData);
mWifiConfigStore.registerStoreData(mDeletedEphemeralSsidsStoreData);
// Unless the added network is ephemeral or Passpoint, persist the network update/addition.
if (!config.ephemeral && !config.isPasspoint()) {
saveToStore(true);
if (mListener != null) {
if (result.isNewNetwork()) {
mListener.onSavedNetworkAdded(newConfig.networkId);
} else {
mListener.onSavedNetworkUpdated(newConfig.networkId);
}
}
}
/**
* Save the current snapshot of the in-memory lists to the config store.
*
* @param forceWrite Whether the write needs to be forced or not.
* @return Whether the write was successful or not, this is applicable only for force writes.
*/
public boolean saveToStore(boolean forceWrite) {
if (mPendingStoreRead) {
Log.e(TAG, "Cannot save to store before store is read!");
return false;
}
ArrayList sharedConfigurations = new ArrayList<>();
ArrayList userConfigurations = new ArrayList<>();
// List of network IDs for legacy Passpoint configuration to be removed.
List legacyPasspointNetId = new ArrayList<>();
for (WifiConfiguration config : mConfiguredNetworks.valuesForAllUsers()) {
// Ignore ephemeral networks and non-legacy Passpoint configurations.
if (config.ephemeral || (config.isPasspoint() && !config.isLegacyPasspointConfig)) {
continue;
}
// Migrate the legacy Passpoint configurations owned by the current user to
// {@link PasspointManager}.
if (config.isLegacyPasspointConfig && WifiConfigurationUtil.doesUidBelongToAnyProfile(
config.creatorUid, mUserManager.getProfiles(mCurrentUserId))) {
legacyPasspointNetId.add(config.networkId);
// Migrate the legacy Passpoint configuration and add it to PasspointManager.
if (!PasspointManager.addLegacyPasspointConfig(config)) {
Log.e(TAG, "Failed to migrate legacy Passpoint config: " + config.FQDN);
}
// This will prevent adding |config| to the |sharedConfigurations|.
continue;
}
// We push all shared networks & private networks not belonging to the current
// user to the shared store. Ideally, private networks for other users should
// not even be in memory,
// But, this logic is in place to deal with store migration from N to O
// because all networks were previously stored in a central file. We cannot
// write these private networks to the user specific store until the corresponding
// user logs in.
if (config.shared || !WifiConfigurationUtil.doesUidBelongToAnyProfile(
config.creatorUid, mUserManager.getProfiles(mCurrentUserId))) {
sharedConfigurations.add(config);
} else {
userConfigurations.add(config);
}
}
// Remove the configurations for migrated Passpoint configurations.
for (int networkId : legacyPasspointNetId) {
mConfiguredNetworks.remove(networkId);
}
// Setup store data for write.
mNetworkListStoreData.setSharedConfigurations(sharedConfigurations);
mNetworkListStoreData.setUserConfigurations(userConfigurations);
mDeletedEphemeralSsidsStoreData.setSsidList(mDeletedEphemeralSSIDs);
try {
mWifiConfigStore.write(forceWrite);
} catch (IOException e) {
Log.wtf(TAG, "Writing to store failed. Saved networks maybe lost!", e);
return false;
} catch (XmlPullParserException e) {
Log.wtf(TAG, "XML serialization for store failed. Saved networks maybe lost!", e);
return false;
}
return true;
}
简单看了下是以xml的形式保存下WiFi的属性配置。而xml最初是由WifiInjector初始化时创建的
WifiInjector.java
mWifiConfigStore = new WifiConfigStore(
mContext, wifiStateMachineLooper, mClock,
WifiConfigStore.createSharedFile());
// Legacy config store
DelayedDiskWrite writer = new DelayedDiskWrite();
mIpConfigStore = new IpConfigStore(writer);
// Config Manager
mWifiConfigManager = new WifiConfigManager(mContext, mClock,
UserManager.get(mContext), TelephonyManager.from(mContext),
mWifiKeyStore, mWifiConfigStore, mWifiPermissionsUtil,
mWifiPermissionsWrapper, new NetworkListStoreData(mContext),
new DeletedEphemeralSsidsStoreData());
WifiConfigStore.java
private static StoreFile createFile(File storeBaseDir) {
File storeDir = new File(storeBaseDir, STORE_DIRECTORY_NAME);
if (!storeDir.exists()) {
if (!storeDir.mkdir()) {
Log.w(TAG, "Could not create store directory " + storeDir);
}
}
return new StoreFile(new File(storeDir, STORE_FILE_NAME));
}
/**
* Create a new instance of the shared store file.
*
* @return new instance of the store file or null if the directory cannot be created.
*/
public static StoreFile createSharedFile() {
return createFile(Environment.getDataMiscDirectory());
}
/**
* Config store file name for both shared & user specific stores.
*/
private static final String STORE_FILE_NAME = "WifiConfigStore.xml";
/**
* Directory to store the config store files in.
*/
private static final String STORE_DIRECTORY_NAME = "wifi";
应该是在/data/misc/wifi/WifiConfigStore.xml下保存了。
/**
* Enable a network using the public {@link WifiManager#enableNetwork(int, boolean)} API.
*
* @param networkId network ID of the network that needs the update.
* @param disableOthers Whether to disable all other networks or not. This is used to indicate
* that the app requested connection to a specific network.
* @param uid uid of the app requesting the update.
* @return true if it succeeds, false otherwise
*/
public boolean enableNetwork(int networkId, boolean disableOthers, int uid) {
if (mVerboseLoggingEnabled) {
Log.v(TAG, "Enabling network " + networkId + " (disableOthers " + disableOthers + ")");
}
if (!doesUidBelongToCurrentUser(uid)) {
Log.e(TAG, "UID " + uid + " not visible to the current user");
return false;
}
WifiConfiguration config = getInternalConfiguredNetwork(networkId);
if (config == null) {
return false;
}
if (!canModifyNetwork(config, uid, DISALLOW_LOCKDOWN_CHECK_BYPASS)) {
Log.e(TAG, "UID " + uid + " does not have permission to update configuration "
+ config.configKey());
return false;
}
if (!updateNetworkSelectionStatus(
networkId, WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLE)) {
return false;
}
if (disableOthers) {
setLastSelectedNetwork(networkId);
}
saveToStore(true);
return true;
}
/**
* Update a network's status (both internal and public) according to the update reason and
* its current state.
*
* Each network has 2 status:
* 1. NetworkSelectionStatus: This is internal selection status of the network. This is used
* for temporarily disabling a network for Network Selector.
* 2. Status: This is the exposed status for a network. This is mostly set by
* the public API's {@link WifiManager#enableNetwork(int, boolean)} &
* {@link WifiManager#disableNetwork(int)}.
*
* @param networkId network ID of the network that needs the update.
* @param reason reason to update the network.
* @return true if the input configuration has been updated, false otherwise.
*/
public boolean updateNetworkSelectionStatus(int networkId, int reason) {
WifiConfiguration config = getInternalConfiguredNetwork(networkId);
if (config == null) {
return false;
}
return updateNetworkSelectionStatus(config, reason);
}
/**
* Update a network's status (both internal and public) according to the update reason and
* its current state.
*
* @param config network to be updated.
* @param reason reason code for update.
* @return true if the input configuration has been updated, false otherwise.
*/
private boolean updateNetworkSelectionStatus(WifiConfiguration config, int reason) {
NetworkSelectionStatus networkStatus = config.getNetworkSelectionStatus();
if (reason != NetworkSelectionStatus.NETWORK_SELECTION_ENABLE) {
networkStatus.incrementDisableReasonCounter(reason);
// For network disable reasons, we should only update the status if we cross the
// threshold.
int disableReasonCounter = networkStatus.getDisableReasonCounter(reason);
int disableReasonThreshold = NETWORK_SELECTION_DISABLE_THRESHOLD[reason];
if (disableReasonCounter < disableReasonThreshold) {
if (mVerboseLoggingEnabled) {
Log.v(TAG, "Disable counter for network " + config.getPrintableSsid()
+ " for reason "
+ NetworkSelectionStatus.getNetworkDisableReasonString(reason) + " is "
+ networkStatus.getDisableReasonCounter(reason) + " and threshold is "
+ disableReasonThreshold);
}
return true;
}
}
return setNetworkSelectionStatus(config, reason);
}
/**
* Sets a network's status (both internal and public) according to the update reason and
* its current state.
*
* This updates the network's {@link WifiConfiguration#mNetworkSelectionStatus} field and the
* public {@link WifiConfiguration#status} field if the network is either enabled or
* permanently disabled.
*
* @param config network to be updated.
* @param reason reason code for update.
* @return true if the input configuration has been updated, false otherwise.
*/
private boolean setNetworkSelectionStatus(WifiConfiguration config, int reason) {
NetworkSelectionStatus networkStatus = config.getNetworkSelectionStatus();
if (reason < 0 || reason >= NetworkSelectionStatus.NETWORK_SELECTION_DISABLED_MAX) {
Log.e(TAG, "Invalid Network disable reason " + reason);
return false;
}
if (reason == NetworkSelectionStatus.NETWORK_SELECTION_ENABLE) {
setNetworkSelectionEnabled(config);
setNetworkStatus(config, WifiConfiguration.Status.ENABLED);
} else if (reason < NetworkSelectionStatus.DISABLED_TLS_VERSION_MISMATCH) {
setNetworkSelectionTemporarilyDisabled(config, reason);
} else {
setNetworkSelectionPermanentlyDisabled(config, reason);
setNetworkStatus(config, WifiConfiguration.Status.DISABLED);
}
localLog("setNetworkSelectionStatus: configKey=" + config.configKey()
+ " networkStatus=" + networkStatus.getNetworkStatusString() + " disableReason="
+ networkStatus.getNetworkDisableReasonString() + " at="
+ createDebugTimeStampString(mClock.getWallClockMillis()));
saveToStore(false);
return true;
}
/**
* Helper method to mark a network enabled for network selection.
*/
private void setNetworkSelectionEnabled(WifiConfiguration config) {
NetworkSelectionStatus status = config.getNetworkSelectionStatus();
status.setNetworkSelectionStatus(
NetworkSelectionStatus.NETWORK_SELECTION_ENABLED);
status.setDisableTime(
NetworkSelectionStatus.INVALID_NETWORK_SELECTION_DISABLE_TIMESTAMP);
status.setNetworkSelectionDisableReason(NetworkSelectionStatus.NETWORK_SELECTION_ENABLE);
// Clear out all the disable reason counters.
status.clearDisableReasonCounter();
if (mListener != null) mListener.onSavedNetworkEnabled(config.networkId);
}
/**
* Helper method to set the publicly exposed status for the network and send out the network
* status change broadcast.
*/
private void setNetworkStatus(WifiConfiguration config, int status) {
config.status = status;
sendConfiguredNetworkChangedBroadcast(config, WifiManager.CHANGE_REASON_CONFIG_CHANGE);
}
saveConfiguration应该是对应于saveToStore?