diff options
author | Peter Qiu <zqiu@google.com> | 2017-07-20 14:49:13 -0700 |
---|---|---|
committer | Peter Qiu <zqiu@google.com> | 2017-07-26 15:43:25 -0700 |
commit | 74390d669cf29f102a7a3804cfffc5934a39d4bc (patch) | |
tree | 7144cbd266788d39a01c6fcad00199c516b74195 | |
parent | 0f2d9e8da0a64cb397aaac94cf1f66b077761ea6 (diff) |
Add support for maintaining carrier Wi-Fi network configurtion
The carrier Wi-Fi network configurations are based on the current
active subscriptions.
Bug: 30988281
Test: frameworks/opt/net/wifi/tests/wifitests/runtests.sh
Test: manual
Change-Id: I35f8f26510184240f4cbe6ee55e089145705ab86
-rw-r--r-- | service/java/com/android/server/wifi/CarrierNetworkConfig.java | 198 | ||||
-rw-r--r-- | tests/wifitests/src/com/android/server/wifi/CarrierNetworkConfigTest.java | 172 |
2 files changed, 370 insertions, 0 deletions
diff --git a/service/java/com/android/server/wifi/CarrierNetworkConfig.java b/service/java/com/android/server/wifi/CarrierNetworkConfig.java new file mode 100644 index 000000000..c23213e8a --- /dev/null +++ b/service/java/com/android/server/wifi/CarrierNetworkConfig.java @@ -0,0 +1,198 @@ +/* + * Copyright (C) 2017 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.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.net.wifi.EAPConstants; +import android.net.wifi.WifiEnterpriseConfig; +import android.os.PersistableBundle; +import android.telephony.CarrierConfigManager; +import android.telephony.SubscriptionInfo; +import android.telephony.SubscriptionManager; +import android.util.Base64; +import android.util.Log; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Class for maintaining/caching carrier Wi-Fi network configurations. + */ +public class CarrierNetworkConfig { + private static final String TAG = "CarrierNetworkConfig"; + + private static final String NETWORK_CONFIG_SEPARATOR = ","; + private static final int ENCODED_SSID_INDEX = 0; + private static final int EAP_TYPE_INDEX = 1; + private static final int CONFIG_ELEMENT_SIZE = 2; + + private final Map<String, NetworkInfo> mCarrierNetworkMap; + + public CarrierNetworkConfig(Context context) { + mCarrierNetworkMap = new HashMap<>(); + updateNetworkConfig(context); + + // Monitor for carrier config changes. + IntentFilter filter = new IntentFilter(); + filter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); + context.registerReceiver(new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + updateNetworkConfig(context); + } + }, filter); + } + + /** + * @return true if the given SSID is associated with a carrier network + */ + public boolean isCarrierNetwork(String ssid) { + return mCarrierNetworkMap.containsKey(ssid); + } + + /** + * @return the EAP type associated with a carrier AP, or -1 if the specified AP + * is not associated with a carrier network + */ + public int getNetworkEapType(String ssid) { + NetworkInfo info = mCarrierNetworkMap.get(ssid); + return info == null ? -1 : info.mEapType; + } + + /** + * @return the name of carrier associated with a carrier AP, or null if the specified AP + * is not associated with a carrier network. + */ + public String getCarrierName(String ssid) { + NetworkInfo info = mCarrierNetworkMap.get(ssid); + return info == null ? null : info.mCarrierName; + } + + /** + * Utility class for storing carrier network information. + */ + private static class NetworkInfo { + final int mEapType; + final String mCarrierName; + + NetworkInfo(int eapType, String carrierName) { + mEapType = eapType; + mCarrierName = carrierName; + } + } + + /** + * Update the carrier network map based on the current carrier configuration of the active + * subscriptions. + * + * @param context Current application context + */ + private void updateNetworkConfig(Context context) { + // Reset network map. + mCarrierNetworkMap.clear(); + + CarrierConfigManager carrierConfigManager = + (CarrierConfigManager) context.getSystemService(Context.CARRIER_CONFIG_SERVICE); + if (carrierConfigManager == null) { + return; + } + + SubscriptionManager subscriptionManager = (SubscriptionManager) context.getSystemService( + Context.TELEPHONY_SUBSCRIPTION_SERVICE); + if (subscriptionManager == null) { + return; + } + List<SubscriptionInfo> subInfoList = subscriptionManager.getActiveSubscriptionInfoList(); + if (subInfoList == null) { + return; + } + + // Process the carrier config for each active subscription. + for (SubscriptionInfo subInfo : subInfoList) { + processNetworkConfig( + carrierConfigManager.getConfigForSubId(subInfo.getSubscriptionId()), + subInfo.getDisplayName().toString()); + } + } + + /** + * Process the carrier network config, the network config string is formatted as follow: + * + * "[Base64 Encoded SSID],[EAP Type]" + * Where EAP Type is the standard EAP method number, refer to + * http://www.iana.org/assignments/eap-numbers/eap-numbers.xhtml for more info. + + * @param carrierConfig The bundle containing the carrier configuration + * @param carrierName The display name of the associated carrier + */ + private void processNetworkConfig(PersistableBundle carrierConfig, String carrierName) { + if (carrierConfig == null) { + return; + } + String[] networkConfigs = carrierConfig.getStringArray( + CarrierConfigManager.KEY_CARRIER_WIFI_STRING_ARRAY); + if (networkConfigs == null) { + return; + } + + for (String networkConfig : networkConfigs) { + String[] configArr = networkConfig.split(NETWORK_CONFIG_SEPARATOR); + if (configArr.length != CONFIG_ELEMENT_SIZE) { + Log.e(TAG, "Ignore invalid config: " + networkConfig); + continue; + } + try { + String ssid = new String(Base64.decode( + configArr[ENCODED_SSID_INDEX], Base64.DEFAULT)); + int eapType = parseEapType(Integer.parseInt(configArr[EAP_TYPE_INDEX])); + // Verify EAP type, must be a SIM based EAP type. + if (eapType == -1) { + Log.e(TAG, "Invalid EAP type: " + configArr[EAP_TYPE_INDEX]); + continue; + } + mCarrierNetworkMap.put(ssid, new NetworkInfo(eapType, carrierName)); + } catch (NumberFormatException e) { + Log.e(TAG, "Failed to parse EAP type: " + e.getMessage()); + } catch (IllegalArgumentException e) { + Log.e(TAG, "Failed to decode SSID: " + e.getMessage()); + } + } + } + + /** + * Convert a standard SIM-based EAP type (SIM, AKA, AKA') to the internal EAP type as defined in + * {@link WifiEnterpriseConfig.Eap}. -1 will be returned if the given EAP type is not + * SIM-based. + * + * @return SIM-based EAP type as defined in {@link WifiEnterpriseConfig.Eap}, or -1 if not + * SIM-based EAP type + */ + private static int parseEapType(int eapType) { + if (eapType == EAPConstants.EAP_SIM) { + return WifiEnterpriseConfig.Eap.SIM; + } else if (eapType == EAPConstants.EAP_AKA) { + return WifiEnterpriseConfig.Eap.AKA; + } else if (eapType == EAPConstants.EAP_AKA_PRIME) { + return WifiEnterpriseConfig.Eap.AKA_PRIME; + } + return -1; + } +} diff --git a/tests/wifitests/src/com/android/server/wifi/CarrierNetworkConfigTest.java b/tests/wifitests/src/com/android/server/wifi/CarrierNetworkConfigTest.java new file mode 100644 index 000000000..f8d2e5202 --- /dev/null +++ b/tests/wifitests/src/com/android/server/wifi/CarrierNetworkConfigTest.java @@ -0,0 +1,172 @@ +/* + * Copyright (C) 2017 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.*; +import static org.mockito.Mockito.*; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.net.wifi.EAPConstants; +import android.net.wifi.WifiEnterpriseConfig; +import android.os.PersistableBundle; +import android.telephony.CarrierConfigManager; +import android.telephony.SubscriptionInfo; +import android.telephony.SubscriptionManager; +import android.test.suitebuilder.annotation.SmallTest; +import android.util.Base64; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.Arrays; + +/** + * Unit tests for {@link com.android.server.wifi.CarrierNetworkConfig}. + */ +@SmallTest +public class CarrierNetworkConfigTest { + private static final String TEST_SSID = "Test SSID"; + private static final int TEST_STANDARD_EAP_TYPE = EAPConstants.EAP_SIM; + private static final int TEST_INTERNAL_EAP_TYPE = WifiEnterpriseConfig.Eap.SIM; + private static final int TEST_SUBSCRIPTION_ID = 1; + private static final String TEST_CARRIER_NAME = "Test Carrier"; + private static final SubscriptionInfo TEST_SUBSCRIPTION_INFO = + new SubscriptionInfo(TEST_SUBSCRIPTION_ID, null, 0, TEST_CARRIER_NAME, null, 0, 0, + null, 0, null, 0, 0, null); + + @Mock Context mContext; + @Mock CarrierConfigManager mCarrierConfigManager; + @Mock SubscriptionManager mSubscriptionManager; + BroadcastReceiver mBroadcastReceiver; + CarrierNetworkConfig mCarrierNetworkConfig; + + /** + * Generate and return a carrier config for testing + * + * @param ssid The SSID of the carrier network + * @param eapType The EAP type of the carrier network + * @return {@link PersistableBundle} containing carrier config + */ + private PersistableBundle generateTestConfig(String ssid, int eapType) { + PersistableBundle bundle = new PersistableBundle(); + String networkConfig = + new String(Base64.encode(ssid.getBytes(), Base64.DEFAULT)) + "," + eapType; + bundle.putStringArray(CarrierConfigManager.KEY_CARRIER_WIFI_STRING_ARRAY, + new String[] {networkConfig}); + return bundle; + } + + /** + * Method to initialize mocks for tests. + */ + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + when(mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE)) + .thenReturn(mCarrierConfigManager); + when(mContext.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE)) + .thenReturn(mSubscriptionManager); + when(mCarrierConfigManager.getConfigForSubId(TEST_SUBSCRIPTION_ID)) + .thenReturn(generateTestConfig(TEST_SSID, TEST_STANDARD_EAP_TYPE)); + when(mSubscriptionManager.getActiveSubscriptionInfoList()) + .thenReturn(Arrays.asList(new SubscriptionInfo[] {TEST_SUBSCRIPTION_INFO})); + mCarrierNetworkConfig = new CarrierNetworkConfig(mContext); + ArgumentCaptor<BroadcastReceiver> receiver = + ArgumentCaptor.forClass(BroadcastReceiver.class); + verify(mContext).registerReceiver(receiver.capture(), any(IntentFilter.class)); + mBroadcastReceiver = receiver.getValue(); + reset(mCarrierConfigManager); + } + + /** + * Verify that {@link CarrierNetworkConfig#isCarrierNetwork} will return true and + * {@link CarrierNetworkConfig#getNetworkEapType} will return the corresponding EAP type + * when the given SSID is associated with a carrier network. + * + * @throws Exception + */ + @Test + public void getExistingCarrierNetworkInfo() throws Exception { + assertTrue(mCarrierNetworkConfig.isCarrierNetwork(TEST_SSID)); + assertEquals(TEST_INTERNAL_EAP_TYPE, mCarrierNetworkConfig.getNetworkEapType(TEST_SSID)); + assertEquals(TEST_CARRIER_NAME, mCarrierNetworkConfig.getCarrierName(TEST_SSID)); + } + + /** + * Verify that {@link CarrierNetworkConfig#isCarrierNetwork} will return false and + * {@link CarrierNetworkConfig#getNetworkEapType} will return -1 when the given SSID is not + * associated with any carrier network. + * + * @throws Exception + */ + @Test + public void getNonCarrierNetworkInfo() throws Exception { + String dummySsid = "Dummy SSID"; + assertFalse(mCarrierNetworkConfig.isCarrierNetwork(dummySsid)); + assertEquals(-1, mCarrierNetworkConfig.getNetworkEapType(dummySsid)); + } + + /** + * Verify that the carrier network config is updated when + * {@link CarrierConfigManager#ACTION_CARRIER_CONFIG_CHANGED} intent is received. + * + * @throws Exception + */ + @Test + public void receivedCarrierConfigChangedIntent() throws Exception { + String updatedSsid = "Updated SSID"; + int updatedStandardEapType = EAPConstants.EAP_AKA; + int updatedInternalEapType = WifiEnterpriseConfig.Eap.AKA; + String updatedCarrierName = "Updated Carrier"; + SubscriptionInfo updatedSubscriptionInfo = new SubscriptionInfo(TEST_SUBSCRIPTION_ID, + null, 0, updatedCarrierName, null, 0, 0, null, 0, null, 0, 0, null); + when(mSubscriptionManager.getActiveSubscriptionInfoList()) + .thenReturn(Arrays.asList(new SubscriptionInfo[] {updatedSubscriptionInfo})); + when(mCarrierConfigManager.getConfigForSubId(TEST_SUBSCRIPTION_ID)) + .thenReturn(generateTestConfig(updatedSsid, updatedStandardEapType)); + mBroadcastReceiver.onReceive(mContext, + new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)); + + // Verify that original SSID no longer associated with a carrier network. + assertFalse(mCarrierNetworkConfig.isCarrierNetwork(TEST_SSID)); + assertEquals(-1, mCarrierNetworkConfig.getNetworkEapType(TEST_SSID)); + assertEquals(null, mCarrierNetworkConfig.getCarrierName(TEST_SSID)); + + // Verify that updated SSID is associated with a carrier network. + assertTrue(mCarrierNetworkConfig.isCarrierNetwork(updatedSsid)); + assertEquals(updatedInternalEapType, mCarrierNetworkConfig.getNetworkEapType(updatedSsid)); + assertEquals(updatedCarrierName, mCarrierNetworkConfig.getCarrierName(updatedSsid)); + } + + /** + * Verify that the carrier network config is not updated when non + * {@link CarrierConfigManager#ACTION_CARRIER_CONFIG_CHANGED} intent is received. + * + * @throws Exception + */ + @Test + public void receivedNonCarrierConfigChangedIntent() throws Exception { + mBroadcastReceiver.onReceive(mContext, new Intent("dummyIntent")); + verify(mCarrierConfigManager, never()).getConfig(); + } +} |