diff options
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>() { |