summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--service/java/com/android/server/wifi/ConfigurationMap.java95
-rw-r--r--service/java/com/android/server/wifi/WifiConfigStore.java342
-rw-r--r--service/java/com/android/server/wifi/WifiService.java6
-rw-r--r--service/java/com/android/server/wifi/WifiServiceImpl.java9
-rw-r--r--service/java/com/android/server/wifi/WifiStateMachine.java89
-rw-r--r--tests/wifitests/src/com/android/server/wifi/ConfigurationMapTest.java198
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiConfigStoreTest.java556
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiConfigurationUtil.java42
8 files changed, 1137 insertions, 200 deletions
diff --git a/service/java/com/android/server/wifi/ConfigurationMap.java b/service/java/com/android/server/wifi/ConfigurationMap.java
index 837c5799c..809952014 100644
--- a/service/java/com/android/server/wifi/ConfigurationMap.java
+++ b/service/java/com/android/server/wifi/ConfigurationMap.java
@@ -1,6 +1,7 @@
package com.android.server.wifi;
import android.net.wifi.WifiConfiguration;
+import android.os.UserHandle;
import java.util.ArrayList;
import java.util.Collection;
@@ -12,14 +13,21 @@ import java.util.Map;
public class ConfigurationMap {
private final Map<Integer, WifiConfiguration> mPerID = new HashMap<>();
private final Map<Integer, WifiConfiguration> mPerConfigKey = new HashMap<>();
- private final Map<String, Integer> mPerFQDN = new HashMap<>();
+
+ private final Map<Integer, WifiConfiguration> mPerIDForCurrentUser = new HashMap<>();
+ private final Map<String, WifiConfiguration> mPerFQDNForCurrentUser = new HashMap<>();
+
+ private int mCurrentUserId = UserHandle.USER_SYSTEM;
// RW methods:
- public WifiConfiguration put(int netid, WifiConfiguration config) {
- WifiConfiguration current = mPerID.put(netid, config);
+ public WifiConfiguration put(WifiConfiguration config) {
+ final WifiConfiguration current = mPerID.put(config.networkId, config);
mPerConfigKey.put(config.configKey().hashCode(), config); // This is ridiculous...
- if (config.FQDN != null && config.FQDN.length() > 0) {
- mPerFQDN.put(config.FQDN, netid);
+ if (config.isVisibleToUser(mCurrentUserId)) {
+ mPerIDForCurrentUser.put(config.networkId, config);
+ if (config.FQDN != null && config.FQDN.length() > 0) {
+ mPerFQDNForCurrentUser.put(config.FQDN, config);
+ }
}
return current;
}
@@ -31,9 +39,11 @@ public class ConfigurationMap {
}
mPerConfigKey.remove(config.configKey().hashCode());
- Iterator<Map.Entry<String, Integer>> entries = mPerFQDN.entrySet().iterator();
+ mPerIDForCurrentUser.remove(netID);
+ Iterator<Map.Entry<String, WifiConfiguration>> entries =
+ mPerFQDNForCurrentUser.entrySet().iterator();
while (entries.hasNext()) {
- if (entries.next().getValue() == netID) {
+ if (entries.next().getValue().networkId == netID) {
entries.remove();
break;
}
@@ -44,32 +54,67 @@ public class ConfigurationMap {
public void clear() {
mPerID.clear();
mPerConfigKey.clear();
- mPerFQDN.clear();
+ mPerIDForCurrentUser.clear();
+ mPerFQDNForCurrentUser.clear();
+ }
+
+ /**
+ * Handles the switch to a different foreground user:
+ * - Hides private network configurations belonging to the previous foreground user
+ * - Reveals private network configurations belonging to the new foreground user
+ *
+ * @param userId the id of the new foreground user
+ * @return a list of {@link WifiConfiguration}s that became hidden because of the user switch
+ */
+ public List<WifiConfiguration> handleUserSwitch(int userId) {
+ mPerIDForCurrentUser.clear();
+ mPerFQDNForCurrentUser.clear();
+
+ final int previousUserId = mCurrentUserId;
+ mCurrentUserId = userId;
+
+ final List<WifiConfiguration> hiddenConfigurations = new ArrayList<>();
+ for (Map.Entry<Integer, WifiConfiguration> entry : mPerID.entrySet()) {
+ final WifiConfiguration config = entry.getValue();
+ if (config.isVisibleToUser(mCurrentUserId)) {
+ mPerIDForCurrentUser.put(entry.getKey(), config);
+ if (config.FQDN != null && config.FQDN.length() > 0) {
+ mPerFQDNForCurrentUser.put(config.FQDN, config);
+ }
+ } else if (config.isVisibleToUser(previousUserId)) {
+ hiddenConfigurations.add(config);
+ }
+ }
+
+ return hiddenConfigurations;
}
// RO methods:
- public WifiConfiguration get(int netid) {
+ public WifiConfiguration getForAllUsers(int netid) {
return mPerID.get(netid);
}
- public int size() {
+ public WifiConfiguration getForCurrentUser(int netid) {
+ return mPerIDForCurrentUser.get(netid);
+ }
+
+ public int sizeForAllUsers() {
return mPerID.size();
}
- public boolean isEmpty() {
- return mPerID.size() == 0;
+ public int sizeForCurrentUser() {
+ return mPerIDForCurrentUser.size();
}
- public WifiConfiguration getByFQDN(String fqdn) {
- Integer id = mPerFQDN.get(fqdn);
- return id != null ? mPerID.get(id) : null;
+ public WifiConfiguration getByFQDNForCurrentUser(String fqdn) {
+ return mPerFQDNForCurrentUser.get(fqdn);
}
- public WifiConfiguration getByConfigKey(String key) {
+ public WifiConfiguration getByConfigKeyForCurrentUser(String key) {
if (key == null) {
return null;
}
- for (WifiConfiguration config : mPerID.values()) {
+ for (WifiConfiguration config : mPerIDForCurrentUser.values()) {
if (config.configKey().equals(key)) {
return config;
}
@@ -77,13 +122,13 @@ public class ConfigurationMap {
return null;
}
- public WifiConfiguration getByConfigKeyID(int id) {
+ public WifiConfiguration getByConfigKeyIDForAllUsers(int id) {
return mPerConfigKey.get(id);
}
- public Collection<WifiConfiguration> getEnabledNetworks() {
+ public Collection<WifiConfiguration> getEnabledNetworksForCurrentUser() {
List<WifiConfiguration> list = new ArrayList<>();
- for (WifiConfiguration config : mPerID.values()) {
+ for (WifiConfiguration config : mPerIDForCurrentUser.values()) {
if (config.status != WifiConfiguration.Status.DISABLED) {
list.add(config);
}
@@ -91,8 +136,8 @@ public class ConfigurationMap {
return list;
}
- public WifiConfiguration getEphemeral(String ssid) {
- for (WifiConfiguration config : mPerID.values()) {
+ public WifiConfiguration getEphemeralForCurrentUser(String ssid) {
+ for (WifiConfiguration config : mPerIDForCurrentUser.values()) {
if (ssid.equals(config.SSID) && config.ephemeral) {
return config;
}
@@ -100,7 +145,11 @@ public class ConfigurationMap {
return null;
}
- public Collection<WifiConfiguration> values() {
+ public Collection<WifiConfiguration> valuesForAllUsers() {
return mPerID.values();
}
+
+ public Collection<WifiConfiguration> valuesForCurrentUser() {
+ return mPerIDForCurrentUser.values();
+ }
}
diff --git a/service/java/com/android/server/wifi/WifiConfigStore.java b/service/java/com/android/server/wifi/WifiConfigStore.java
index 35f146e1a..13218a454 100644
--- a/service/java/com/android/server/wifi/WifiConfigStore.java
+++ b/service/java/com/android/server/wifi/WifiConfigStore.java
@@ -215,7 +215,7 @@ public class WifiConfigStore extends IpConfigStore {
/* Network History Keys */
private static final String SSID_KEY = "SSID";
- private static final String CONFIG_KEY = "CONFIG";
+ static final String CONFIG_KEY = "CONFIG";
private static final String CHOICE_KEY = "CHOICE";
private static final String LINK_KEY = "LINK";
private static final String BSSID_KEY = "BSSID";
@@ -235,7 +235,7 @@ public class WifiConfigStore extends IpConfigStore {
private static final String FAILURE_KEY = "FAILURE";
private static final String DID_SELF_ADD_KEY = "DID_SELF_ADD";
private static final String PEER_CONFIGURATION_KEY = "PEER_CONFIGURATION";
- private static final String CREATOR_UID_KEY = "CREATOR_UID_KEY";
+ static final String CREATOR_UID_KEY = "CREATOR_UID_KEY";
private static final String CONNECT_UID_KEY = "CONNECT_UID_KEY";
private static final String UPDATE_UID_KEY = "UPDATE_UID";
private static final String SUPPLICANT_STATUS_KEY = "SUP_STATUS";
@@ -254,6 +254,7 @@ public class WifiConfigStore extends IpConfigStore {
private static final String USER_APPROVED_KEY = "USER_APPROVED";
private static final String CREATION_TIME_KEY = "CREATION_TIME";
private static final String UPDATE_TIME_KEY = "UPDATE_TIME";
+ static final String SHARED_KEY = "SHARED";
private static final String SEPARATOR = ": ";
private static final String NL = "\n";
@@ -739,13 +740,13 @@ public class WifiConfigStore extends IpConfigStore {
}
int getConfiguredNetworksSize() {
- return mConfiguredNetworks.size();
+ return mConfiguredNetworks.sizeForCurrentUser();
}
private List<WifiConfiguration>
getConfiguredNetworks(Map<String, String> pskMap) {
List<WifiConfiguration> networks = new ArrayList<>();
- for(WifiConfiguration config : mConfiguredNetworks.values()) {
+ for (WifiConfiguration config : mConfiguredNetworks.valuesForCurrentUser()) {
WifiConfiguration newConfig = new WifiConfiguration(config);
// When updating this condition, update WifiStateMachine's CONNECT_NETWORK handler to
// correctly handle updating existing configs that are filtered out here.
@@ -773,7 +774,7 @@ public class WifiConfigStore extends IpConfigStore {
private List<WifiConfiguration>
getAllConfiguredNetworks() {
List<WifiConfiguration> networks = new ArrayList<>();
- for(WifiConfiguration config : mConfiguredNetworks.values()) {
+ for (WifiConfiguration config : mConfiguredNetworks.valuesForCurrentUser()) {
WifiConfiguration newConfig = new WifiConfiguration(config);
networks.add(newConfig);
}
@@ -832,7 +833,7 @@ public class WifiConfigStore extends IpConfigStore {
List<WifiConfiguration> getRecentConfiguredNetworks(int milli, boolean copy) {
List<WifiConfiguration> networks = new ArrayList<WifiConfiguration>();
- for (WifiConfiguration config : mConfiguredNetworks.values()) {
+ for (WifiConfiguration config : mConfiguredNetworks.valuesForCurrentUser()) {
if (config.ephemeral) {
// Do not enumerate and return this configuration to any one,
// instead treat it as unknown. the configuration can still be retrieved
@@ -897,7 +898,7 @@ public class WifiConfigStore extends IpConfigStore {
* @return Wificonfiguration
*/
public WifiConfiguration getWifiConfiguration(int netId) {
- return mConfiguredNetworks.get(netId);
+ return mConfiguredNetworks.getForCurrentUser(netId);
}
/**
@@ -905,7 +906,7 @@ public class WifiConfigStore extends IpConfigStore {
* @return Wificonfiguration
*/
public WifiConfiguration getWifiConfiguration(String key) {
- return mConfiguredNetworks.getByConfigKey(key);
+ return mConfiguredNetworks.getByConfigKeyForCurrentUser(key);
}
/**
@@ -915,7 +916,7 @@ public class WifiConfigStore extends IpConfigStore {
void enableAllNetworks() {
boolean networkEnabledStateChanged = false;
- for (WifiConfiguration config : mConfiguredNetworks.values()) {
+ for (WifiConfiguration config : mConfiguredNetworks.valuesForCurrentUser()) {
if (config != null && !config.ephemeral
&& !config.getNetworkSelectionStatus().isNetworkEnabled()) {
if (tryEnableQualifiedNetwork(config)) {
@@ -966,10 +967,15 @@ public class WifiConfigStore extends IpConfigStore {
boolean selectNetwork(WifiConfiguration config, boolean updatePriorities, int uid) {
if (VDBG) localLogNetwork("selectNetwork", config.networkId);
if (config.networkId == INVALID_NETWORK_ID) return false;
+ if (!config.isVisibleToUser(mWifiStateMachine.getCurrentUserId())) {
+ loge("selectNetwork " + Integer.toString(config.networkId) + ": Network config is not "
+ + "visible to current user.");
+ return false;
+ }
// Reset the priority of each network at start or if it goes too high.
if (mLastPriority == -1 || mLastPriority > 1000000) {
- for(WifiConfiguration config2 : mConfiguredNetworks.values()) {
+ for (WifiConfiguration config2 : mConfiguredNetworks.valuesForCurrentUser()) {
if (updatePriorities) {
if (config2.networkId != INVALID_NETWORK_ID) {
config2.priority = 0;
@@ -1036,9 +1042,16 @@ public class WifiConfigStore extends IpConfigStore {
config.SSID == null)) {
return new NetworkUpdateResult(INVALID_NETWORK_ID);
}
+
+ if (!config.isVisibleToUser(mWifiStateMachine.getCurrentUserId())) {
+ return new NetworkUpdateResult(INVALID_NETWORK_ID);
+ }
+
if (VDBG) localLogNetwork("WifiConfigStore: saveNetwork netId", config.networkId);
if (VDBG) {
- loge("WifiConfigStore saveNetwork, size=" + mConfiguredNetworks.size()
+ logd("WifiConfigStore saveNetwork,"
+ + " size=" + Integer.toString(mConfiguredNetworks.sizeForAllUsers())
+ + " (for all users)"
+ " SSID=" + config.SSID
+ " Uid=" + Integer.toString(config.creatorUid)
+ "/" + Integer.toString(config.lastUpdateUid));
@@ -1063,12 +1076,12 @@ public class WifiConfigStore extends IpConfigStore {
if (VDBG) localLogNetwork("WifiConfigStore: will enable netId=", netId);
mWifiNative.enableNetwork(netId, false);
- conf = mConfiguredNetworks.get(netId);
+ conf = mConfiguredNetworks.getForCurrentUser(netId);
if (conf != null)
conf.status = Status.ENABLED;
}
- conf = mConfiguredNetworks.get(netId);
+ conf = mConfiguredNetworks.getForCurrentUser(netId);
if (conf != null) {
if (!conf.getNetworkSelectionStatus().isNetworkEnabled()) {
if (VDBG) localLog("WifiConfigStore: re-enabling: " + conf.SSID);
@@ -1162,7 +1175,7 @@ public class WifiConfigStore extends IpConfigStore {
void updateStatus(int netId, DetailedState state) {
if (netId != INVALID_NETWORK_ID) {
- WifiConfiguration config = mConfiguredNetworks.get(netId);
+ WifiConfiguration config = mConfiguredNetworks.getForAllUsers(netId);
if (config == null) return;
switch (state) {
case CONNECTED:
@@ -1201,7 +1214,7 @@ public class WifiConfigStore extends IpConfigStore {
return null;
}
- WifiConfiguration foundConfig = mConfiguredNetworks.getEphemeral(SSID);
+ WifiConfiguration foundConfig = mConfiguredNetworks.getEphemeralForCurrentUser(SSID);
mDeletedEphemeralSSIDs.add(SSID);
loge("Forget ephemeral SSID " + SSID + " num=" + mDeletedEphemeralSSIDs.size());
@@ -1226,7 +1239,8 @@ public class WifiConfigStore extends IpConfigStore {
boolean forgetNetwork(int netId) {
if (showNetworks) localLogNetwork("forgetNetwork", netId);
- WifiConfiguration config = mConfiguredNetworks.get(netId);
+ WifiConfiguration config = mConfiguredNetworks.getForCurrentUser(netId);
+
boolean remove = removeConfigAndSendBroadcastIfNeeded(netId);
if (!remove) {
//success but we dont want to remove the network from supplicant conf file
@@ -1255,8 +1269,11 @@ public class WifiConfigStore extends IpConfigStore {
* @return network Id
*/
int addOrUpdateNetwork(WifiConfiguration config, int uid) {
- if (showNetworks) localLogNetwork("addOrUpdateNetwork id=", config.networkId);
+ if (config == null || !config.isVisibleToUser(mWifiStateMachine.getCurrentUserId())) {
+ return WifiConfiguration.INVALID_NETWORK_ID;
+ }
+ if (showNetworks) localLogNetwork("addOrUpdateNetwork id=", config.networkId);
if (config.isPasspoint()) {
/* create a temporary SSID with providerFriendlyName */
Long csum = getChecksum(config.FQDN);
@@ -1266,7 +1283,7 @@ public class WifiConfigStore extends IpConfigStore {
NetworkUpdateResult result = addOrUpdateNetworkNative(config, uid);
if (result.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) {
- WifiConfiguration conf = mConfiguredNetworks.get(result.getNetworkId());
+ WifiConfiguration conf = mConfiguredNetworks.getForCurrentUser(result.getNetworkId());
if (conf != null) {
sendConfiguredNetworksChangedBroadcast(conf,
result.isNewNetwork ? WifiManager.CHANGE_REASON_ADDED :
@@ -1380,7 +1397,11 @@ public class WifiConfigStore extends IpConfigStore {
*/
boolean removeNetwork(int netId) {
if (showNetworks) localLogNetwork("removeNetwork", netId);
- WifiConfiguration config = mConfiguredNetworks.get(netId);
+ WifiConfiguration config = mConfiguredNetworks.getForCurrentUser(netId);
+ if (config == null) {
+ return false;
+ }
+
boolean ret = mWifiNative.removeNetwork(netId);
if (ret) {
removeConfigAndSendBroadcastIfNeeded(netId);
@@ -1399,7 +1420,7 @@ public class WifiConfigStore extends IpConfigStore {
}
private boolean removeConfigAndSendBroadcastIfNeeded(int netId) {
- WifiConfiguration config = mConfiguredNetworks.get(netId);
+ WifiConfiguration config = mConfiguredNetworks.getForCurrentUser(netId);
if (config != null) {
if (VDBG) {
loge("removeNetwork " + Integer.toString(netId) + " key=" +
@@ -1459,7 +1480,7 @@ public class WifiConfigStore extends IpConfigStore {
boolean success = true;
WifiConfiguration [] copiedConfigs =
- mConfiguredNetworks.values().toArray(new WifiConfiguration[0]);
+ mConfiguredNetworks.valuesForCurrentUser().toArray(new WifiConfiguration[0]);
for (WifiConfiguration config : copiedConfigs) {
if (app.uid != config.creatorUid || !app.packageName.equals(config.creatorName)) {
continue;
@@ -1481,7 +1502,7 @@ public class WifiConfigStore extends IpConfigStore {
boolean success = true;
WifiConfiguration[] copiedConfigs =
- mConfiguredNetworks.values().toArray(new WifiConfiguration[0]);
+ mConfiguredNetworks.valuesForAllUsers().toArray(new WifiConfiguration[0]);
for (WifiConfiguration config : copiedConfigs) {
if (userId != UserHandle.getUserId(config.creatorUid)) {
continue;
@@ -1506,6 +1527,11 @@ public class WifiConfigStore extends IpConfigStore {
* @return {@code true} if it succeeds, {@code false} otherwise
*/
boolean enableNetwork(int netId, boolean disableOthers, int uid) {
+ WifiConfiguration config = mConfiguredNetworks.getForCurrentUser(netId);
+ if (config == null) {
+ return false;
+ }
+
boolean ret = enableNetworkWithoutBroadcast(netId, disableOthers);
if (disableOthers) {
if (VDBG) localLogNetwork("enableNetwork(disableOthers=true, uid=" + uid + ") ", netId);
@@ -1516,7 +1542,7 @@ public class WifiConfigStore extends IpConfigStore {
if (VDBG) localLogNetwork("enableNetwork(disableOthers=false) ", netId);
WifiConfiguration enabledNetwork;
synchronized(mConfiguredNetworks) { // !!! Useless synchronization!
- enabledNetwork = mConfiguredNetworks.get(netId);
+ enabledNetwork = mConfiguredNetworks.getForCurrentUser(netId);
}
// check just in case the network was removed by someone else.
if (enabledNetwork != null) {
@@ -1528,10 +1554,14 @@ public class WifiConfigStore extends IpConfigStore {
}
boolean enableNetworkWithoutBroadcast(int netId, boolean disableOthers) {
+ final WifiConfiguration config = mConfiguredNetworks.getForCurrentUser(netId);
+ if (config == null) {
+ return false;
+ }
+
boolean ret = mWifiNative.enableNetwork(netId, disableOthers);
- WifiConfiguration config = mConfiguredNetworks.get(netId);
- if (config != null) config.status = Status.ENABLED;
+ config.status = Status.ENABLED;
if (disableOthers) {
markAllNetworksDisabledExcept(netId);
@@ -1542,7 +1572,7 @@ public class WifiConfigStore extends IpConfigStore {
void disableAllNetworks() {
if (VDBG) localLog("disableAllNetworks");
boolean networkDisabled = false;
- for (WifiConfiguration enabled : mConfiguredNetworks.getEnabledNetworks()) {
+ for (WifiConfiguration enabled : mConfiguredNetworks.getEnabledNetworksForCurrentUser()) {
if(mWifiNative.disableNetwork(enabled.networkId)) {
networkDisabled = true;
enabled.status = Status.DISABLED;
@@ -1845,7 +1875,7 @@ public class WifiConfigStore extends IpConfigStore {
* Fetch the static IP configuration for a given network id
*/
StaticIpConfiguration getStaticIpConfiguration(int netId) {
- WifiConfiguration config = mConfiguredNetworks.get(netId);
+ WifiConfiguration config = mConfiguredNetworks.getForCurrentUser(netId);
if (config != null) {
return config.getStaticIpConfiguration();
}
@@ -1856,7 +1886,7 @@ public class WifiConfigStore extends IpConfigStore {
* Set the static IP configuration for a given network id
*/
void setStaticIpConfiguration(int netId, StaticIpConfiguration staticIpConfiguration) {
- WifiConfiguration config = mConfiguredNetworks.get(netId);
+ WifiConfiguration config = mConfiguredNetworks.getForCurrentUser(netId);
if (config != null) {
config.setStaticIpConfiguration(staticIpConfiguration);
}
@@ -1866,7 +1896,7 @@ public class WifiConfigStore extends IpConfigStore {
* set default GW MAC address
*/
void setDefaultGwMacAddress(int netId, String macAddress) {
- WifiConfiguration config = mConfiguredNetworks.get(netId);
+ WifiConfiguration config = mConfiguredNetworks.getForCurrentUser(netId);
if (config != null) {
//update defaultGwMacAddress
config.defaultGwMacAddress = macAddress;
@@ -1880,7 +1910,7 @@ public class WifiConfigStore extends IpConfigStore {
* @return ProxyInfo for the network id
*/
ProxyInfo getProxyProperties(int netId) {
- WifiConfiguration config = mConfiguredNetworks.get(netId);
+ WifiConfiguration config = mConfiguredNetworks.getForCurrentUser(netId);
if (config != null) {
return config.getHttpProxy();
}
@@ -1893,7 +1923,7 @@ public class WifiConfigStore extends IpConfigStore {
* @return {@code true} if using static ip for netId
*/
boolean isUsingStaticIp(int netId) {
- WifiConfiguration config = mConfiguredNetworks.get(netId);
+ WifiConfiguration config = mConfiguredNetworks.getForCurrentUser(netId);
if (config != null && config.getIpAssignment() == IpAssignment.STATIC) {
return true;
}
@@ -1901,7 +1931,7 @@ public class WifiConfigStore extends IpConfigStore {
}
boolean isEphemeral(int netId) {
- WifiConfiguration config = mConfiguredNetworks.get(netId);
+ WifiConfiguration config = mConfiguredNetworks.getForCurrentUser(netId);
return config != null && config.ephemeral;
}
@@ -1935,7 +1965,7 @@ public class WifiConfigStore extends IpConfigStore {
mLastPriority = 0;
- mConfiguredNetworks.clear();
+ final Map<String, WifiConfiguration> configs = new HashMap<>();
final SparseArray<Map<String, String>> networkExtras = new SparseArray<>();
@@ -1993,6 +2023,9 @@ public class WifiConfigStore extends IpConfigStore {
config.networkId, ID_STRING_VAR_NAME));
if (fqdn != null) {
extras.put(ID_STRING_KEY_FQDN, fqdn);
+ config.FQDN = fqdn;
+ // Mark the configuration as a Hotspot 2.0 network.
+ config.providerFriendlyName = "";
}
}
networkExtras.put(config.networkId, extras);
@@ -2013,40 +2046,64 @@ public class WifiConfigStore extends IpConfigStore {
config.setIpAssignment(IpAssignment.DHCP);
config.setProxySettings(ProxySettings.NONE);
- WifiConfiguration possibleOldConfig =
- mConfiguredNetworks.getByConfigKey(config.configKey());
- if (possibleOldConfig != null) {
- // That SSID is already known, just ignore this duplicate entry
+ if (!WifiServiceImpl.isValid(config)) {
if (showNetworks) {
- localLog("update duplicate network " + possibleOldConfig.networkId
- + " with " + config.networkId);
+ localLog("Ignoring network " + config.networkId + " because configuration "
+ + "loaded from wpa_supplicant.conf is not valid.");
}
- // This can happen after the user manually connected to an AP and try to use WPS
- // to connect the AP later.In this way, supplicant will create a new network for
- // the AP although there is an existing network already.
- mWifiNative.removeNetwork(possibleOldConfig.networkId);
- mConfiguredNetworks.remove(possibleOldConfig.networkId);
- mConfiguredNetworks.put(config.networkId, config);
-
- } else if(WifiServiceImpl.isValid(config)){
- mConfiguredNetworks.put(config.networkId, config);
- if (showNetworks) {
- localLogNetwork("loaded configured network", config.networkId);
- }
- } else {
+ continue;
+ }
+
+ // The configKey is explicitly stored in wpa_supplicant.conf, because config does
+ // not contain sufficient information to compute it at this point.
+ String configKey = extras.get(ID_STRING_KEY_CONFIG_KEY);
+ if (configKey == null) {
+ // Handle the legacy case where the configKey is not stored in
+ // wpa_supplicant.conf but can be computed straight away.
+ configKey = config.configKey();
+ }
+
+ final WifiConfiguration duplicateConfig = configs.put(configKey, config);
+ if (duplicateConfig != null) {
+ // The network is already known. Overwrite the duplicate entry.
if (showNetworks) {
- log("Ignoring loaded configured for network " + config.networkId
- + " because config are not valid");
+ localLog("Replacing duplicate network " + duplicateConfig.networkId
+ + " with " + config.networkId + ".");
}
+ // This can happen after the user manually connected to an AP and tried to use
+ // WPS to connect the AP later. In this case, the supplicant will create a new
+ // network for the AP although there is an existing network already.
+ mWifiNative.removeNetwork(duplicateConfig.networkId);
}
}
done = (lines.length == 1);
}
- readPasspointConfig(networkExtras);
+ readNetworkHistory(configs);
+ readPasspointConfig(configs, networkExtras);
+
+ // We are only now updating mConfiguredNetworks for two reasons:
+ // 1) The information required to compute configKeys is spread across wpa_supplicant.conf
+ // and networkHistory.txt. Thus, we had to load both files first.
+ // 2) mConfiguredNetworks caches a Passpoint network's FQDN the moment the network is added.
+ // Thus, we had to load the FQDNs first.
+ mConfiguredNetworks.clear();
+ for (Map.Entry<String, WifiConfiguration> entry : configs.entrySet()) {
+ final String configKey = entry.getKey();
+ final WifiConfiguration config = entry.getValue();
+ if (!configKey.equals(config.configKey())) {
+ if (showNetworks) {
+ log("Ignoring network " + config.networkId + " because the configKey loaded "
+ + "from wpa_supplicant.conf is not valid.");
+ }
+ mWifiNative.removeNetwork(config.networkId);
+ continue;
+ }
+ mConfiguredNetworks.put(config);
+ }
+
readIpAndProxyConfigurations();
- readNetworkHistory();
readAutoJoinConfig();
buildPnoList();
@@ -2054,10 +2111,11 @@ public class WifiConfigStore extends IpConfigStore {
sendConfiguredNetworksChangedBroadcast();
if (showNetworks) {
- localLog("loadConfiguredNetworks loaded " + mConfiguredNetworks.size() + " networks");
+ localLog("loadConfiguredNetworks loaded " + mConfiguredNetworks.sizeForAllUsers()
+ + " networks (for all users)");
}
- if (mConfiguredNetworks.isEmpty()) {
+ if (mConfiguredNetworks.sizeForAllUsers() == 0) {
// no networks? Lets log if the file contents
logKernelTime();
logContents(SUPPLICANT_CONFIG_FILE);
@@ -2093,6 +2151,12 @@ public class WifiConfigStore extends IpConfigStore {
}
private Map<String, String> readNetworkVariablesFromSupplicantFile(String key) {
+ // TODO(b/26733972): This method assumes that the SSID is a unique identifier for network
+ // configurations. That is wrong. There may be any number of networks with the same SSID.
+ // There may also be any number of network configurations for the same network. The correct
+ // unique identifier is the configKey. This method should be switched from SSID to configKey
+ // (which is either stored in wpa_supplicant.conf directly or can be computed from the
+ // information found in that file).
Map<String, String> result = new HashMap<>();
BufferedReader reader = null;
if (VDBG) loge("readNetworkVariablesFromSupplicantFile key=" + key);
@@ -2159,7 +2223,7 @@ public class WifiConfigStore extends IpConfigStore {
/* Mark all networks except specified netId as disabled */
private void markAllNetworksDisabledExcept(int netId) {
- for(WifiConfiguration config : mConfiguredNetworks.values()) {
+ for (WifiConfiguration config : mConfiguredNetworks.valuesForCurrentUser()) {
if(config != null && config.networkId != netId) {
if (config.status != Status.DISABLED) {
config.status = Status.DISABLED;
@@ -2178,7 +2242,7 @@ public class WifiConfigStore extends IpConfigStore {
// unlocked key store; unless the certificates can be stored with
// hardware encryption
- for(WifiConfiguration config : mConfiguredNetworks.values()) {
+ for (WifiConfiguration config : mConfiguredNetworks.valuesForCurrentUser()) {
if (config.allowedKeyManagement.get(KeyMgmt.WPA_EAP)
&& config.allowedKeyManagement.get(KeyMgmt.IEEE8021X)) {
@@ -2192,8 +2256,8 @@ public class WifiConfigStore extends IpConfigStore {
return false;
}
- void readPasspointConfig(SparseArray<Map<String, String>> networkExtras) {
-
+ void readPasspointConfig(Map<String, WifiConfiguration> configs,
+ SparseArray<Map<String, String>> networkExtras) {
List<HomeSP> homeSPs;
try {
homeSPs = mMOManager.loadAllSPs();
@@ -2206,7 +2270,7 @@ public class WifiConfigStore extends IpConfigStore {
for (HomeSP homeSp : homeSPs) {
String fqdn = homeSp.getFQDN();
Log.d(TAG, "Looking for " + fqdn);
- for (WifiConfiguration config : mConfiguredNetworks.values()) {
+ for (WifiConfiguration config : configs.values()) {
Log.d(TAG, "Testing " + config.SSID);
if (config.enterpriseConfig == null) {
@@ -2231,8 +2295,6 @@ public class WifiConfigStore extends IpConfigStore {
config.enterpriseConfig.setPlmn(
imsiParameter != null ? imsiParameter.toString() : null);
config.enterpriseConfig.setRealm(homeSp.getCredential().getRealm());
- // Allow mConfiguredNetworks to cache the FQDN.
- mConfiguredNetworks.put(config.networkId, config);
}
}
}
@@ -2262,12 +2324,13 @@ public class WifiConfigStore extends IpConfigStore {
/* Make a copy */
final List<WifiConfiguration> networks = new ArrayList<WifiConfiguration>();
- for (WifiConfiguration config : mConfiguredNetworks.values()) {
+ for (WifiConfiguration config : mConfiguredNetworks.valuesForAllUsers()) {
networks.add(new WifiConfiguration(config));
}
if (VDBG) {
- loge(" writeKnownNetworkHistory() num networks:" +
- mConfiguredNetworks.size() + " needWrite=" + needUpdate);
+ logd(" writeKnownNetworkHistory() num networks:"
+ + mConfiguredNetworks.sizeForAllUsers() + " (for all users) needWrite="
+ + needUpdate);
}
if (needUpdate == false) {
return;
@@ -2378,6 +2441,7 @@ public class WifiConfigStore extends IpConfigStore {
config.lastUpdateName + NL);
out.writeUTF(USER_APPROVED_KEY + SEPARATOR +
Integer.toString(config.userApproved) + NL);
+ out.writeUTF(SHARED_KEY + SEPARATOR + Boolean.toString(config.shared) + NL);
String allowedKeyManagementString =
makeString(config.allowedKeyManagement,
WifiConfiguration.KeyMgmt.strings);
@@ -2502,7 +2566,16 @@ public class WifiConfigStore extends IpConfigStore {
&& lastSelectedConfiguration.equals(config.configKey()));
}
- private void readNetworkHistory() {
+ /**
+ * Adds information stored in networkHistory.txt to the given configs. The configs are provided
+ * as a mapping from configKey to WifiConfiguration, because the WifiConfigurations themselves
+ * do not contain sufficient information to compute their configKeys until after the information
+ * that is stored in networkHistory.txt has been added to them.
+ *
+ * @param configs mapping from configKey to a WifiConfiguration that contains the information
+ * information read from wpa_supplicant.conf
+ */
+ private void readNetworkHistory(Map<String, WifiConfiguration> configs) {
if (showNetworks) {
localLog("readNetworkHistory() path:" + networkHistoryConfigFile);
}
@@ -2535,7 +2608,8 @@ public class WifiConfigStore extends IpConfigStore {
String value = line.substring(colon + 1).trim();
if (key.equals(CONFIG_KEY)) {
- config = mConfiguredNetworks.getByConfigKey(value);
+ config = configs.get(value);
+
// skip reading that configuration data
// since we don't have a corresponding network ID
if (config == null) {
@@ -2721,6 +2795,9 @@ public class WifiConfigStore extends IpConfigStore {
case USER_APPROVED_KEY:
config.userApproved = Integer.parseInt(value);
break;
+ case SHARED_KEY:
+ config.shared = Boolean.parseBoolean(value);
+ break;
}
}
}
@@ -2771,7 +2848,7 @@ public class WifiConfigStore extends IpConfigStore {
private void writeIpAndProxyConfigurations() {
final SparseArray<IpConfiguration> networks = new SparseArray<IpConfiguration>();
- for(WifiConfiguration config : mConfiguredNetworks.values()) {
+ for (WifiConfiguration config : mConfiguredNetworks.valuesForAllUsers()) {
if (!config.ephemeral) {
networks.put(configKey(config), config.getIpConfiguration());
}
@@ -2790,7 +2867,7 @@ public class WifiConfigStore extends IpConfigStore {
for (int i = 0; i < networks.size(); i++) {
int id = networks.keyAt(i);
- WifiConfiguration config = mConfiguredNetworks.getByConfigKeyID(id);
+ WifiConfiguration config = mConfiguredNetworks.getByConfigKeyIDForAllUsers(id);
// This is the only place the map is looked up through a (dangerous) hash-value!
if (config == null || config.ephemeral) {
@@ -2831,7 +2908,8 @@ public class WifiConfigStore extends IpConfigStore {
boolean existingMO = false;
// networkId of INVALID_NETWORK_ID means we want to create a new network
if (netId == INVALID_NETWORK_ID) {
- WifiConfiguration savedConfig = mConfiguredNetworks.getByConfigKey(config.configKey());
+ WifiConfiguration savedConfig =
+ mConfiguredNetworks.getByConfigKeyForCurrentUser(config.configKey());
if (savedConfig != null) {
netId = savedConfig.networkId;
} else {
@@ -3044,7 +3122,8 @@ public class WifiConfigStore extends IpConfigStore {
* In order to generate the key id, fetch uninitialized
* fields from the currently tracked configuration
*/
- WifiConfiguration currentConfig = mConfiguredNetworks.get(netId);
+ WifiConfiguration currentConfig =
+ mConfiguredNetworks.getForCurrentUser(netId);
String keyId = config.getKeyIdForCredentials(currentConfig);
if (!installKeys(enterpriseConfig, keyId)) {
@@ -3098,7 +3177,7 @@ public class WifiConfigStore extends IpConfigStore {
* when written. For example, wep key is stored as * irrespective
* of the value sent to the supplicant
*/
- WifiConfiguration currentConfig = mConfiguredNetworks.get(netId);
+ WifiConfiguration currentConfig = mConfiguredNetworks.getForCurrentUser(netId);
if (currentConfig == null) {
currentConfig = new WifiConfiguration();
currentConfig.setIpAssignment(IpAssignment.DHCP);
@@ -3122,6 +3201,7 @@ public class WifiConfigStore extends IpConfigStore {
currentConfig.numNoInternetAccessReports = config.numNoInternetAccessReports;
currentConfig.updateTime = config.updateTime;
currentConfig.creationTime = config.creationTime;
+ currentConfig.shared = config.shared;
}
if (DBG) {
log("created new config netId=" + Integer.toString(netId)
@@ -3206,7 +3286,7 @@ public class WifiConfigStore extends IpConfigStore {
currentConfig.lastUpdateUid = config.lastUpdateUid;
}
- mConfiguredNetworks.put(netId, currentConfig);
+ mConfiguredNetworks.put(currentConfig);
NetworkUpdateResult result = writeIpAndProxyConfigurationsOnChange(currentConfig, config);
result.setIsNewNetwork(newNetwork);
@@ -3215,13 +3295,13 @@ public class WifiConfigStore extends IpConfigStore {
if (homeSP != null) {
writePasspointConfigs(null, homeSP);
}
- writeKnownNetworkHistory(false);
+ writeKnownNetworkHistory(true);
return result;
}
public WifiConfiguration getWifiConfigForHomeSP(HomeSP homeSP) {
- WifiConfiguration config = mConfiguredNetworks.getByFQDN(homeSP.getFQDN());
+ WifiConfiguration config = mConfiguredNetworks.getByFQDNForCurrentUser(homeSP.getFQDN());
if (config == null) {
Log.e(TAG, "Could not find network for homeSP " + homeSP.getFQDN());
}
@@ -3229,7 +3309,7 @@ public class WifiConfigStore extends IpConfigStore {
}
public HomeSP getHomeSPForConfig(WifiConfiguration config) {
- WifiConfiguration storedConfig = mConfiguredNetworks.get(config.networkId);
+ WifiConfiguration storedConfig = mConfiguredNetworks.getForCurrentUser(config.networkId);
return storedConfig != null && storedConfig.isPasspoint() ?
mMOManager.getHomeSP(storedConfig.FQDN) : null;
}
@@ -3249,6 +3329,11 @@ public class WifiConfigStore extends IpConfigStore {
* @param config
*/
public void linkConfiguration(WifiConfiguration config) {
+ if (!config.isVisibleToUser(mWifiStateMachine.getCurrentUserId())) {
+ loge("linkConfiguration: Attempting to link config " + config.configKey()
+ + " that is not visible to the current user.");
+ return;
+ }
if (getScanDetailCache(config) != null && getScanDetailCache(config).size() > 6) {
// Ignore configurations with large number of BSSIDs
@@ -3258,7 +3343,7 @@ public class WifiConfigStore extends IpConfigStore {
// Only link WPA_PSK config
return;
}
- for (WifiConfiguration link : mConfiguredNetworks.values()) {
+ for (WifiConfiguration link : mConfiguredNetworks.valuesForCurrentUser()) {
boolean doLink = false;
if (link.configKey().equals(config.configKey())) {
@@ -3767,7 +3852,7 @@ public class WifiConfigStore extends IpConfigStore {
}
}
- for (WifiConfiguration config : mConfiguredNetworks.values()) {
+ for (WifiConfiguration config : mConfiguredNetworks.valuesForCurrentUser()) {
boolean found = false;
if (config.SSID == null || !config.SSID.equals(SSID)) {
continue;
@@ -3800,6 +3885,58 @@ public class WifiConfigStore extends IpConfigStore {
}
}
+ /**
+ * Handles the switch to a different foreground user:
+ * - Removes all ephemeral networks
+ * - Disables private network configurations belonging to the previous foreground user
+ * - Enables private network configurations belonging to the new foreground user
+ *
+ * TODO(b/25600871): Terminate background users if the new foreground user has one or more
+ * private network configurations.
+ */
+ public void handleUserSwitch() {
+ Set<WifiConfiguration> ephemeralConfigs = new HashSet<>();
+ for (WifiConfiguration config : mConfiguredNetworks.valuesForCurrentUser()) {
+ if (config.ephemeral) {
+ ephemeralConfigs.add(config);
+ }
+ }
+ if (!ephemeralConfigs.isEmpty()) {
+ for (WifiConfiguration config : ephemeralConfigs) {
+ if (config.configKey().equals(lastSelectedConfiguration)) {
+ lastSelectedConfiguration = null;
+ }
+ if (config.enterpriseConfig != null) {
+ removeKeys(config.enterpriseConfig);
+ }
+ mConfiguredNetworks.remove(config.networkId);
+ mScanDetailCaches.remove(config.networkId);
+ mWifiNative.removeNetwork(config.networkId);
+ }
+ mWifiNative.saveConfig();
+ writeKnownNetworkHistory(true);
+ }
+
+ final List<WifiConfiguration> hiddenConfigurations =
+ mConfiguredNetworks.handleUserSwitch(mWifiStateMachine.getCurrentUserId());
+ for (WifiConfiguration network : hiddenConfigurations) {
+ if (mWifiNative.disableNetwork(network.networkId)) {
+ network.status = Status.DISABLED;
+ }
+ }
+
+ for (WifiConfiguration config : mConfiguredNetworks.valuesForCurrentUser()) {
+ enableNetworkWithoutBroadcast(config.networkId, false);
+ }
+ enableAllNetworks();
+
+ // TODO(b/25600871): This broadcast is unnecessary if either of the following is true:
+ // * The user switch did not change the list of visible networks
+ // * The user switch revealed additional networks that were temporarily disabled and got
+ // re-enabled now (because enableAllNetworks() sent the same broadcast already).
+ sendConfiguredNetworksChangedBroadcast();
+ }
+
/* Compare current and new configuration and write to file on change */
private NetworkUpdateResult writeIpAndProxyConfigurationsOnChange(
WifiConfiguration currentConfig,
@@ -4141,6 +4278,10 @@ public class WifiConfigStore extends IpConfigStore {
return ipConfigFile;
}
+ protected void logd(String s) {
+ Log.d(TAG, s);
+ }
+
protected void loge(String s) {
loge(s, false);
}
@@ -4186,7 +4327,7 @@ public class WifiConfigStore extends IpConfigStore {
WifiConfiguration config;
synchronized(mConfiguredNetworks) { // !!! Useless synchronization
- config = mConfiguredNetworks.get(netId);
+ config = mConfiguredNetworks.getForAllUsers(netId);
}
if (config != null) {
@@ -4287,7 +4428,7 @@ public class WifiConfigStore extends IpConfigStore {
}
void resetSimNetworks() {
- for(WifiConfiguration config : mConfiguredNetworks.values()) {
+ for (WifiConfiguration config : mConfiguredNetworks.valuesForAllUsers()) {
if (isSimConfig(config)) {
/* This configuration may have cached Pseudonym IDs; lets remove them */
mWifiNative.setNetworkVariable(config.networkId, "identity", "NULL");
@@ -4301,28 +4442,29 @@ public class WifiConfigStore extends IpConfigStore {
// matching the one we are trying to add.
if(config.networkId != INVALID_NETWORK_ID) {
- return (mConfiguredNetworks.get(config.networkId) != null);
+ return (mConfiguredNetworks.getForCurrentUser(config.networkId) != null);
}
- return (mConfiguredNetworks.getByConfigKey(config.configKey()) != null);
+ return (mConfiguredNetworks.getByConfigKeyForCurrentUser(config.configKey()) != null);
}
/**
* Checks if uid has access to modify the configuration corresponding to networkId.
*
- * Factors involved in modifiability of a config are as follows.
- * If uid is a Device Owner app then it has full control over the device, including WiFi
- * configs.
- * If the modification is only for administrative annotation (e.g. when connecting) or the
- * config is not lockdown eligible (currently that means any config not last updated by the DO)
- * then the creator of config or an app holding OVERRIDE_CONFIG_WIFI can modify the config.
- * If the config is lockdown eligible and the modification is substantial (not annotation)
- * then the requirement to be able to modify the config by the uid is as follows:
- * a) the uid has to hold OVERRIDE_CONFIG_WIFI and
- * b) the lockdown feature should be disabled.
+ * The conditions checked are, in descending priority order:
+ * - Disallow modification if the the configuration is not visible to the uid.
+ * - Allow modification if the uid represents the Device Owner app.
+ * - Allow modification if both of the following are true:
+ * - The uid represents the configuration's creator or an app holding OVERRIDE_CONFIG_WIFI.
+ * - The modification is only for administrative annotation (e.g. when connecting) or the
+ * configuration is not lockdown eligible (which currently means that it was not last
+ * updated by the DO).
+ * - Allow modification if configuration lockdown is explicitly disabled and the uid represents
+ * an app holding OVERRIDE_CONFIG_WIFI.
+ * - In all other cases, disallow modification.
*/
boolean canModifyNetwork(int uid, int networkId, boolean onlyAnnotate) {
- WifiConfiguration config = mConfiguredNetworks.get(networkId);
+ WifiConfiguration config = mConfiguredNetworks.getForCurrentUser(networkId);
if (config == null) {
loge("canModifyNetwork: cannot find config networkId " + networkId);
@@ -4336,7 +4478,6 @@ public class WifiConfigStore extends IpConfigStore {
DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
if (isUidDeviceOwner) {
- // Device Owner has full control over the device, including WiFi Configs
return true;
}
@@ -4381,7 +4522,8 @@ public class WifiConfigStore extends IpConfigStore {
if (config.networkId != INVALID_NETWORK_ID){
netid = config.networkId;
} else {
- WifiConfiguration test = mConfiguredNetworks.getByConfigKey(config.configKey());
+ WifiConfiguration test =
+ mConfiguredNetworks.getByConfigKeyForCurrentUser(config.configKey());
if (test == null) {
return false;
} else {
@@ -4407,7 +4549,7 @@ public class WifiConfigStore extends IpConfigStore {
*/
void handleBadNetworkDisconnectReport(int netId, WifiInfo info) {
/* TODO verify the bad network is current */
- WifiConfiguration config = mConfiguredNetworks.get(netId);
+ WifiConfiguration config = mConfiguredNetworks.getForCurrentUser(netId);
if (config != null) {
if ((info.is24GHz() && info.getRssi()
<= WifiQualifiedNetworkSelector.QUALIFIED_RSSI_24G_BAND)
@@ -4431,7 +4573,7 @@ public class WifiConfigStore extends IpConfigStore {
return found;
// Look for the BSSID in our config store
- for (WifiConfiguration config : mConfiguredNetworks.values()) {
+ for (WifiConfiguration config : mConfiguredNetworks.valuesForCurrentUser()) {
if (getScanDetailCache(config) != null) {
for (ScanDetail scanDetail : getScanDetailCache(config).values()) {
if (scanDetail.getBSSIDString().equals(BSSID)) {
diff --git a/service/java/com/android/server/wifi/WifiService.java b/service/java/com/android/server/wifi/WifiService.java
index 8caa3eb4c..28e5b18a6 100644
--- a/service/java/com/android/server/wifi/WifiService.java
+++ b/service/java/com/android/server/wifi/WifiService.java
@@ -18,6 +18,7 @@ package com.android.server.wifi;
import android.content.Context;
import android.util.Log;
+
import com.android.server.SystemService;
public final class WifiService extends SystemService {
@@ -42,4 +43,9 @@ public final class WifiService extends SystemService {
mImpl.checkAndStartWifi();
}
}
+
+ @Override
+ public void onSwitchUser(int userId) {
+ mImpl.handleUserSwitch(userId);
+ }
}
diff --git a/service/java/com/android/server/wifi/WifiServiceImpl.java b/service/java/com/android/server/wifi/WifiServiceImpl.java
index 2dcac2505..832ccb102 100644
--- a/service/java/com/android/server/wifi/WifiServiceImpl.java
+++ b/service/java/com/android/server/wifi/WifiServiceImpl.java
@@ -400,6 +400,10 @@ public class WifiServiceImpl extends IWifiManager.Stub {
if (wifiEnabled) setWifiEnabled(wifiEnabled);
}
+ public void handleUserSwitch(int userId) {
+ mWifiStateMachine.handleUserSwitch(userId);
+ }
+
/**
* see {@link android.net.wifi.WifiManager#pingSupplicant()}
* @return {@code true} if the operation succeeds, {@code false} otherwise
@@ -863,11 +867,6 @@ public class WifiServiceImpl extends IWifiManager.Stub {
public boolean removeNetwork(int netId) {
enforceChangePermission();
- if (!isOwner(Binder.getCallingUid())) {
- Slog.e(TAG, "Remove is not authorized for user");
- return false;
- }
-
if (mWifiStateMachineChannel != null) {
return mWifiStateMachine.syncRemoveNetwork(mWifiStateMachineChannel, netId);
} else {
diff --git a/service/java/com/android/server/wifi/WifiStateMachine.java b/service/java/com/android/server/wifi/WifiStateMachine.java
index ab64d8ed7..cefc7df20 100644
--- a/service/java/com/android/server/wifi/WifiStateMachine.java
+++ b/service/java/com/android/server/wifi/WifiStateMachine.java
@@ -235,6 +235,8 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno
private int mHalFeatureSet = 0;
private static int mPnoResultFound = 0;
+ private int mCurrentUserId = UserHandle.USER_SYSTEM;
+
@Override
public void onPnoNetworkFound(ScanResult results[]) {
if (DBG) {
@@ -881,6 +883,8 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno
/* used to indicated RSSI threshold breach in hw */
static final int CMD_RSSI_THRESHOLD_BREACH = BASE + 164;
+ /* used to indicate that the foreground user was switched */
+ static final int CMD_USER_SWITCH = BASE + 165;
/* Wifi state machine modes of operation */
@@ -2727,6 +2731,10 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno
mWifiQualifiedNetworkSelector.dump(fd, pw, args);
}
+ public void handleUserSwitch(int userId) {
+ sendMessage(CMD_USER_SWITCH, userId);
+ }
+
/**
* ******************************************************
* Internal private functions
@@ -3331,6 +3339,10 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno
sb.append(" thresholds=");
sb.append(Arrays.toString(mRssiRanges));
break;
+ case CMD_USER_SWITCH:
+ sb.append(" userId=");
+ sb.append(Integer.toString(msg.arg1));
+ break;
default:
sb.append(" ");
sb.append(Integer.toString(msg.arg1));
@@ -6923,6 +6935,9 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno
case CMD_RSSI_THRESHOLD_BREACH:
s = "CMD_RSSI_THRESHOLD_BREACH";
break;
+ case CMD_USER_SWITCH:
+ s = "CMD_USER_SWITCH";
+ break;
default:
s = "what:" + Integer.toString(what);
break;
@@ -7131,6 +7146,15 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno
}
break;
case CMD_ADD_OR_UPDATE_NETWORK:
+ // Only the current foreground user can modify networks.
+ if (UserHandle.getUserId(message.sendingUid) != mCurrentUserId) {
+ loge("Only the current foreground user can modify networks "
+ + " currentUserId=" + mCurrentUserId
+ + " sendingUserId=" + UserHandle.getUserId(message.sendingUid));
+ replyToMessage(message, message.what, FAILURE);
+ break;
+ }
+
config = (WifiConfiguration) message.obj;
if (!recordUidIfAuthorized(config, message.sendingUid,
@@ -7173,7 +7197,16 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno
replyToMessage(message, CMD_ADD_OR_UPDATE_NETWORK, res);
break;
case CMD_REMOVE_NETWORK:
+ // Only the current foreground user can modify networks.
+ if (UserHandle.getUserId(message.sendingUid) != mCurrentUserId) {
+ loge("Only the current foreground user can modify networks "
+ + " currentUserId=" + mCurrentUserId
+ + " sendingUserId=" + UserHandle.getUserId(message.sendingUid));
+ replyToMessage(message, message.what, FAILURE);
+ break;
+ }
netId = message.arg1;
+
if (!mWifiConfigStore.canModifyNetwork(message.sendingUid, netId,
/* onlyAnnotate */ false)) {
logw("Not authorized to remove network "
@@ -7190,6 +7223,15 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno
replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
break;
case CMD_ENABLE_NETWORK:
+ // Only the current foreground user can modify networks.
+ if (UserHandle.getUserId(message.sendingUid) != mCurrentUserId) {
+ loge("Only the current foreground user can modify networks "
+ + " currentUserId=" + mCurrentUserId
+ + " sendingUserId=" + UserHandle.getUserId(message.sendingUid));
+ replyToMessage(message, message.what, FAILURE);
+ break;
+ }
+
boolean disableOthers = message.arg2 == 1;
netId = message.arg1;
config = mWifiConfigStore.getWifiConfiguration(netId);
@@ -7445,8 +7487,13 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno
// If we're autojoining a network that the user or an app explicitly selected,
// keep track of the UID that selected it.
- int lastConnectUid = mWifiConfigStore.isLastSelectedConfiguration(config) ?
- config.lastConnectUid : WifiConfiguration.UNKNOWN_UID;
+ // TODO(b/25600871): Keep track of the lastSelectedConfiguration and the
+ // lastConnectUid on a per-user basis.
+ int lastConnectUid = WifiConfiguration.UNKNOWN_UID;
+ if (mWifiConfigStore.isLastSelectedConfiguration(config)
+ && UserHandle.getUserId(config.lastConnectUid) == mCurrentUserId) {
+ lastConnectUid = config.lastConnectUid;
+ }
if (mWifiConfigStore.selectNetwork(config, /* updatePriorities = */ false,
lastConnectUid) && mWifiNative.reconnect()) {
@@ -7505,6 +7552,16 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno
mWifiConfigStore.removeNetworksForUser(message.arg1);
break;
case WifiManager.CONNECT_NETWORK:
+ // Only the current foreground user can modify networks.
+ if (UserHandle.getUserId(message.sendingUid) != mCurrentUserId) {
+ loge("Only the current foreground user can modify networks "
+ + " currentUserId=" + mCurrentUserId
+ + " sendingUserId=" + UserHandle.getUserId(message.sendingUid));
+ replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
+ WifiManager.NOT_AUTHORIZED);
+ break;
+ }
+
/**
* The connect message can contain a network id passed as arg1 on message or
* or a config passed as obj on message.
@@ -7646,6 +7703,16 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno
mWifiConnectionStatistics.numWifiManagerJoinAttempt++;
// Fall thru
case WifiStateMachine.CMD_AUTO_SAVE_NETWORK:
+ // Only the current foreground user can modify networks.
+ if (UserHandle.getUserId(message.sendingUid) != mCurrentUserId) {
+ loge("Only the current foreground user can modify networks "
+ + " currentUserId=" + mCurrentUserId
+ + " sendingUserId=" + UserHandle.getUserId(message.sendingUid));
+ replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED,
+ WifiManager.NOT_AUTHORIZED);
+ break;
+ }
+
lastSavedConfigurationAttempt = null; // Used for debug
config = (WifiConfiguration) message.obj;
if (config == null) {
@@ -7732,6 +7799,16 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno
}
break;
case WifiManager.FORGET_NETWORK:
+ // Only the current foreground user can modify networks.
+ if (UserHandle.getUserId(message.sendingUid) != mCurrentUserId) {
+ loge("Only the current foreground user can modify networks "
+ + " currentUserId=" + mCurrentUserId
+ + " sendingUserId=" + UserHandle.getUserId(message.sendingUid));
+ replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED,
+ WifiManager.NOT_AUTHORIZED);
+ break;
+ }
+
// Debug only, remember last configuration that was forgotten
WifiConfiguration toRemove
= mWifiConfigStore.getWifiConfiguration(message.arg1);
@@ -8453,6 +8530,10 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno
}
/* allow parent state to reset data for other networks */
return NOT_HANDLED;
+ case CMD_USER_SWITCH:
+ mCurrentUserId = message.arg1;
+ mWifiConfigStore.handleUserSwitch();
+ break;
default:
return NOT_HANDLED;
}
@@ -10080,6 +10161,10 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno
}
}
+ public int getCurrentUserId() {
+ return mCurrentUserId;
+ }
+
/**
* @param reason reason code from supplicant on network disconnected event
* @return true if this is a suspicious disconnect
diff --git a/tests/wifitests/src/com/android/server/wifi/ConfigurationMapTest.java b/tests/wifitests/src/com/android/server/wifi/ConfigurationMapTest.java
new file mode 100644
index 000000000..917fd77a7
--- /dev/null
+++ b/tests/wifitests/src/com/android/server/wifi/ConfigurationMapTest.java
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.wifi;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import android.net.wifi.WifiConfiguration;
+import android.os.UserHandle;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Unit tests for {@link com.android.server.wifi.ConfigurationMapTest}.
+ */
+@SmallTest
+public class ConfigurationMapTest {
+ private static final List<WifiConfiguration> CONFIGS = Arrays.asList(
+ WifiConfigurationUtil.generateWifiConfig(0, 1000000, "\"red\"", true, true, null, null),
+ WifiConfigurationUtil.generateWifiConfig(
+ 1, 1000001, "\"green\"", false, true, null, null),
+ WifiConfigurationUtil.generateWifiConfig(
+ 2, 1000002, "\"blue\"", true, false, "example.com", "Blue"),
+ WifiConfigurationUtil.generateWifiConfig(
+ 3, 1100000, "\"cyan\"", true, true, null, null),
+ WifiConfigurationUtil.generateWifiConfig(
+ 4, 1100001, "\"yellow\"", false, false, null, null),
+ WifiConfigurationUtil.generateWifiConfig(
+ 5, 1100002, "\"magenta\"", true, true, "example.org", "Magenta"));
+
+ private int mCurrentUserId = UserHandle.USER_SYSTEM;
+ private final ConfigurationMap mConfigs = new ConfigurationMap();
+
+ public void switchUser(int newUserId) {
+ Set<WifiConfiguration> hiddenConfigurations = new HashSet<>();
+ for (WifiConfiguration config : mConfigs.valuesForAllUsers()) {
+ if (config.isVisibleToUser(mCurrentUserId) && !config.isVisibleToUser(newUserId)) {
+ hiddenConfigurations.add(config);
+ }
+ }
+
+ mCurrentUserId = newUserId;
+ assertEquals(hiddenConfigurations, new HashSet<>(mConfigs.handleUserSwitch(newUserId)));
+ }
+
+ public void verifyGetters(List<WifiConfiguration> configs) {
+ final Set<WifiConfiguration> configsForCurrentUser = new HashSet<>();
+ final Set<WifiConfiguration> enabledConfigsForCurrentUser = new HashSet<>();
+ final List<WifiConfiguration> configsNotForCurrentUser = new ArrayList<>();
+
+ // Find out which network configurations should be / should not be visible to the current
+ // user. Also, check that *ForAllUsers() methods can be used to access all network
+ // configurations, irrespective of their visibility to the current user.
+ for (WifiConfiguration config : configs) {
+ if (config.isVisibleToUser(mCurrentUserId)) {
+ configsForCurrentUser.add(config);
+ if (config.status != WifiConfiguration.Status.DISABLED) {
+ enabledConfigsForCurrentUser.add(config);
+ }
+ } else {
+ configsNotForCurrentUser.add(config);
+ }
+
+ assertEquals(config, mConfigs.getForAllUsers(config.networkId));
+ assertEquals(config,
+ mConfigs.getByConfigKeyIDForAllUsers(config.configKey().hashCode()));
+ }
+
+ // Verify that *ForCurrentUser() methods can be used to access network configurations
+ // visible to the current user.
+ for (WifiConfiguration config : configsForCurrentUser) {
+ assertEquals(config, mConfigs.getForCurrentUser(config.networkId));
+ if (config.FQDN != null) {
+ assertEquals(config, mConfigs.getByFQDNForCurrentUser(config.FQDN));
+ }
+ assertEquals(config, mConfigs.getByConfigKeyForCurrentUser(config.configKey()));
+ final boolean wasEphemeral = config.ephemeral;
+ config.ephemeral = false;
+ assertNull(mConfigs.getEphemeralForCurrentUser(config.SSID));
+ config.ephemeral = true;
+ assertEquals(config, mConfigs.getEphemeralForCurrentUser(config.SSID));
+ config.ephemeral = wasEphemeral;
+ }
+
+ // Verify that *ForCurrentUser() methods cannot be used to access network configurations not
+ // visible to the current user.
+ for (WifiConfiguration config : configsNotForCurrentUser) {
+ assertNull(mConfigs.getForCurrentUser(config.networkId));
+ if (config.FQDN != null) {
+ assertNull(mConfigs.getByFQDNForCurrentUser(config.FQDN));
+ }
+ assertNull(mConfigs.getByConfigKeyForCurrentUser(config.configKey()));
+ final boolean wasEphemeral = config.ephemeral;
+ config.ephemeral = false;
+ assertNull(mConfigs.getEphemeralForCurrentUser(config.SSID));
+ config.ephemeral = true;
+ assertNull(mConfigs.getEphemeralForCurrentUser(config.SSID));
+ config.ephemeral = wasEphemeral;
+ }
+
+ // Verify that the methods which refer to more than one network configuration return the
+ // correct sets of networks.
+ assertEquals(configs.size(), mConfigs.sizeForAllUsers());
+ assertEquals(configsForCurrentUser.size(), mConfigs.sizeForCurrentUser());
+ assertEquals(enabledConfigsForCurrentUser,
+ new HashSet<WifiConfiguration>(mConfigs.getEnabledNetworksForCurrentUser()));
+ assertEquals(new HashSet<>(configs),
+ new HashSet<WifiConfiguration>(mConfigs.valuesForAllUsers()));
+ }
+
+ /**
+ * Verifies that all getters return the correct network configurations, taking into account the
+ * current user. Also verifies that handleUserSwitch() returns the list of network
+ * configurations that are no longer visible.
+ */
+ @Test
+ public void testGettersAndHandleUserSwitch() {
+ for (WifiConfiguration config : CONFIGS) {
+ assertNull(mConfigs.put(config));
+ }
+
+ verifyGetters(CONFIGS);
+
+ switchUser(10);
+ verifyGetters(CONFIGS);
+
+ switchUser(11);
+ verifyGetters(CONFIGS);
+ }
+
+ /**
+ * Verifies put(), remove() and clear().
+ */
+ @Test
+ public void testPutRemoveClear() {
+ final List<WifiConfiguration> configs = new ArrayList<>();
+ final WifiConfiguration config1 = CONFIGS.get(0);
+
+ // Verify that there are no network configurations to start with.
+ switchUser(UserHandle.getUserId(config1.creatorUid));
+ verifyGetters(configs);
+
+ // Add |config1|.
+ assertNull(mConfigs.put(config1));
+ // Verify that the getters return |config1|.
+ configs.add(config1);
+ verifyGetters(configs);
+
+ // Overwrite |config1| with |config2|.
+ final WifiConfiguration config2 = CONFIGS.get(1);
+ config2.networkId = config1.networkId;
+ assertEquals(config1, mConfigs.put(config2));
+ // Verify that the getters return |config2| only.
+ configs.clear();
+ configs.add(config2);
+ verifyGetters(configs);
+
+ // Add |config3|.
+ final WifiConfiguration config3 = CONFIGS.get(2);
+ assertNull(mConfigs.put(config3));
+ // Verify that the getters return |config2| and |config3|.
+ configs.add(config3);
+ verifyGetters(configs);
+
+ // Remove |config2|.
+ assertEquals(config2, mConfigs.remove(config2.networkId));
+ // Verify that the getters return |config3| only.
+ configs.remove(config2);
+ verifyGetters(configs);
+
+ // Clear all network configurations.
+ mConfigs.clear();
+ // Verify that the getters do not return any network configurations.
+ configs.clear();
+ verifyGetters(configs);
+ }
+}
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiConfigStoreTest.java b/tests/wifitests/src/com/android/server/wifi/WifiConfigStoreTest.java
index 0a9af5e0b..638a726e6 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiConfigStoreTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiConfigStoreTest.java
@@ -17,20 +17,25 @@
package com.android.server.wifi;
import static org.hamcrest.CoreMatchers.not;
+import static org.mockito.Mockito.anyBoolean;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.anyObject;
import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.intThat;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.net.wifi.WifiConfiguration;
-import android.net.wifi.WifiEnterpriseConfig;
+import android.os.UserHandle;
import android.test.AndroidTestCase;
+import com.android.server.net.DelayedDiskWrite;
+import com.android.server.wifi.MockAnswerUtil.AnswerWithArguments;
import com.android.server.wifi.hotspot2.omadm.MOManager;
import com.android.server.wifi.hotspot2.pps.Credential;
import com.android.server.wifi.hotspot2.pps.HomeSP;
@@ -38,31 +43,59 @@ import com.android.server.wifi.hotspot2.pps.HomeSP;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.EOFException;
+import java.io.File;
+import java.io.FileOutputStream;
import java.lang.reflect.Field;
+import java.math.BigInteger;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
/**
* Unit tests for {@link com.android.server.wifi.WifiConfigStore}.
*/
public class WifiConfigStoreTest extends AndroidTestCase {
- private static final int UID = 10;
- private static final String[] SSIDS = {"\"red\"", "\"green\"", "\"blue\""};
- private static final String[] ENCODED_SSIDS = {"726564", "677265656e", "626c7565"};
- private static final String[] FQDNS = {null, "example.com", "example.org"};
- private static final String[] PROVIDER_FRIENDLY_NAMES = {null, "Green", "Blue"};
- private static final String[] CONFIG_KEYS = {"\"red\"NONE", "example.comWPA_EAP",
- "example.orgWPA_EAP"};
+ private static final List<WifiConfiguration> CONFIGS = Arrays.asList(
+ WifiConfigurationUtil.generateWifiConfig(
+ 0, 1000000, "\"red\"", true, true, null, null),
+ WifiConfigurationUtil.generateWifiConfig(
+ 1, 1000001, "\"green\"", true, true, "example.com", "Green"),
+ WifiConfigurationUtil.generateWifiConfig(
+ 2, 1100000, "\"blue\"", false, true, "example.org", "Blue"));
+
+ private static final int[] USER_IDS = {0, 10, 11};
+ private static final Map<Integer, List<WifiConfiguration>> VISIBLE_CONFIGS = new HashMap<>();
+ static {
+ for (int userId : USER_IDS) {
+ List<WifiConfiguration> configs = new ArrayList<>();
+ for (int i = 0; i < CONFIGS.size(); ++i) {
+ if (CONFIGS.get(i).isVisibleToUser(userId)) {
+ configs.add(CONFIGS.get(i));
+ }
+ }
+ VISIBLE_CONFIGS.put(userId, configs);
+ }
+ }
@Mock private Context mContext;
@Mock private WifiStateMachine mWifiStateMachine;
@Mock private WifiNative mWifiNative;
@Mock private FrameworkFacade mFrameworkFacade;
+ @Mock private DelayedDiskWrite mWriter;
@Mock private MOManager mMOManager;
private WifiConfigStore mConfigStore;
+ private ConfigurationMap mConfiguredNetworks;
+ public byte[] mNetworkHistory;
@Override
public void setUp() throws Exception {
@@ -71,97 +104,387 @@ public class WifiConfigStoreTest extends AndroidTestCase {
final Context realContext = getContext();
when(mContext.getPackageName()).thenReturn(realContext.getPackageName());
when(mContext.getResources()).thenReturn(realContext.getResources());
+ when(mContext.getPackageManager()).thenReturn(realContext.getPackageManager());
+
+ when(mWifiStateMachine.getCurrentUserId()).thenReturn(UserHandle.USER_SYSTEM);
mConfigStore = new WifiConfigStore(mContext, mWifiStateMachine, mWifiNative,
mFrameworkFacade);
+ final Field configuredNetworksField =
+ WifiConfigStore.class.getDeclaredField("mConfiguredNetworks");
+ configuredNetworksField.setAccessible(true);
+ mConfiguredNetworks = (ConfigurationMap) configuredNetworksField.get(mConfigStore);
+
+ // Intercept writes to networkHistory.txt.
+ doAnswer(new AnswerWithArguments<Void>() {
+ public void answer(String filePath, DelayedDiskWrite.Writer writer) throws Exception {
+ final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+ final DataOutputStream stream = new DataOutputStream(buffer);
+ writer.onWriteCalled(stream);
+ stream.close();
+ mNetworkHistory = buffer.toByteArray();
+ }}).when(mWriter).write(anyString(), (DelayedDiskWrite.Writer) anyObject());
+ final Field writerField = WifiConfigStore.class.getSuperclass().getDeclaredField("mWriter");
+ writerField.setAccessible(true);
+ writerField.set(mConfigStore, mWriter);
+
when(mMOManager.isEnabled()).thenReturn(true);
final Field moManagerField = WifiConfigStore.class.getDeclaredField("mMOManager");
moManagerField.setAccessible(true);
moManagerField.set(mConfigStore, mMOManager);
}
- private WifiConfiguration generateWifiConfig(int network) {
- final WifiConfiguration config = new WifiConfiguration();
- config.SSID = SSIDS[network];
- config.creatorUid = UID;
- if (FQDNS[network] != null) {
- config.FQDN = FQDNS[network];
- config.providerFriendlyName = PROVIDER_FRIENDLY_NAMES[network];
- config.enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.SIM);
+ private void switchUser(int newUserId) {
+ when(mWifiStateMachine.getCurrentUserId()).thenReturn(newUserId);
+ mConfigStore.handleUserSwitch();
+ }
+
+ private void switchUserToCreatorOf(WifiConfiguration config) {
+ switchUser(UserHandle.getUserId(config.creatorUid));
+ }
+
+ private void addNetworks() throws Exception {
+ final int originalUserId = mWifiStateMachine.getCurrentUserId();
+
+ when(mWifiNative.setNetworkVariable(anyInt(), anyString(), anyString())).thenReturn(true);
+ when(mWifiNative.setNetworkExtra(anyInt(), anyString(), (Map<String, String>) anyObject()))
+ .thenReturn(true);
+ for (int i = 0; i < CONFIGS.size(); ++i) {
+ assertEquals(i, CONFIGS.get(i).networkId);
+ switchUserToCreatorOf(CONFIGS.get(i));
+ final WifiConfiguration config = new WifiConfiguration(CONFIGS.get(i));
+ config.networkId = -1;
+ when(mWifiNative.addNetwork()).thenReturn(i);
+ when(mWifiNative.getNetworkVariable(i, WifiConfiguration.ssidVarName))
+ .thenReturn(encodeConfigSSID(CONFIGS.get(i)));
+ mConfigStore.saveNetwork(config, config.creatorUid);
+ }
+
+ switchUser(originalUserId);
+ }
+
+ private String encodeConfigSSID(WifiConfiguration config) throws Exception {
+ return new BigInteger(1, config.SSID.substring(1, config.SSID.length() - 1)
+ .getBytes("UTF-8")).toString(16);
+ }
+
+ private WifiNative createNewWifiNativeMock() throws Exception {
+ final WifiNative wifiNative = mock(WifiNative.class);
+ final Field wifiNativeField = WifiConfigStore.class.getDeclaredField("mWifiNative");
+ wifiNativeField.setAccessible(true);
+ wifiNativeField.set(mConfigStore, wifiNative);
+ return wifiNative;
+ }
+
+ /**
+ * Verifies that getConfiguredNetworksSize() returns the number of network configurations
+ * visible to the current user.
+ */
+ public void testGetConfiguredNetworksSize() throws Exception {
+ addNetworks();
+ for (Map.Entry<Integer, List<WifiConfiguration>> entry : VISIBLE_CONFIGS.entrySet()) {
+ switchUser(entry.getKey());
+ assertEquals(entry.getValue().size(), mConfigStore.getConfiguredNetworksSize());
+ }
+ }
+
+ private void verifyNetworkConfig(WifiConfiguration expectedConfig,
+ WifiConfiguration actualConfig) {
+ assertNotNull(actualConfig);
+ assertEquals(expectedConfig.SSID, actualConfig.SSID);
+ assertEquals(expectedConfig.FQDN, actualConfig.FQDN);
+ assertEquals(expectedConfig.providerFriendlyName,
+ actualConfig.providerFriendlyName);
+ assertEquals(expectedConfig.configKey(), actualConfig.configKey(false));
+ }
+
+ private void verifyNetworkConfigs(Collection<WifiConfiguration> expectedConfigs,
+ Collection<WifiConfiguration> actualConfigs) {
+ assertEquals(expectedConfigs.size(), actualConfigs.size());
+ for (WifiConfiguration expectedConfig : expectedConfigs) {
+ WifiConfiguration actualConfig = null;
+ // Find the network configuration to test (assume that |actualConfigs| contains them in
+ // undefined order).
+ for (final WifiConfiguration candidate : actualConfigs) {
+ if (candidate.networkId == expectedConfig.networkId) {
+ actualConfig = candidate;
+ break;
+ }
+ }
+ verifyNetworkConfig(expectedConfig, actualConfig);
+ }
+ }
+
+ /**
+ * Verifies that getConfiguredNetworksSize() returns the network configurations visible to the
+ * current user.
+ */
+ public void testGetConfiguredNetworks() throws Exception {
+ addNetworks();
+ for (Map.Entry<Integer, List<WifiConfiguration>> entry : VISIBLE_CONFIGS.entrySet()) {
+ switchUser(entry.getKey());
+ verifyNetworkConfigs(entry.getValue(), mConfigStore.getConfiguredNetworks());
+ }
+ }
+
+ /**
+ * Verifies that getPrivilegedConfiguredNetworks() returns the network configurations visible to
+ * the current user.
+ */
+ public void testGetPrivilegedConfiguredNetworks() throws Exception {
+ addNetworks();
+ for (Map.Entry<Integer, List<WifiConfiguration>> entry : VISIBLE_CONFIGS.entrySet()) {
+ switchUser(entry.getKey());
+ verifyNetworkConfigs(entry.getValue(), mConfigStore.getPrivilegedConfiguredNetworks());
+ }
+ }
+
+ /**
+ * Verifies that getWifiConfiguration(int netId) can be used to access network configurations
+ * visible to the current user only.
+ */
+ public void testGetWifiConfigurationByNetworkId() throws Exception {
+ addNetworks();
+ for (int userId : USER_IDS) {
+ switchUser(userId);
+ for (WifiConfiguration expectedConfig: CONFIGS) {
+ final WifiConfiguration actualConfig =
+ mConfigStore.getWifiConfiguration(expectedConfig.networkId);
+ if (expectedConfig.isVisibleToUser(userId)) {
+ verifyNetworkConfig(expectedConfig, actualConfig);
+ } else {
+ assertNull(actualConfig);
+ }
+ }
+ }
+ }
+
+ /**
+ * Verifies that getWifiConfiguration(String key) can be used to access network configurations
+ * visible to the current user only.
+ */
+ public void testGetWifiConfigurationByConfigKey() throws Exception {
+ addNetworks();
+ for (int userId : USER_IDS) {
+ switchUser(userId);
+ for (WifiConfiguration expectedConfig: CONFIGS) {
+ final WifiConfiguration actualConfig =
+ mConfigStore.getWifiConfiguration(expectedConfig.configKey());
+ if (expectedConfig.isVisibleToUser(userId)) {
+ verifyNetworkConfig(expectedConfig, actualConfig);
+ } else {
+ assertNull(actualConfig);
+ }
+ }
+ }
+ }
+
+ /**
+ * Verifies that enableAllNetworks() enables all temporarily disabled network configurations
+ * visible to the current user.
+ */
+ public void testEnableAllNetworks() throws Exception {
+ addNetworks();
+ when(mWifiNative.enableNetwork(anyInt(), anyBoolean())).thenReturn(true);
+ for (int userId : USER_IDS) {
+ switchUser(userId);
+
+ for (WifiConfiguration config : mConfiguredNetworks.valuesForAllUsers()) {
+ final WifiConfiguration.NetworkSelectionStatus status =
+ config.getNetworkSelectionStatus();
+ status.setNetworkSelectionStatus(WifiConfiguration.NetworkSelectionStatus
+ .NETWORK_SELECTION_TEMPORARY_DISABLED);
+ status.setNetworkSelectionDisableReason(
+ WifiConfiguration.NetworkSelectionStatus.DISABLED_AUTHENTICATION_FAILURE);
+ status.setDisableTime(System.currentTimeMillis() - 60 * 60 * 1000);
+ }
+
+ mConfigStore.enableAllNetworks();
+
+ for (WifiConfiguration config : mConfiguredNetworks.valuesForAllUsers()) {
+ assertEquals(config.isVisibleToUser(userId),
+ config.getNetworkSelectionStatus().isNetworkEnabled());
+ }
+ }
+ }
+
+ /**
+ * Verifies that selectNetwork() disables all network configurations visible to the current user
+ * except the selected one.
+ */
+ public void testSelectNetwork() throws Exception {
+ addNetworks();
+
+ for (int userId : USER_IDS) {
+ switchUser(userId);
+
+ for (WifiConfiguration config : mConfiguredNetworks.valuesForAllUsers()) {
+ // Enable all network configurations.
+ for (WifiConfiguration config2 : mConfiguredNetworks.valuesForAllUsers()) {
+ config2.status = WifiConfiguration.Status.ENABLED;
+ }
+
+ // Try to select a network configuration.
+ final WifiNative wifiNative = createNewWifiNativeMock();
+ final boolean success =
+ mConfigStore.selectNetwork(config, false, config.creatorUid);
+ if (!config.isVisibleToUser(userId)) {
+ // If the network configuration is not visible to the current user, verify that
+ // nothing changed.
+ assertFalse(success);
+ verify(wifiNative, never()).selectNetwork(anyInt());
+ verify(wifiNative, never()).enableNetwork(anyInt(), anyBoolean());
+ for (WifiConfiguration config2 : mConfiguredNetworks.valuesForAllUsers()) {
+ assertEquals(WifiConfiguration.Status.ENABLED, config2.status);
+ }
+ } else {
+ // If the network configuration is visible to the current user, verify that it
+ // was enabled and all other network configurations visible to the user were
+ // disabled.
+ assertTrue(success);
+ verify(wifiNative).selectNetwork(config.networkId);
+ verify(wifiNative, never()).selectNetwork(intThat(not(config.networkId)));
+ verify(wifiNative).enableNetwork(config.networkId, true);
+ verify(wifiNative, never()).enableNetwork(config.networkId, false);
+ verify(wifiNative, never()).enableNetwork(intThat(not(config.networkId)),
+ anyBoolean());
+ for (WifiConfiguration config2 : mConfiguredNetworks.valuesForAllUsers()) {
+ if (config2.isVisibleToUser(userId)
+ && config2.networkId != config.networkId) {
+ assertEquals(WifiConfiguration.Status.DISABLED, config2.status);
+ } else {
+ assertEquals(WifiConfiguration.Status.ENABLED, config2.status);
+ }
+ }
+ }
+ }
}
- return config;
}
/**
* Verifies that saveNetwork() correctly stores a network configuration in wpa_supplicant
- * variables.
- * TODO: Test all variables. Currently, only "ssid" and "id_str" are tested.
+ * variables and the networkHistory.txt file.
+ * TODO: Test all variables. Currently, only the following variables are tested:
+ * - In the wpa_supplicant: "ssid", "id_str"
+ * - In networkHistory.txt: "CONFIG", "CREATOR_UID_KEY", "SHARED"
*/
- public void verifySaveNetwork(int network) {
+ private void verifySaveNetwork(int network) throws Exception {
+ // Switch to the correct user.
+ switchUserToCreatorOf(CONFIGS.get(network));
+
// Set up wpa_supplicant.
when(mWifiNative.addNetwork()).thenReturn(0);
- when(mWifiNative.setNetworkVariable(eq(0), anyString(), anyString())).thenReturn(true);
- when(mWifiNative.setNetworkExtra(eq(0), anyString(), (Map<String, String>) anyObject()))
+ when(mWifiNative.setNetworkVariable(eq(network), anyString(), anyString()))
.thenReturn(true);
- when(mWifiNative.getNetworkVariable(0, WifiConfiguration.ssidVarName))
- .thenReturn(ENCODED_SSIDS[network]);
+ when(mWifiNative.setNetworkExtra(eq(network), anyString(),
+ (Map<String, String>) anyObject())).thenReturn(true);
+ when(mWifiNative.getNetworkVariable(network, WifiConfiguration.ssidVarName))
+ .thenReturn(encodeConfigSSID(CONFIGS.get(network)));
// Store a network configuration.
- mConfigStore.saveNetwork(generateWifiConfig(network), UID);
+ mConfigStore.saveNetwork(CONFIGS.get(network), CONFIGS.get(network).creatorUid);
// Verify that wpa_supplicant variables were written correctly for the network
// configuration.
final Map<String, String> metadata = new HashMap<String, String>();
- if (FQDNS[network] != null) {
- metadata.put(WifiConfigStore.ID_STRING_KEY_FQDN, FQDNS[network]);
+ if (CONFIGS.get(network).FQDN != null) {
+ metadata.put(WifiConfigStore.ID_STRING_KEY_FQDN, CONFIGS.get(network).FQDN);
}
- metadata.put(WifiConfigStore.ID_STRING_KEY_CONFIG_KEY, CONFIG_KEYS[network]);
- metadata.put(WifiConfigStore.ID_STRING_KEY_CREATOR_UID, Integer.toString(UID));
- verify(mWifiNative).setNetworkExtra(0, WifiConfigStore.ID_STRING_VAR_NAME,
+ metadata.put(WifiConfigStore.ID_STRING_KEY_CONFIG_KEY, CONFIGS.get(network).configKey());
+ metadata.put(WifiConfigStore.ID_STRING_KEY_CREATOR_UID,
+ Integer.toString(CONFIGS.get(network).creatorUid));
+ verify(mWifiNative).setNetworkExtra(network, WifiConfigStore.ID_STRING_VAR_NAME,
metadata);
// Verify that no wpa_supplicant variables were read or written for any other network
// configurations.
- verify(mWifiNative, never()).setNetworkExtra(intThat(not(0)), anyString(),
+ verify(mWifiNative, never()).setNetworkExtra(intThat(not(network)), anyString(),
(Map<String, String>) anyObject());
- verify(mWifiNative, never()).setNetworkVariable(intThat(not(0)), anyString(), anyString());
- verify(mWifiNative, never()).getNetworkVariable(intThat(not(0)), anyString());
+ verify(mWifiNative, never()).setNetworkVariable(intThat(not(network)), anyString(),
+ anyString());
+ verify(mWifiNative, never()).getNetworkVariable(intThat(not(network)), anyString());
+
+ // Parse networkHistory.txt.
+ assertNotNull(mNetworkHistory);
+ final DataInputStream stream =
+ new DataInputStream(new ByteArrayInputStream(mNetworkHistory));
+ List<String> keys = new ArrayList<>();
+ List<String> values = new ArrayList<>();
+ try {
+ while (true) {
+ final String[] tokens = stream.readUTF().split(":", 2);
+ if (tokens.length == 2) {
+ keys.add(tokens[0].trim());
+ values.add(tokens[1].trim());
+ }
+ }
+ } catch (EOFException e) {
+ // Ignore. This is expected.
+ }
+
+ // Verify that a networkHistory.txt entry was written correctly for the network
+ // configuration.
+ assertTrue(keys.size() >= 3);
+ assertEquals(WifiConfigStore.CONFIG_KEY, keys.get(0));
+ assertEquals(CONFIGS.get(network).configKey(), values.get(0));
+ final int creatorUidIndex = keys.indexOf(WifiConfigStore.CREATOR_UID_KEY);
+ assertTrue(creatorUidIndex != -1);
+ assertEquals(Integer.toString(CONFIGS.get(network).creatorUid),
+ values.get(creatorUidIndex));
+ final int sharedIndex = keys.indexOf(WifiConfigStore.SHARED_KEY);
+ assertTrue(sharedIndex != -1);
+ assertEquals(Boolean.toString(CONFIGS.get(network).shared), values.get(sharedIndex));
+
+ // Verify that no networkHistory.txt entries were written for any other network
+ // configurations.
+ final int lastConfigIndex = keys.lastIndexOf(WifiConfigStore.CONFIG_KEY);
+ assertEquals(0, lastConfigIndex);
}
/**
* Verifies that saveNetwork() correctly stores a regular network configuration.
*/
- public void testSaveNetworkRegular() {
+ public void testSaveNetworkRegular() throws Exception {
verifySaveNetwork(0);
}
/**
* Verifies that saveNetwork() correctly stores a HotSpot 2.0 network configuration.
*/
- public void testSaveNetworkHotspot20() {
+ public void testSaveNetworkHotspot20() throws Exception {
verifySaveNetwork(1);
}
/**
- * Verifies that loadConfiguredNetworks() correctly reads data from the wpa_supplicant and
- * the MOManager, correlating the two sources based on the FQDN for HotSpot 2.0 networks.
- * TODO: Test all variables. Currently, only "ssid" and "id_str" are tested.
+ * Verifies that saveNetwork() correctly stores a private network configuration.
+ */
+ public void testSaveNetworkPrivate() throws Exception {
+ verifySaveNetwork(2);
+ }
+
+ /**
+ * Verifies that loadConfiguredNetworks() correctly reads data from the wpa_supplicant, the
+ * networkHistory.txt file and the MOManager, correlating the three sources based on the
+ * configKey and the FQDN for HotSpot 2.0 networks.
+ * TODO: Test all variables. Currently, only the following variables are tested:
+ * - In the wpa_supplicant: "ssid", "id_str"
+ * - In networkHistory.txt: "CONFIG", "CREATOR_UID_KEY", "SHARED"
*/
public void testLoadConfiguredNetworks() throws Exception {
- // Set up list of networks returned by wpa_supplicant.
+ // Set up list of network configurations returned by wpa_supplicant.
final String header = "network id / ssid / bssid / flags";
String networks = header;
- for (int i = 0; i < SSIDS.length; ++i) {
- networks += "\n" + Integer.toString(i) + "\t" + SSIDS[i] + "\tany";
+ for (WifiConfiguration config : CONFIGS) {
+ networks += "\n" + Integer.toString(config.networkId) + "\t" + config.SSID + "\tany";
}
when(mWifiNative.listNetworks(anyInt())).thenReturn(header);
when(mWifiNative.listNetworks(-1)).thenReturn(networks);
- // Set up variables returned by wpa_supplicant for the individual networks.
- for (int i = 0; i < SSIDS.length; ++i) {
+ // Set up variables returned by wpa_supplicant for the individual network configurations.
+ for (int i = 0; i < CONFIGS.size(); ++i) {
when(mWifiNative.getNetworkVariable(i, WifiConfiguration.ssidVarName))
- .thenReturn(ENCODED_SSIDS[i]);
+ .thenReturn(encodeConfigSSID(CONFIGS.get(i)));
}
// Legacy regular network configuration: No "id_str".
when(mWifiNative.getNetworkExtra(0, WifiConfigStore.ID_STRING_VAR_NAME))
@@ -170,47 +493,140 @@ public class WifiConfigStoreTest extends AndroidTestCase {
when(mWifiNative.getNetworkExtra(1, WifiConfigStore.ID_STRING_VAR_NAME))
.thenReturn(null);
when(mWifiNative.getNetworkVariable(1, WifiConfigStore.ID_STRING_VAR_NAME))
- .thenReturn('"' + FQDNS[1] + '"');
+ .thenReturn('"' + CONFIGS.get(1).FQDN + '"');
// Up-to-date configuration: Metadata in "id_str".
final Map<String, String> metadata = new HashMap<String, String>();
- metadata.put(WifiConfigStore.ID_STRING_KEY_CONFIG_KEY, CONFIG_KEYS[2]);
- metadata.put(WifiConfigStore.ID_STRING_KEY_CREATOR_UID, Integer.toString(UID));
- metadata.put(WifiConfigStore.ID_STRING_KEY_FQDN, FQDNS[2]);
+ metadata.put(WifiConfigStore.ID_STRING_KEY_CONFIG_KEY, CONFIGS.get(2).configKey());
+ metadata.put(WifiConfigStore.ID_STRING_KEY_CREATOR_UID,
+ Integer.toString(CONFIGS.get(2).creatorUid));
+ metadata.put(WifiConfigStore.ID_STRING_KEY_FQDN, CONFIGS.get(2).FQDN);
when(mWifiNative.getNetworkExtra(2, WifiConfigStore.ID_STRING_VAR_NAME))
.thenReturn(metadata);
+ // Set up networkHistory.txt file.
+ final File file = File.createTempFile("networkHistory.txt", null);
+ file.deleteOnExit();
+ Field wifiConfigStoreNetworkHistoryConfigFile =
+ WifiConfigStore.class.getDeclaredField("networkHistoryConfigFile");
+ wifiConfigStoreNetworkHistoryConfigFile.setAccessible(true);
+ wifiConfigStoreNetworkHistoryConfigFile.set(null, file.getAbsolutePath());
+ final DataOutputStream stream = new DataOutputStream(new FileOutputStream(file));
+ for (WifiConfiguration config : CONFIGS) {
+ stream.writeUTF(WifiConfigStore.CONFIG_KEY + ": " + config.configKey() + '\n');
+ stream.writeUTF(WifiConfigStore.CREATOR_UID_KEY + ": "
+ + Integer.toString(config.creatorUid) + '\n');
+ stream.writeUTF(WifiConfigStore.SHARED_KEY + ": "
+ + Boolean.toString(config.shared) + '\n');
+ }
+ stream.close();
+
// Set up list of home service providers returned by MOManager.
final List<HomeSP> homeSPs = new ArrayList<HomeSP>();
- for (int i : new int[] {1, 2}) {
- homeSPs.add(new HomeSP(null, FQDNS[i], new HashSet<Long>(), new HashSet<String>(),
- new HashSet<Long>(), new ArrayList<Long>(), PROVIDER_FRIENDLY_NAMES[i], null,
- new Credential(0, 0, null, false, null, null), null, 0, null, null, null));
+ for (WifiConfiguration config : CONFIGS) {
+ if (config.FQDN != null) {
+ homeSPs.add(new HomeSP(null, config.FQDN, new HashSet<Long>(),
+ new HashSet<String>(), new HashSet<Long>(), new ArrayList<Long>(),
+ config.providerFriendlyName, null, new Credential(0, 0, null, false, null,
+ null), null, 0, null, null, null));
+ }
}
when(mMOManager.loadAllSPs()).thenReturn(homeSPs);
// Load network configurations.
mConfigStore.loadConfiguredNetworks();
- // Verify that network configurations were loaded. For HotSpot 2.0 networks, this also
- // verifies that the data read from the wpa_supplicant was correlated with the data read
- // from the MOManager based on the FQDN stored in the wpa_supplicant's "id_str" variable.
- final List<WifiConfiguration> configs = mConfigStore.getConfiguredNetworks();
- assertEquals(SSIDS.length, configs.size());
- for (int i = 0; i < SSIDS.length; ++i) {
- WifiConfiguration config = null;
- // Find the network configuration to test (getConfiguredNetworks() returns them in
- // undefined order).
- for (final WifiConfiguration candidate : configs) {
- if (candidate.networkId == i) {
- config = candidate;
- break;
+ // Verify that network configurations were loaded and correlated correctly across the three
+ // sources.
+ verifyNetworkConfigs(CONFIGS, mConfiguredNetworks.valuesForAllUsers());
+ }
+
+ /**
+ * Verifies that handleUserSwitch() removes ephemeral network configurations, disables network
+ * configurations that should no longer be visible and enables network configurations that
+ * should become visible.
+ */
+ private void verifyHandleUserSwitch(int oldUserId, int newUserId,
+ boolean makeOneConfigEphemeral) throws Exception {
+ addNetworks();
+ switchUser(oldUserId);
+
+ final WifiNative wifiNative = createNewWifiNativeMock();
+ final Field lastSelectedConfigurationField =
+ WifiConfigStore.class.getDeclaredField("lastSelectedConfiguration");
+ lastSelectedConfigurationField.setAccessible(true);
+ WifiConfiguration removedEphemeralConfig = null;
+ final Set<WifiConfiguration> oldUserOnlyConfigs = new HashSet<>();
+ final Set<WifiConfiguration> newUserOnlyConfigs = new HashSet<>();
+ final Set<WifiConfiguration> neitherUserConfigs = new HashSet<>();
+ final Collection<WifiConfiguration> oldConfigs = mConfiguredNetworks.valuesForAllUsers();
+ int expectedNumberOfConfigs = oldConfigs.size();
+ for (WifiConfiguration config : oldConfigs) {
+ if (config.isVisibleToUser(oldUserId)) {
+ config.status = WifiConfiguration.Status.ENABLED;
+ if (config.isVisibleToUser(newUserId)) {
+ if (makeOneConfigEphemeral && removedEphemeralConfig == null) {
+ config.ephemeral = true;
+ lastSelectedConfigurationField.set(mConfigStore, config.configKey());
+ removedEphemeralConfig = config;
+ }
+ } else {
+ oldUserOnlyConfigs.add(config);
+ }
+ } else {
+ config.status = WifiConfiguration.Status.DISABLED;
+ if (config.isVisibleToUser(newUserId)) {
+ newUserOnlyConfigs.add(config);
+ } else {
+ neitherUserConfigs.add(config);
}
}
- assertNotNull(config);
- assertEquals(SSIDS[i], config.SSID);
- assertEquals(FQDNS[i], config.FQDN);
- assertEquals(PROVIDER_FRIENDLY_NAMES[i], config.providerFriendlyName);
- assertEquals(CONFIG_KEYS[i], config.configKey(false));
}
+ when(wifiNative.disableNetwork(anyInt())).thenReturn(true);
+
+ switchUser(newUserId);
+ if (makeOneConfigEphemeral) {
+ // Verify that the ephemeral network configuration was removed.
+ assertNotNull(removedEphemeralConfig);
+ assertNull(mConfiguredNetworks.getForAllUsers(removedEphemeralConfig.networkId));
+ assertNull(lastSelectedConfigurationField.get(mConfigStore));
+ verify(wifiNative).removeNetwork(removedEphemeralConfig.networkId);
+ --expectedNumberOfConfigs;
+ } else {
+ assertNull(removedEphemeralConfig);
+ }
+
+ // Verify that the other network configurations were revealed/hidden and enabled/disabled as
+ // appropriate.
+ final Collection<WifiConfiguration> newConfigs = mConfiguredNetworks.valuesForAllUsers();
+ assertEquals(expectedNumberOfConfigs, newConfigs.size());
+ for (WifiConfiguration config : newConfigs) {
+ if (oldUserOnlyConfigs.contains(config)) {
+ verify(wifiNative).disableNetwork(config.networkId);
+ assertEquals(WifiConfiguration.Status.DISABLED, config.status);
+ } else {
+ verify(wifiNative, never()).disableNetwork(config.networkId);
+ if (neitherUserConfigs.contains(config)) {
+ assertEquals(WifiConfiguration.Status.DISABLED, config.status);
+ } else {
+ assertEquals(WifiConfiguration.Status.ENABLED, config.status);
+ }
+ }
+ }
+ }
+
+ /**
+ * Verifies that handleUserSwitch() behaves correctly when the user switch removes an ephemeral
+ * network configuration and reveals a private network configuration.
+ */
+ public void testHandleUserSwitchWithEphemeral() throws Exception {
+ verifyHandleUserSwitch(USER_IDS[2], USER_IDS[0], true);
+ }
+
+ /**
+ * Verifies that handleUserSwitch() behaves correctly when the user switch hides a private
+ * network configuration.
+ */
+ public void testHandleUserSwitchWithoutEphemeral() throws Exception {
+ verifyHandleUserSwitch(USER_IDS[0], USER_IDS[2], false);
}
}
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiConfigurationUtil.java b/tests/wifitests/src/com/android/server/wifi/WifiConfigurationUtil.java
new file mode 100644
index 000000000..c786741cf
--- /dev/null
+++ b/tests/wifitests/src/com/android/server/wifi/WifiConfigurationUtil.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.wifi;
+
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiEnterpriseConfig;
+
+/**
+ * Helper for creating and populating WifiConfigurations in unit tests.
+ */
+public class WifiConfigurationUtil {
+ public static WifiConfiguration generateWifiConfig(int networkId, int uid, String ssid,
+ boolean shared, boolean enabled, String fqdn, String providerFriendlyName) {
+ final WifiConfiguration config = new WifiConfiguration();
+ config.SSID = ssid;
+ config.networkId = networkId;
+ config.creatorUid = uid;
+ config.shared = shared;
+ config.status = enabled ? WifiConfiguration.Status.ENABLED
+ : WifiConfiguration.Status.DISABLED;
+ if (fqdn != null) {
+ config.FQDN = fqdn;
+ config.providerFriendlyName = providerFriendlyName;
+ config.enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.SIM);
+ }
+ return config;
+ }
+}