summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--service/java/com/android/server/wifi/ConfigurationMap.java40
-rw-r--r--service/java/com/android/server/wifi/WifiConfigStore.java83
-rw-r--r--service/java/com/android/server/wifi/WifiNative.java72
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiConfigStoreTest.java216
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiNativeTest.java84
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java20
6 files changed, 456 insertions, 59 deletions
diff --git a/service/java/com/android/server/wifi/ConfigurationMap.java b/service/java/com/android/server/wifi/ConfigurationMap.java
index 0fb56eaba..837c5799c 100644
--- a/service/java/com/android/server/wifi/ConfigurationMap.java
+++ b/service/java/com/android/server/wifi/ConfigurationMap.java
@@ -1,15 +1,10 @@
package com.android.server.wifi;
import android.net.wifi.WifiConfiguration;
-import android.util.Log;
-
-import com.android.server.wifi.hotspot2.Utils;
-import com.android.server.wifi.hotspot2.pps.HomeSP;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -29,41 +24,6 @@ public class ConfigurationMap {
return current;
}
- public void populatePasspointData(Collection<HomeSP> homeSPs, WifiNative wifiNative) {
- mPerFQDN.clear();
-
- for (HomeSP homeSp : homeSPs) {
- String fqdn = homeSp.getFQDN();
- Log.d(WifiConfigStore.TAG, "Looking for " + fqdn);
- for (WifiConfiguration config : mPerID.values()) {
- Log.d(WifiConfigStore.TAG, "Testing " + config.SSID);
-
- String id_str = Utils.unquote(wifiNative.getNetworkVariable(
- config.networkId, WifiConfigStore.idStringVarName));
- if (id_str != null && id_str.equals(fqdn) && config.enterpriseConfig != null) {
- Log.d(WifiConfigStore.TAG, "Matched " + id_str + " with " + config.networkId);
- config.FQDN = fqdn;
- config.providerFriendlyName = homeSp.getFriendlyName();
-
- HashSet<Long> roamingConsortiumIds = homeSp.getRoamingConsortiums();
- config.roamingConsortiumIds = new long[roamingConsortiumIds.size()];
- int i = 0;
- for (long id : roamingConsortiumIds) {
- config.roamingConsortiumIds[i] = id;
- i++;
- }
- IMSIParameter imsiParameter = homeSp.getCredential().getImsi();
- config.enterpriseConfig.setPlmn(
- imsiParameter != null ? imsiParameter.toString() : null);
- config.enterpriseConfig.setRealm(homeSp.getCredential().getRealm());
- mPerFQDN.put(fqdn, config.networkId);
- }
- }
- }
-
- Log.d(WifiConfigStore.TAG, "loaded " + mPerFQDN.size() + " passpoint configs");
- }
-
public WifiConfiguration remove(int netID) {
WifiConfiguration config = mPerID.remove(netID);
if (config == null) {
diff --git a/service/java/com/android/server/wifi/WifiConfigStore.java b/service/java/com/android/server/wifi/WifiConfigStore.java
index b2f531303..35f146e1a 100644
--- a/service/java/com/android/server/wifi/WifiConfigStore.java
+++ b/service/java/com/android/server/wifi/WifiConfigStore.java
@@ -324,7 +324,14 @@ public class WifiConfigStore extends IpConfigStore {
private static final String ENABLE_RSSI_POLL_WHILE_ASSOCIATED_KEY
= "ENABLE_RSSI_POLL_WHILE_ASSOCIATED_KEY";
- public static final String idStringVarName = "id_str";
+ // This is the only variable whose contents will not be interpreted by wpa_supplicant. We use it
+ // to store metadata that allows us to correlate a wpa_supplicant.conf entry with additional
+ // information about the same network stored in other files. The metadata is stored as a
+ // serialized JSON dictionary.
+ public static final String ID_STRING_VAR_NAME = "id_str";
+ public static final String ID_STRING_KEY_FQDN = "fqdn";
+ public static final String ID_STRING_KEY_CREATOR_UID = "creatorUid";
+ public static final String ID_STRING_KEY_CONFIG_KEY = "configKey";
// The Wifi verbose log is provided as a way to persist the verbose logging settings
// for testing purpose.
@@ -1930,6 +1937,8 @@ public class WifiConfigStore extends IpConfigStore {
mConfiguredNetworks.clear();
+ final SparseArray<Map<String, String>> networkExtras = new SparseArray<>();
+
int last_id = -1;
boolean done = false;
while (!done) {
@@ -1972,6 +1981,22 @@ public class WifiConfigStore extends IpConfigStore {
readNetworkVariables(config);
+ // Parse the serialized JSON dictionary in ID_STRING_VAR_NAME once and cache the
+ // result for efficiency.
+ Map<String, String> extras = mWifiNative.getNetworkExtra(config.networkId,
+ ID_STRING_VAR_NAME);
+ if (extras == null) {
+ extras = new HashMap<String, String>();
+ // If ID_STRING_VAR_NAME did not contain a dictionary, assume that it contains
+ // just a quoted FQDN. This is the legacy format that was used in Marshmallow.
+ final String fqdn = Utils.unquote(mWifiNative.getNetworkVariable(
+ config.networkId, ID_STRING_VAR_NAME));
+ if (fqdn != null) {
+ extras.put(ID_STRING_KEY_FQDN, fqdn);
+ }
+ }
+ networkExtras.put(config.networkId, extras);
+
Checksum csum = new CRC32();
if (config.SSID != null) {
csum.update(config.SSID.getBytes(), 0, config.SSID.getBytes().length);
@@ -2019,7 +2044,7 @@ public class WifiConfigStore extends IpConfigStore {
done = (lines.length == 1);
}
- readPasspointConfig();
+ readPasspointConfig(networkExtras);
readIpAndProxyConfigurations();
readNetworkHistory();
readAutoJoinConfig();
@@ -2167,7 +2192,7 @@ public class WifiConfigStore extends IpConfigStore {
return false;
}
- void readPasspointConfig() {
+ void readPasspointConfig(SparseArray<Map<String, String>> networkExtras) {
List<HomeSP> homeSPs;
try {
@@ -2177,7 +2202,42 @@ public class WifiConfigStore extends IpConfigStore {
return;
}
- mConfiguredNetworks.populatePasspointData(homeSPs, mWifiNative);
+ int matchedConfigs = 0;
+ for (HomeSP homeSp : homeSPs) {
+ String fqdn = homeSp.getFQDN();
+ Log.d(TAG, "Looking for " + fqdn);
+ for (WifiConfiguration config : mConfiguredNetworks.values()) {
+ Log.d(TAG, "Testing " + config.SSID);
+
+ if (config.enterpriseConfig == null) {
+ continue;
+ }
+ final String configFqdn =
+ networkExtras.get(config.networkId).get(ID_STRING_KEY_FQDN);
+ if (configFqdn != null && configFqdn.equals(fqdn)) {
+ Log.d(TAG, "Matched " + configFqdn + " with " + config.networkId);
+ ++matchedConfigs;
+ config.FQDN = fqdn;
+ config.providerFriendlyName = homeSp.getFriendlyName();
+
+ HashSet<Long> roamingConsortiumIds = homeSp.getRoamingConsortiums();
+ config.roamingConsortiumIds = new long[roamingConsortiumIds.size()];
+ int i = 0;
+ for (long id : roamingConsortiumIds) {
+ config.roamingConsortiumIds[i] = id;
+ i++;
+ }
+ IMSIParameter imsiParameter = homeSp.getCredential().getImsi();
+ 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);
+ }
+ }
+ }
+
+ Log.d(TAG, "loaded " + matchedConfigs + " passpoint configs");
}
public void writePasspointConfigs(final String fqdn, final HomeSP homeSP) {
@@ -2804,14 +2864,15 @@ public class WifiConfigStore extends IpConfigStore {
break setVariables;
}
+ final Map<String, String> metadata = new HashMap<String, String>();
if (config.isPasspoint()) {
- if (!mWifiNative.setNetworkVariable(
- netId,
- idStringVarName,
- '"' + config.FQDN + '"')) {
- loge("failed to set id_str: " + config.FQDN);
- break setVariables;
- }
+ metadata.put(ID_STRING_KEY_FQDN, config.FQDN);
+ }
+ metadata.put(ID_STRING_KEY_CONFIG_KEY, config.configKey());
+ metadata.put(ID_STRING_KEY_CREATOR_UID, Integer.toString(config.creatorUid));
+ if (!mWifiNative.setNetworkExtra(netId, ID_STRING_VAR_NAME, metadata)) {
+ loge("failed to set id_str: " + metadata.toString());
+ break setVariables;
}
if (config.BSSID != null) {
diff --git a/service/java/com/android/server/wifi/WifiNative.java b/service/java/com/android/server/wifi/WifiNative.java
index a1d9379e7..7fe0bf79d 100644
--- a/service/java/com/android/server/wifi/WifiNative.java
+++ b/service/java/com/android/server/wifi/WifiNative.java
@@ -16,15 +16,21 @@
package com.android.server.wifi;
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.net.wifi.RttManager;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiEnterpriseConfig;
import android.net.wifi.WifiLinkLayerStats;
-import android.net.wifi.WifiWakeReasonAndCounts;
import android.net.wifi.WifiManager;
import android.net.wifi.WifiScanner;
import android.net.wifi.WifiSsid;
+import android.net.wifi.WifiWakeReasonAndCounts;
import android.net.wifi.WpsInfo;
import android.net.wifi.p2p.WifiP2pConfig;
import android.net.wifi.p2p.WifiP2pGroup;
@@ -34,12 +40,7 @@ import android.os.SystemProperties;
import android.text.TextUtils;
import android.util.LocalLog;
import android.util.Log;
-import android.content.Context;
-import android.content.Intent;
-import android.app.AlarmManager;
-import android.app.PendingIntent;
-import android.content.IntentFilter;
-import android.content.BroadcastReceiver;
+
import com.android.server.connectivity.KeepalivePacketData;
import com.android.server.wifi.hotspot2.NetworkDetail;
import com.android.server.wifi.hotspot2.SupplicantBridge;
@@ -48,16 +49,26 @@ import com.android.server.wifi.util.InformationElementUtil;
import libcore.util.HexEncoding;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.net.URLEncoder;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
import java.util.List;
import java.util.Locale;
+import java.util.Map;
import java.util.Set;
+
/**
* Native calls for bring up/shut down of the supplicant daemon and for
* sending requests to the supplicant daemon
@@ -370,6 +381,20 @@ public class WifiNative {
return doIntCommand("ADD_NETWORK");
}
+ public boolean setNetworkExtra(int netId, String name, Map<String, String> values) {
+ final String encoded;
+ try {
+ encoded = URLEncoder.encode(new JSONObject(values).toString(), "UTF-8");
+ } catch (NullPointerException e) {
+ Log.e(TAG, "Unable to serialize networkExtra: " + e.toString());
+ return false;
+ } catch (UnsupportedEncodingException e) {
+ Log.e(TAG, "Unable to serialize networkExtra: " + e.toString());
+ return false;
+ }
+ return setNetworkVariable(netId, name, "\"" + encoded + "\"");
+ }
+
public boolean setNetworkVariable(int netId, String name, String value) {
if (TextUtils.isEmpty(name) || TextUtils.isEmpty(value)) return false;
if (name.equals(WifiConfiguration.pskVarName)
@@ -380,6 +405,39 @@ public class WifiNative {
}
}
+ public Map<String, String> getNetworkExtra(int netId, String name) {
+ final String wrapped = getNetworkVariable(netId, name);
+ if (wrapped == null || !wrapped.startsWith("\"") || !wrapped.endsWith("\"")) {
+ return null;
+ }
+ try {
+ final String encoded = wrapped.substring(1, wrapped.length() - 1);
+ // This method reads a JSON dictionary that was written by setNetworkExtra(). However,
+ // on devices that upgraded from Marshmallow, it may encounter a legacy value instead -
+ // an FQDN stored as a plain string. If such a value is encountered, the JSONObject
+ // constructor will thrown a JSONException and the method will return null.
+ final JSONObject json = new JSONObject(URLDecoder.decode(encoded, "UTF-8"));
+ final Map<String, String> values = new HashMap<String, String>();
+ final Iterator<?> it = json.keys();
+ while (it.hasNext()) {
+ final String key = (String) it.next();
+ final Object value = json.get(key);
+ if (value instanceof String) {
+ values.put(key, (String) value);
+ }
+ }
+ return values;
+ } catch (UnsupportedEncodingException e) {
+ Log.e(TAG, "Unable to serialize networkExtra: " + e.toString());
+ return null;
+ } catch (JSONException e) {
+ // This is not necessarily an error. This exception will also occur if we encounter a
+ // legacy FQDN stored as a plain string. We want to return null in this case as no JSON
+ // dictionary of extras was found.
+ return null;
+ }
+ }
+
public String getNetworkVariable(int netId, String name) {
if (TextUtils.isEmpty(name)) return null;
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiConfigStoreTest.java b/tests/wifitests/src/com/android/server/wifi/WifiConfigStoreTest.java
new file mode 100644
index 000000000..0a9af5e0b
--- /dev/null
+++ b/tests/wifitests/src/com/android/server/wifi/WifiConfigStoreTest.java
@@ -0,0 +1,216 @@
+/*
+ * 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.hamcrest.CoreMatchers.not;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.anyObject;
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.intThat;
+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.test.AndroidTestCase;
+
+import com.android.server.wifi.hotspot2.omadm.MOManager;
+import com.android.server.wifi.hotspot2.pps.Credential;
+import com.android.server.wifi.hotspot2.pps.HomeSP;
+
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 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"};
+
+ @Mock private Context mContext;
+ @Mock private WifiStateMachine mWifiStateMachine;
+ @Mock private WifiNative mWifiNative;
+ @Mock private FrameworkFacade mFrameworkFacade;
+ @Mock private MOManager mMOManager;
+ private WifiConfigStore mConfigStore;
+
+ @Override
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+
+ final Context realContext = getContext();
+ when(mContext.getPackageName()).thenReturn(realContext.getPackageName());
+ when(mContext.getResources()).thenReturn(realContext.getResources());
+
+ mConfigStore = new WifiConfigStore(mContext, mWifiStateMachine, mWifiNative,
+ mFrameworkFacade);
+
+ 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);
+ }
+ 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.
+ */
+ public void verifySaveNetwork(int 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()))
+ .thenReturn(true);
+ when(mWifiNative.getNetworkVariable(0, WifiConfiguration.ssidVarName))
+ .thenReturn(ENCODED_SSIDS[network]);
+
+ // Store a network configuration.
+ mConfigStore.saveNetwork(generateWifiConfig(network), UID);
+
+ // 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]);
+ }
+ 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);
+
+ // Verify that no wpa_supplicant variables were read or written for any other network
+ // configurations.
+ verify(mWifiNative, never()).setNetworkExtra(intThat(not(0)), anyString(),
+ (Map<String, String>) anyObject());
+ verify(mWifiNative, never()).setNetworkVariable(intThat(not(0)), anyString(), anyString());
+ verify(mWifiNative, never()).getNetworkVariable(intThat(not(0)), anyString());
+ }
+
+ /**
+ * Verifies that saveNetwork() correctly stores a regular network configuration.
+ */
+ public void testSaveNetworkRegular() {
+ verifySaveNetwork(0);
+ }
+
+ /**
+ * Verifies that saveNetwork() correctly stores a HotSpot 2.0 network configuration.
+ */
+ public void testSaveNetworkHotspot20() {
+ 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.
+ */
+ public void testLoadConfiguredNetworks() throws Exception {
+ // Set up list of networks 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";
+ }
+ 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) {
+ when(mWifiNative.getNetworkVariable(i, WifiConfiguration.ssidVarName))
+ .thenReturn(ENCODED_SSIDS[i]);
+ }
+ // Legacy regular network configuration: No "id_str".
+ when(mWifiNative.getNetworkExtra(0, WifiConfigStore.ID_STRING_VAR_NAME))
+ .thenReturn(null);
+ // Legacy Hotspot 2.0 network configuration: Quoted FQDN in "id_str".
+ when(mWifiNative.getNetworkExtra(1, WifiConfigStore.ID_STRING_VAR_NAME))
+ .thenReturn(null);
+ when(mWifiNative.getNetworkVariable(1, WifiConfigStore.ID_STRING_VAR_NAME))
+ .thenReturn('"' + FQDNS[1] + '"');
+ // 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]);
+ when(mWifiNative.getNetworkExtra(2, WifiConfigStore.ID_STRING_VAR_NAME))
+ .thenReturn(metadata);
+
+ // 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));
+ }
+ 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;
+ }
+ }
+ 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));
+ }
+ }
+}
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiNativeTest.java b/tests/wifitests/src/com/android/server/wifi/WifiNativeTest.java
new file mode 100644
index 000000000..73e2effe5
--- /dev/null
+++ b/tests/wifitests/src/com/android/server/wifi/WifiNativeTest.java
@@ -0,0 +1,84 @@
+/*
+ * 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.assertTrue;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.lang.reflect.Constructor;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Unit tests for {@link com.android.server.wifi.WifiNative}.
+ */
+@SmallTest
+public class WifiNativeTest {
+ private static final int NETWORK_ID = 0;
+ private static final String NETWORK_EXTRAS_VARIABLE = "test";
+ private static final Map<String, String> NETWORK_EXTRAS_VALUES = new HashMap<>();
+ static {
+ NETWORK_EXTRAS_VALUES.put("key1", "value1");
+ NETWORK_EXTRAS_VALUES.put("key2", "value2");
+ }
+ private static final String NETWORK_EXTRAS_SERIALIZED =
+ "\"%7B%22key2%22%3A%22value2%22%2C%22key1%22%3A%22value1%22%7D\"";
+
+ private WifiNative mWifiNative;
+
+ @Before
+ public void setUp() throws Exception {
+ final Constructor<WifiNative> wifiNativeConstructor =
+ WifiNative.class.getDeclaredConstructor(String.class);
+ wifiNativeConstructor.setAccessible(true);
+ mWifiNative = spy(wifiNativeConstructor.newInstance("test"));
+ }
+
+ /**
+ * Verifies that setNetworkExtra() correctly writes a serialized and URL-encoded JSON object.
+ */
+ @Test
+ public void testSetNetworkExtra() {
+ when(mWifiNative.setNetworkVariable(anyInt(), anyString(), anyString())).thenReturn(true);
+ assertTrue(mWifiNative.setNetworkExtra(NETWORK_ID, NETWORK_EXTRAS_VARIABLE,
+ NETWORK_EXTRAS_VALUES));
+ verify(mWifiNative).setNetworkVariable(NETWORK_ID, NETWORK_EXTRAS_VARIABLE,
+ NETWORK_EXTRAS_SERIALIZED);
+ }
+
+ /**
+ * Verifies that getNetworkExtra() correctly reads a serialized and URL-encoded JSON object.
+ */
+ @Test
+ public void testGetNetworkExtra() {
+ when(mWifiNative.getNetworkVariable(NETWORK_ID, NETWORK_EXTRAS_VARIABLE))
+ .thenReturn(NETWORK_EXTRAS_SERIALIZED);
+ final Map<String, String> actualValues =
+ mWifiNative.getNetworkExtra(NETWORK_ID, NETWORK_EXTRAS_VARIABLE);
+ assertEquals(NETWORK_EXTRAS_VALUES, actualValues);
+ }
+}
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java b/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java
index 383771047..a34da8721 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java
@@ -21,6 +21,7 @@ import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.any;
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.mock;
import static org.mockito.Mockito.verify;
@@ -69,7 +70,6 @@ import com.android.server.wifi.hotspot2.osu.OSUManager;
import com.android.server.wifi.p2p.WifiP2pServiceImpl;
import org.junit.After;
-import org.junit.AfterClass;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
@@ -86,6 +86,7 @@ import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
+import java.util.Map;
/**
* Example Unit Test File
@@ -456,6 +457,23 @@ public class WifiStateMachineTest {
return true;
}
});
+ when(mWifiNative.setNetworkExtra(anyInt(), anyString(), (Map<String, String>) anyObject()))
+ .then(new Answer<Boolean>() {
+ @Override
+ public Boolean answer(InvocationOnMock invocationOnMock)
+ throws Throwable {
+ Object args[] = invocationOnMock.getArguments();
+ Integer netId = (Integer) args[0];
+ String name = (String) args[1];
+ if (netId != 0) {
+ Log.d(TAG, "Can't set extra " + name + " for " + netId);
+ return false;
+ }
+
+ Log.d(TAG, "Setting extra for " + netId);
+ return true;
+ }
+ });
when(mWifiNative.getNetworkVariable(anyInt(), anyString())).then(
new Answer<String>() {