diff options
Diffstat (limited to 'service')
6 files changed, 3 insertions, 1557 deletions
diff --git a/service/java/com/android/server/wifi/WifiConfigManager.java b/service/java/com/android/server/wifi/WifiConfigManager.java index 8180ab70b..75b39b261 100644 --- a/service/java/com/android/server/wifi/WifiConfigManager.java +++ b/service/java/com/android/server/wifi/WifiConfigManager.java @@ -47,7 +47,6 @@ import android.util.Log; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.server.LocalServices; -import com.android.server.wifi.WifiConfigStoreLegacy.WifiConfigStoreDataLegacy; import com.android.server.wifi.hotspot2.PasspointManager; import com.android.server.wifi.util.TelephonyUtil; import com.android.server.wifi.util.WifiPermissionsUtil; @@ -248,7 +247,6 @@ public class WifiConfigManager { private final TelephonyManager mTelephonyManager; private final WifiKeyStore mWifiKeyStore; private final WifiConfigStore mWifiConfigStore; - private final WifiConfigStoreLegacy mWifiConfigStoreLegacy; private final WifiPermissionsUtil mWifiPermissionsUtil; private final WifiPermissionsWrapper mWifiPermissionsWrapper; /** @@ -342,7 +340,7 @@ public class WifiConfigManager { WifiConfigManager( Context context, Clock clock, UserManager userManager, TelephonyManager telephonyManager, WifiKeyStore wifiKeyStore, - WifiConfigStore wifiConfigStore, WifiConfigStoreLegacy wifiConfigStoreLegacy, + WifiConfigStore wifiConfigStore, WifiPermissionsUtil wifiPermissionsUtil, WifiPermissionsWrapper wifiPermissionsWrapper, NetworkListStoreData networkListStoreData, @@ -354,7 +352,6 @@ public class WifiConfigManager { mTelephonyManager = telephonyManager; mWifiKeyStore = wifiKeyStore; mWifiConfigStore = wifiConfigStore; - mWifiConfigStoreLegacy = wifiConfigStoreLegacy; mWifiPermissionsUtil = wifiPermissionsUtil; mWifiPermissionsWrapper = wifiPermissionsWrapper; @@ -2697,46 +2694,6 @@ public class WifiConfigManager { } /** - * Migrate data from legacy store files. The function performs the following operations: - * 1. Check if the legacy store files are present and the new store files are absent on device. - * 2. Read all the data from the store files. - * 3. Save it to the new store files. - * 4. Delete the legacy store file. - * - * @return true if migration was successful or not needed (fresh install), false if it failed. - */ - public boolean migrateFromLegacyStore() { - if (!mWifiConfigStoreLegacy.areStoresPresent()) { - Log.d(TAG, "Legacy store files not found. No migration needed!"); - return true; - } - if (mWifiConfigStore.areStoresPresent()) { - Log.d(TAG, "New store files found. No migration needed!" - + " Remove legacy store files"); - mWifiConfigStoreLegacy.removeStores(); - return true; - } - WifiConfigStoreDataLegacy storeData = mWifiConfigStoreLegacy.read(); - Log.d(TAG, "Reading from legacy store completed"); - loadInternalData(storeData.getConfigurations(), new ArrayList<WifiConfiguration>(), - storeData.getDeletedEphemeralSSIDs()); - - // Setup user store for the current user in case it have not setup yet, so that data - // owned by the current user will be backed to the user store. - if (mDeferredUserUnlockRead) { - mWifiConfigStore.setUserStore(WifiConfigStore.createUserFile(mCurrentUserId)); - mDeferredUserUnlockRead = false; - } - - if (!saveToStore(true)) { - return false; - } - mWifiConfigStoreLegacy.removeStores(); - Log.d(TAG, "Migration from legacy store completed"); - return true; - } - - /** * Read the config store and load the in-memory lists from the store data retrieved and sends * out the networks changed broadcast. * @@ -2750,10 +2707,7 @@ public class WifiConfigManager { public boolean loadFromStore() { if (!mWifiConfigStore.areStoresPresent()) { Log.d(TAG, "New store files not found. No saved networks loaded!"); - if (!mWifiConfigStoreLegacy.areStoresPresent()) { - // No legacy store files either, so reset the pending store read flag. - mPendingStoreRead = false; - } + mPendingStoreRead = false; return true; } // If the user unlock comes in before we load from store, which means the user store have diff --git a/service/java/com/android/server/wifi/WifiConfigStoreLegacy.java b/service/java/com/android/server/wifi/WifiConfigStoreLegacy.java deleted file mode 100644 index 39e48a5cb..000000000 --- a/service/java/com/android/server/wifi/WifiConfigStoreLegacy.java +++ /dev/null @@ -1,354 +0,0 @@ -/* - * 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.IpConfiguration; -import android.net.wifi.WifiConfiguration; -import android.net.wifi.WifiEnterpriseConfig; -import android.os.Environment; -import android.util.Log; -import android.util.SparseArray; - -import com.android.server.net.IpConfigStore; -import com.android.server.wifi.hotspot2.LegacyPasspointConfig; -import com.android.server.wifi.hotspot2.LegacyPasspointConfigParser; - -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -/** - * This class provides the API's to load network configurations from legacy store - * mechanism (Pre O release). - * This class loads network configurations from: - * 1. /data/misc/wifi/networkHistory.txt - * 2. /data/misc/wifi/wpa_supplicant.conf - * 3. /data/misc/wifi/ipconfig.txt - * 4. /data/misc/wifi/PerProviderSubscription.conf - * - * The order of invocation of the public methods during migration is the following: - * 1. Check if legacy stores are present using {@link #areStoresPresent()}. - * 2. Load all the store data using {@link #read()} - * 3. Write the store data to the new store. - * 4. Remove all the legacy stores using {@link #removeStores()} - * - * NOTE: This class should only be used from WifiConfigManager and is not thread-safe! - * - * TODO(b/31065385): Passpoint config store data migration & deletion. - */ -public class WifiConfigStoreLegacy { - /** - * Log tag. - */ - private static final String TAG = "WifiConfigStoreLegacy"; - /** - * NetworkHistory config store file path. - */ - private static final File NETWORK_HISTORY_FILE = - new File(WifiNetworkHistory.NETWORK_HISTORY_CONFIG_FILE); - /** - * Passpoint config store file path. - */ - private static final File PPS_FILE = - new File(Environment.getDataMiscDirectory(), "wifi/PerProviderSubscription.conf"); - /** - * IpConfig config store file path. - */ - private static final File IP_CONFIG_FILE = - new File(Environment.getDataMiscDirectory(), "wifi/ipconfig.txt"); - /** - * List of external dependencies for WifiConfigManager. - */ - private final WifiNetworkHistory mWifiNetworkHistory; - private final WifiNative mWifiNative; - private final IpConfigStore mIpconfigStore; - - private final LegacyPasspointConfigParser mPasspointConfigParser; - - WifiConfigStoreLegacy(WifiNetworkHistory wifiNetworkHistory, - WifiNative wifiNative, IpConfigStore ipConfigStore, - LegacyPasspointConfigParser passpointConfigParser) { - mWifiNetworkHistory = wifiNetworkHistory; - mWifiNative = wifiNative; - mIpconfigStore = ipConfigStore; - mPasspointConfigParser = passpointConfigParser; - } - - /** - * Helper function to lookup the WifiConfiguration object from configKey to WifiConfiguration - * object map using the hashcode of the configKey. - * - * @param configurationMap Map of configKey to WifiConfiguration object. - * @param hashCode hash code of the configKey to match. - * @return - */ - private static WifiConfiguration lookupWifiConfigurationUsingConfigKeyHash( - Map<String, WifiConfiguration> configurationMap, int hashCode) { - for (Map.Entry<String, WifiConfiguration> entry : configurationMap.entrySet()) { - if (entry.getKey().hashCode() == hashCode) { - return entry.getValue(); - } - } - return null; - } - - /** - * Helper function to load {@link IpConfiguration} data from the ip config store file and - * populate the provided configuration map. - * - * @param configurationMap Map of configKey to WifiConfiguration object. - */ - private void loadFromIpConfigStore(Map<String, WifiConfiguration> configurationMap) { - // This is a map of the hash code of the network's configKey to the corresponding - // IpConfiguration. - SparseArray<IpConfiguration> ipConfigurations = - mIpconfigStore.readIpAndProxyConfigurations(IP_CONFIG_FILE.getAbsolutePath()); - if (ipConfigurations == null || ipConfigurations.size() == 0) { - Log.w(TAG, "No ip configurations found in ipconfig store"); - return; - } - for (int i = 0; i < ipConfigurations.size(); i++) { - int id = ipConfigurations.keyAt(i); - WifiConfiguration config = - lookupWifiConfigurationUsingConfigKeyHash(configurationMap, id); - // This is the only place the map is looked up through a (dangerous) hash-value! - if (config == null || config.ephemeral) { - Log.w(TAG, "configuration found for missing network, nid=" + id - + ", ignored, networks.size=" + Integer.toString(ipConfigurations.size())); - } else { - config.setIpConfiguration(ipConfigurations.valueAt(i)); - } - } - } - - /** - * Helper function to load {@link WifiConfiguration} data from networkHistory file and populate - * the provided configuration map and deleted ephemeral ssid list. - * - * @param configurationMap Map of configKey to WifiConfiguration object. - * @param deletedEphemeralSSIDs Map of configKey to WifiConfiguration object. - */ - private void loadFromNetworkHistory( - Map<String, WifiConfiguration> configurationMap, Set<String> deletedEphemeralSSIDs) { - // TODO: Need to revisit the scan detail cache persistance. We're not doing it in the new - // config store, so ignore it here as well. - Map<Integer, ScanDetailCache> scanDetailCaches = new HashMap<>(); - mWifiNetworkHistory.readNetworkHistory( - configurationMap, scanDetailCaches, deletedEphemeralSSIDs); - } - - /** - * Helper function to load {@link WifiConfiguration} data from wpa_supplicant and populate - * the provided configuration map and network extras. - * - * This method needs to manually parse the wpa_supplicant.conf file to retrieve some of the - * password fields like psk, wep_keys. password, etc. - * - * @param configurationMap Map of configKey to WifiConfiguration object. - * @param networkExtras Map of network extras parsed from wpa_supplicant. - */ - private void loadFromWpaSupplicant( - Map<String, WifiConfiguration> configurationMap, - SparseArray<Map<String, String>> networkExtras) { - if (!mWifiNative.migrateNetworksFromSupplicant(configurationMap, networkExtras)) { - Log.wtf(TAG, "Failed to load wifi configurations from wpa_supplicant"); - return; - } - if (configurationMap.isEmpty()) { - Log.w(TAG, "No wifi configurations found in wpa_supplicant"); - return; - } - } - - /** - * Helper function to update {@link WifiConfiguration} that represents a Passpoint - * configuration. - * - * This method will manually parse PerProviderSubscription.conf file to retrieve missing - * fields: provider friendly name, roaming consortium OIs, realm, IMSI. - * - * @param configurationMap Map of configKey to WifiConfiguration object. - * @param networkExtras Map of network extras parsed from wpa_supplicant. - */ - private void loadFromPasspointConfigStore( - Map<String, WifiConfiguration> configurationMap, - SparseArray<Map<String, String>> networkExtras) { - Map<String, LegacyPasspointConfig> passpointConfigMap = null; - try { - passpointConfigMap = mPasspointConfigParser.parseConfig(PPS_FILE.getAbsolutePath()); - } catch (IOException e) { - Log.w(TAG, "Failed to read/parse Passpoint config file: " + e.getMessage()); - } - - List<String> entriesToBeRemoved = new ArrayList<>(); - for (Map.Entry<String, WifiConfiguration> entry : configurationMap.entrySet()) { - WifiConfiguration wifiConfig = entry.getValue(); - // Ignore non-Enterprise network since enterprise configuration is required for - // Passpoint. - if (wifiConfig.enterpriseConfig == null || wifiConfig.enterpriseConfig.getEapMethod() - == WifiEnterpriseConfig.Eap.NONE) { - continue; - } - // Ignore configuration without FQDN. - Map<String, String> extras = networkExtras.get(wifiConfig.networkId); - if (extras == null || !extras.containsKey(SupplicantStaNetworkHal.ID_STRING_KEY_FQDN)) { - continue; - } - String fqdn = networkExtras.get(wifiConfig.networkId).get( - SupplicantStaNetworkHal.ID_STRING_KEY_FQDN); - - // Remove the configuration if failed to find the matching configuration in the - // Passpoint configuration file. - if (passpointConfigMap == null || !passpointConfigMap.containsKey(fqdn)) { - entriesToBeRemoved.add(entry.getKey()); - continue; - } - - // Update the missing Passpoint configuration fields to this WifiConfiguration. - LegacyPasspointConfig passpointConfig = passpointConfigMap.get(fqdn); - wifiConfig.isLegacyPasspointConfig = true; - wifiConfig.FQDN = fqdn; - wifiConfig.providerFriendlyName = passpointConfig.mFriendlyName; - if (passpointConfig.mRoamingConsortiumOis != null) { - wifiConfig.roamingConsortiumIds = Arrays.copyOf( - passpointConfig.mRoamingConsortiumOis, - passpointConfig.mRoamingConsortiumOis.length); - } - if (passpointConfig.mImsi != null) { - wifiConfig.enterpriseConfig.setPlmn(passpointConfig.mImsi); - } - if (passpointConfig.mRealm != null) { - wifiConfig.enterpriseConfig.setRealm(passpointConfig.mRealm); - } - } - - // Remove any incomplete Passpoint configurations. Should never happen, in case it does - // remove them to avoid maintaining any invalid Passpoint configurations. - for (String key : entriesToBeRemoved) { - Log.w(TAG, "Remove incomplete Passpoint configuration: " + key); - configurationMap.remove(key); - } - } - - /** - * Helper function to load from the different legacy stores: - * 1. Read the network configurations from wpa_supplicant using {@link WifiNative}. - * 2. Read the network configurations from networkHistory.txt using {@link WifiNetworkHistory}. - * 3. Read the Ip configurations from ipconfig.txt using {@link IpConfigStore}. - * 4. Read all the passpoint info from PerProviderSubscription.conf using - * {@link LegacyPasspointConfigParser}. - */ - public WifiConfigStoreDataLegacy read() { - final Map<String, WifiConfiguration> configurationMap = new HashMap<>(); - final SparseArray<Map<String, String>> networkExtras = new SparseArray<>(); - final Set<String> deletedEphemeralSSIDs = new HashSet<>(); - - loadFromWpaSupplicant(configurationMap, networkExtras); - loadFromNetworkHistory(configurationMap, deletedEphemeralSSIDs); - loadFromIpConfigStore(configurationMap); - loadFromPasspointConfigStore(configurationMap, networkExtras); - - // Now create config store data instance to be returned. - return new WifiConfigStoreDataLegacy( - new ArrayList<>(configurationMap.values()), deletedEphemeralSSIDs); - } - - /** - * Function to check if the legacy store files are present and hence load from those stores and - * then delete them. - * - * @return true if legacy store files are present, false otherwise. - */ - public boolean areStoresPresent() { - // We may have to keep the wpa_supplicant.conf file around. So, just use networkhistory.txt - // as a check to see if we have not yet migrated or not. This should be the last file - // that is deleted after migration. - File file = new File(WifiNetworkHistory.NETWORK_HISTORY_CONFIG_FILE); - return file.exists(); - } - - /** - * Method to remove all the legacy store files. This should only be invoked once all - * the data has been migrated to the new store file. - * 1. Removes all networks from wpa_supplicant and saves it to wpa_supplicant.conf - * 2. Deletes ipconfig.txt - * 3. Deletes networkHistory.txt - * - * @return true if all the store files were deleted successfully, false otherwise. - */ - public boolean removeStores() { - // TODO(b/29352330): Delete wpa_supplicant.conf file instead. - // First remove all networks from wpa_supplicant and save configuration. - if (!mWifiNative.removeAllNetworks()) { - Log.e(TAG, "Removing networks from wpa_supplicant failed"); - } - - // Now remove the ipconfig.txt file. - if (!IP_CONFIG_FILE.delete()) { - Log.e(TAG, "Removing ipconfig.txt failed"); - } - - // Now finally remove network history.txt - if (!NETWORK_HISTORY_FILE.delete()) { - Log.e(TAG, "Removing networkHistory.txt failed"); - } - - if (!PPS_FILE.delete()) { - Log.e(TAG, "Removing PerProviderSubscription.conf failed"); - } - - Log.i(TAG, "All legacy stores removed!"); - return true; - } - - /** - * Interface used to set a masked value in the provided configuration. The masked value is - * retrieved by parsing the wpa_supplicant.conf file. - */ - private interface MaskedWpaSupplicantFieldSetter { - void setValue(WifiConfiguration config, String value); - } - - /** - * Class used to encapsulate all the store data retrieved from the legacy (Pre O) store files. - */ - public static class WifiConfigStoreDataLegacy { - private List<WifiConfiguration> mConfigurations; - private Set<String> mDeletedEphemeralSSIDs; - // private List<HomeSP> mHomeSps; - - WifiConfigStoreDataLegacy(List<WifiConfiguration> configurations, - Set<String> deletedEphemeralSSIDs) { - mConfigurations = configurations; - mDeletedEphemeralSSIDs = deletedEphemeralSSIDs; - } - - public List<WifiConfiguration> getConfigurations() { - return mConfigurations; - } - - public Set<String> getDeletedEphemeralSSIDs() { - return mDeletedEphemeralSSIDs; - } - } -} diff --git a/service/java/com/android/server/wifi/WifiInjector.java b/service/java/com/android/server/wifi/WifiInjector.java index 26d702477..734c28d19 100644 --- a/service/java/com/android/server/wifi/WifiInjector.java +++ b/service/java/com/android/server/wifi/WifiInjector.java @@ -45,7 +45,6 @@ import com.android.server.am.BatteryStatsService; import com.android.server.net.DelayedDiskWrite; import com.android.server.net.IpConfigStore; import com.android.server.wifi.aware.WifiAwareMetrics; -import com.android.server.wifi.hotspot2.LegacyPasspointConfigParser; import com.android.server.wifi.hotspot2.PasspointManager; import com.android.server.wifi.hotspot2.PasspointNetworkEvaluator; import com.android.server.wifi.hotspot2.PasspointObjectFactory; @@ -101,9 +100,7 @@ public class WifiInjector { private final WifiMulticastLockManager mWifiMulticastLockManager; private final WifiConfigStore mWifiConfigStore; private final WifiKeyStore mWifiKeyStore; - private final WifiNetworkHistory mWifiNetworkHistory; private final IpConfigStore mIpConfigStore; - private final WifiConfigStoreLegacy mWifiConfigStoreLegacy; private final WifiConfigManager mWifiConfigManager; private final WifiConnectivityHelper mWifiConnectivityHelper; private final LocalLog mConnectivityLocalLog; @@ -195,15 +192,11 @@ public class WifiInjector { WifiConfigStore.createSharedFile()); // Legacy config store DelayedDiskWrite writer = new DelayedDiskWrite(); - mWifiNetworkHistory = new WifiNetworkHistory(mContext, writer); mIpConfigStore = new IpConfigStore(writer); - mWifiConfigStoreLegacy = new WifiConfigStoreLegacy( - mWifiNetworkHistory, mWifiNative, mIpConfigStore, - new LegacyPasspointConfigParser()); // Config Manager mWifiConfigManager = new WifiConfigManager(mContext, mClock, UserManager.get(mContext), TelephonyManager.from(mContext), - mWifiKeyStore, mWifiConfigStore, mWifiConfigStoreLegacy, mWifiPermissionsUtil, + mWifiKeyStore, mWifiConfigStore, mWifiPermissionsUtil, mWifiPermissionsWrapper, new NetworkListStoreData(), new DeletedEphemeralSsidsStoreData()); mWifiMetrics.setWifiConfigManager(mWifiConfigManager); diff --git a/service/java/com/android/server/wifi/WifiNetworkHistory.java b/service/java/com/android/server/wifi/WifiNetworkHistory.java deleted file mode 100644 index 282f6057d..000000000 --- a/service/java/com/android/server/wifi/WifiNetworkHistory.java +++ /dev/null @@ -1,630 +0,0 @@ -/* - * 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.content.Context; -import android.net.wifi.ScanResult; -import android.net.wifi.WifiConfiguration; -import android.net.wifi.WifiConfiguration.NetworkSelectionStatus; -import android.net.wifi.WifiSsid; -import android.os.Environment; -import android.os.Process; -import android.text.TextUtils; -import android.util.Log; - -import com.android.server.net.DelayedDiskWrite; - -import java.io.BufferedInputStream; -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.EOFException; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.text.DateFormat; -import java.util.BitSet; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; - -/** - * Provides an API to read and write the network history from WifiConfigurations to file - * This is largely separate and extra to the supplicant config file. - */ -public class WifiNetworkHistory { - public static final String TAG = "WifiNetworkHistory"; - private static final boolean DBG = true; - private static final boolean VDBG = true; - static final String NETWORK_HISTORY_CONFIG_FILE = Environment.getDataDirectory() - + "/misc/wifi/networkHistory.txt"; - /* Network History Keys */ - private static final String SSID_KEY = "SSID"; - static final String CONFIG_KEY = "CONFIG"; - private static final String CONFIG_BSSID_KEY = "CONFIG_BSSID"; - private static final String CHOICE_KEY = "CHOICE"; - private static final String CHOICE_TIME_KEY = "CHOICE_TIME"; - private static final String LINK_KEY = "LINK"; - private static final String BSSID_KEY = "BSSID"; - private static final String BSSID_KEY_END = "/BSSID"; - private static final String RSSI_KEY = "RSSI"; - private static final String FREQ_KEY = "FREQ"; - private static final String DATE_KEY = "DATE"; - private static final String MILLI_KEY = "MILLI"; - private static final String NETWORK_ID_KEY = "ID"; - private static final String PRIORITY_KEY = "PRIORITY"; - private static final String DEFAULT_GW_KEY = "DEFAULT_GW"; - private static final String AUTH_KEY = "AUTH"; - private static final String BSSID_STATUS_KEY = "BSSID_STATUS"; - private static final String SELF_ADDED_KEY = "SELF_ADDED"; - private static final String DID_SELF_ADD_KEY = "DID_SELF_ADD"; - private static final String PEER_CONFIGURATION_KEY = "PEER_CONFIGURATION"; - 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 FQDN_KEY = "FQDN"; - private static final String SCORER_OVERRIDE_KEY = "SCORER_OVERRIDE"; - private static final String SCORER_OVERRIDE_AND_SWITCH_KEY = "SCORER_OVERRIDE_AND_SWITCH"; - private static final String VALIDATED_INTERNET_ACCESS_KEY = "VALIDATED_INTERNET_ACCESS"; - private static final String NO_INTERNET_ACCESS_REPORTS_KEY = "NO_INTERNET_ACCESS_REPORTS"; - private static final String NO_INTERNET_ACCESS_EXPECTED_KEY = "NO_INTERNET_ACCESS_EXPECTED"; - private static final String EPHEMERAL_KEY = "EPHEMERAL"; - private static final String USE_EXTERNAL_SCORES_KEY = "USE_EXTERNAL_SCORES"; - private static final String METERED_HINT_KEY = "METERED_HINT"; - private static final String METERED_OVERRIDE_KEY = "METERED_OVERRIDE"; - private static final String NUM_ASSOCIATION_KEY = "NUM_ASSOCIATION"; - private static final String DELETED_EPHEMERAL_KEY = "DELETED_EPHEMERAL"; - private static final String CREATOR_NAME_KEY = "CREATOR_NAME"; - private static final String UPDATE_NAME_KEY = "UPDATE_NAME"; - 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 NETWORK_SELECTION_STATUS_KEY = "NETWORK_SELECTION_STATUS"; - private static final String NETWORK_SELECTION_DISABLE_REASON_KEY = - "NETWORK_SELECTION_DISABLE_REASON"; - private static final String HAS_EVER_CONNECTED_KEY = "HAS_EVER_CONNECTED"; - - private static final String SEPARATOR = ": "; - private static final String NL = "\n"; - - protected final DelayedDiskWrite mWriter; - Context mContext; - /* - * Lost config list, whenever we read a config from networkHistory.txt that was not in - * wpa_supplicant.conf - */ - HashSet<String> mLostConfigsDbg = new HashSet<String>(); - - public WifiNetworkHistory(Context c, DelayedDiskWrite writer) { - mContext = c; - mWriter = writer; - } - - /** - * Write network history to file, for configured networks - * - * @param networks List of ConfiguredNetworks to write to NetworkHistory - */ - public void writeKnownNetworkHistory(final List<WifiConfiguration> networks, - final ConcurrentHashMap<Integer, ScanDetailCache> scanDetailCaches, - final Set<String> deletedEphemeralSSIDs) { - - /* Make a copy */ - //final List<WifiConfiguration> networks = new ArrayList<WifiConfiguration>(); - - //for (WifiConfiguration config : mConfiguredNetworks.valuesForAllUsers()) { - // networks.add(new WifiConfiguration(config)); - //} - - mWriter.write(NETWORK_HISTORY_CONFIG_FILE, new DelayedDiskWrite.Writer() { - public void onWriteCalled(DataOutputStream out) throws IOException { - for (WifiConfiguration config : networks) { - //loge("onWriteCalled write SSID: " + config.SSID); - /* if (config.getLinkProperties() != null) - loge(" lp " + config.getLinkProperties().toString()); - else - loge("attempt config w/o lp"); - */ - NetworkSelectionStatus status = config.getNetworkSelectionStatus(); - if (VDBG) { - int numlink = 0; - if (config.linkedConfigurations != null) { - numlink = config.linkedConfigurations.size(); - } - String disableTime; - if (config.getNetworkSelectionStatus().isNetworkEnabled()) { - disableTime = ""; - } else { - disableTime = "Disable time: " + DateFormat.getInstance().format( - config.getNetworkSelectionStatus().getDisableTime()); - } - logd("saving network history: " + config.configKey() + " gw: " - + config.defaultGwMacAddress + " Network Selection-status: " - + status.getNetworkStatusString() - + disableTime + " ephemeral=" + config.ephemeral - + " choice:" + status.getConnectChoice() - + " link:" + numlink - + " status:" + config.status - + " nid:" + config.networkId - + " hasEverConnected: " + status.getHasEverConnected()); - } - - if (!isValid(config)) { - continue; - } - - if (config.SSID == null) { - if (VDBG) { - logv("writeKnownNetworkHistory trying to write config with null SSID"); - } - continue; - } - if (VDBG) { - logv("writeKnownNetworkHistory write config " + config.configKey()); - } - out.writeUTF(CONFIG_KEY + SEPARATOR + config.configKey() + NL); - - if (config.SSID != null) { - out.writeUTF(SSID_KEY + SEPARATOR + config.SSID + NL); - } - if (config.BSSID != null) { - out.writeUTF(CONFIG_BSSID_KEY + SEPARATOR + config.BSSID + NL); - } else { - out.writeUTF(CONFIG_BSSID_KEY + SEPARATOR + "null" + NL); - } - if (config.FQDN != null) { - out.writeUTF(FQDN_KEY + SEPARATOR + config.FQDN + NL); - } - - out.writeUTF(PRIORITY_KEY + SEPARATOR + Integer.toString(config.priority) + NL); - out.writeUTF(NETWORK_ID_KEY + SEPARATOR - + Integer.toString(config.networkId) + NL); - out.writeUTF(SELF_ADDED_KEY + SEPARATOR - + Boolean.toString(config.selfAdded) + NL); - out.writeUTF(DID_SELF_ADD_KEY + SEPARATOR - + Boolean.toString(config.didSelfAdd) + NL); - out.writeUTF(NO_INTERNET_ACCESS_REPORTS_KEY + SEPARATOR - + Integer.toString(config.numNoInternetAccessReports) + NL); - out.writeUTF(VALIDATED_INTERNET_ACCESS_KEY + SEPARATOR - + Boolean.toString(config.validatedInternetAccess) + NL); - out.writeUTF(NO_INTERNET_ACCESS_EXPECTED_KEY + SEPARATOR + - Boolean.toString(config.noInternetAccessExpected) + NL); - out.writeUTF(EPHEMERAL_KEY + SEPARATOR - + Boolean.toString(config.ephemeral) + NL); - out.writeUTF(METERED_HINT_KEY + SEPARATOR - + Boolean.toString(config.meteredHint) + NL); - out.writeUTF(METERED_OVERRIDE_KEY + SEPARATOR - + Integer.toString(config.meteredOverride) + NL); - out.writeUTF(USE_EXTERNAL_SCORES_KEY + SEPARATOR - + Boolean.toString(config.useExternalScores) + NL); - if (config.creationTime != null) { - out.writeUTF(CREATION_TIME_KEY + SEPARATOR + config.creationTime + NL); - } - if (config.updateTime != null) { - out.writeUTF(UPDATE_TIME_KEY + SEPARATOR + config.updateTime + NL); - } - if (config.peerWifiConfiguration != null) { - out.writeUTF(PEER_CONFIGURATION_KEY + SEPARATOR - + config.peerWifiConfiguration + NL); - } - out.writeUTF(SCORER_OVERRIDE_KEY + SEPARATOR - + Integer.toString(config.numScorerOverride) + NL); - out.writeUTF(SCORER_OVERRIDE_AND_SWITCH_KEY + SEPARATOR - + Integer.toString(config.numScorerOverrideAndSwitchedNetwork) + NL); - out.writeUTF(NUM_ASSOCIATION_KEY + SEPARATOR - + Integer.toString(config.numAssociation) + NL); - out.writeUTF(CREATOR_UID_KEY + SEPARATOR - + Integer.toString(config.creatorUid) + NL); - out.writeUTF(CONNECT_UID_KEY + SEPARATOR - + Integer.toString(config.lastConnectUid) + NL); - out.writeUTF(UPDATE_UID_KEY + SEPARATOR - + Integer.toString(config.lastUpdateUid) + NL); - out.writeUTF(CREATOR_NAME_KEY + SEPARATOR - + config.creatorName + NL); - out.writeUTF(UPDATE_NAME_KEY + SEPARATOR - + 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); - out.writeUTF(AUTH_KEY + SEPARATOR - + allowedKeyManagementString + NL); - out.writeUTF(NETWORK_SELECTION_STATUS_KEY + SEPARATOR - + status.getNetworkSelectionStatus() + NL); - out.writeUTF(NETWORK_SELECTION_DISABLE_REASON_KEY + SEPARATOR - + status.getNetworkSelectionDisableReason() + NL); - - if (status.getConnectChoice() != null) { - out.writeUTF(CHOICE_KEY + SEPARATOR + status.getConnectChoice() + NL); - out.writeUTF(CHOICE_TIME_KEY + SEPARATOR - + status.getConnectChoiceTimestamp() + NL); - } - - if (config.linkedConfigurations != null) { - log("writeKnownNetworkHistory write linked " - + config.linkedConfigurations.size()); - - for (String key : config.linkedConfigurations.keySet()) { - out.writeUTF(LINK_KEY + SEPARATOR + key + NL); - } - } - - String macAddress = config.defaultGwMacAddress; - if (macAddress != null) { - out.writeUTF(DEFAULT_GW_KEY + SEPARATOR + macAddress + NL); - } - - if (getScanDetailCache(config, scanDetailCaches) != null) { - for (ScanDetail scanDetail : getScanDetailCache(config, - scanDetailCaches).values()) { - ScanResult result = scanDetail.getScanResult(); - out.writeUTF(BSSID_KEY + SEPARATOR - + result.BSSID + NL); - out.writeUTF(FREQ_KEY + SEPARATOR - + Integer.toString(result.frequency) + NL); - - out.writeUTF(RSSI_KEY + SEPARATOR - + Integer.toString(result.level) + NL); - - out.writeUTF(BSSID_KEY_END + NL); - } - } - out.writeUTF(HAS_EVER_CONNECTED_KEY + SEPARATOR - + Boolean.toString(status.getHasEverConnected()) + NL); - out.writeUTF(NL); - // Add extra blank lines for clarity - out.writeUTF(NL); - out.writeUTF(NL); - } - if (deletedEphemeralSSIDs != null && deletedEphemeralSSIDs.size() > 0) { - for (String ssid : deletedEphemeralSSIDs) { - out.writeUTF(DELETED_EPHEMERAL_KEY); - out.writeUTF(ssid); - out.writeUTF(NL); - } - } - } - }); - } - - /** - * 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 - */ - public void readNetworkHistory(Map<String, WifiConfiguration> configs, - Map<Integer, ScanDetailCache> scanDetailCaches, - Set<String> deletedEphemeralSSIDs) { - - try (DataInputStream in = - new DataInputStream(new BufferedInputStream( - new FileInputStream(NETWORK_HISTORY_CONFIG_FILE)))) { - - String bssid = null; - String ssid = null; - - int freq = 0; - int status = 0; - long seen = 0; - int rssi = WifiConfiguration.INVALID_RSSI; - String caps = null; - - WifiConfiguration config = null; - while (true) { - String line = in.readUTF(); - if (line == null) { - break; - } - int colon = line.indexOf(':'); - if (colon < 0) { - continue; - } - - String key = line.substring(0, colon).trim(); - String value = line.substring(colon + 1).trim(); - - if (key.equals(CONFIG_KEY)) { - config = configs.get(value); - - // skip reading that configuration data - // since we don't have a corresponding network ID - if (config == null) { - Log.e(TAG, "readNetworkHistory didnt find netid for hash=" - + Integer.toString(value.hashCode()) - + " key: " + value); - mLostConfigsDbg.add(value); - continue; - } else { - // After an upgrade count old connections as owned by system - if (config.creatorName == null || config.lastUpdateName == null) { - config.creatorName = - mContext.getPackageManager().getNameForUid(Process.SYSTEM_UID); - config.lastUpdateName = config.creatorName; - - if (DBG) { - Log.w(TAG, "Upgrading network " + config.networkId - + " to " + config.creatorName); - } - } - } - } else if (config != null) { - NetworkSelectionStatus networkStatus = config.getNetworkSelectionStatus(); - switch (key) { - case SSID_KEY: - if (config.isPasspoint()) { - break; - } - ssid = value; - if (config.SSID != null && !config.SSID.equals(ssid)) { - loge("Error parsing network history file, mismatched SSIDs"); - config = null; //error - ssid = null; - } else { - config.SSID = ssid; - } - break; - case CONFIG_BSSID_KEY: - config.BSSID = value.equals("null") ? null : value; - break; - case FQDN_KEY: - // Check for literal 'null' to be backwards compatible. - config.FQDN = value.equals("null") ? null : value; - break; - case DEFAULT_GW_KEY: - config.defaultGwMacAddress = value; - break; - case SELF_ADDED_KEY: - config.selfAdded = Boolean.parseBoolean(value); - break; - case DID_SELF_ADD_KEY: - config.didSelfAdd = Boolean.parseBoolean(value); - break; - case NO_INTERNET_ACCESS_REPORTS_KEY: - config.numNoInternetAccessReports = Integer.parseInt(value); - break; - case VALIDATED_INTERNET_ACCESS_KEY: - config.validatedInternetAccess = Boolean.parseBoolean(value); - break; - case NO_INTERNET_ACCESS_EXPECTED_KEY: - config.noInternetAccessExpected = Boolean.parseBoolean(value); - break; - case CREATION_TIME_KEY: - config.creationTime = value; - break; - case UPDATE_TIME_KEY: - config.updateTime = value; - break; - case EPHEMERAL_KEY: - config.ephemeral = Boolean.parseBoolean(value); - break; - case METERED_HINT_KEY: - config.meteredHint = Boolean.parseBoolean(value); - break; - case METERED_OVERRIDE_KEY: - config.meteredOverride = Integer.parseInt(value); - break; - case USE_EXTERNAL_SCORES_KEY: - config.useExternalScores = Boolean.parseBoolean(value); - break; - case CREATOR_UID_KEY: - config.creatorUid = Integer.parseInt(value); - break; - case SCORER_OVERRIDE_KEY: - config.numScorerOverride = Integer.parseInt(value); - break; - case SCORER_OVERRIDE_AND_SWITCH_KEY: - config.numScorerOverrideAndSwitchedNetwork = Integer.parseInt(value); - break; - case NUM_ASSOCIATION_KEY: - config.numAssociation = Integer.parseInt(value); - break; - case CONNECT_UID_KEY: - config.lastConnectUid = Integer.parseInt(value); - break; - case UPDATE_UID_KEY: - config.lastUpdateUid = Integer.parseInt(value); - break; - case PEER_CONFIGURATION_KEY: - config.peerWifiConfiguration = value; - break; - case NETWORK_SELECTION_STATUS_KEY: - int networkStatusValue = Integer.parseInt(value); - // Reset temporarily disabled network status - if (networkStatusValue == - NetworkSelectionStatus.NETWORK_SELECTION_TEMPORARY_DISABLED) { - networkStatusValue = - NetworkSelectionStatus.NETWORK_SELECTION_ENABLED; - } - networkStatus.setNetworkSelectionStatus(networkStatusValue); - break; - case NETWORK_SELECTION_DISABLE_REASON_KEY: - networkStatus.setNetworkSelectionDisableReason(Integer.parseInt(value)); - break; - case CHOICE_KEY: - networkStatus.setConnectChoice(value); - break; - case CHOICE_TIME_KEY: - networkStatus.setConnectChoiceTimestamp(Long.parseLong(value)); - break; - case LINK_KEY: - if (config.linkedConfigurations == null) { - config.linkedConfigurations = new HashMap<>(); - } else { - config.linkedConfigurations.put(value, -1); - } - break; - case BSSID_KEY: - status = 0; - ssid = null; - bssid = null; - freq = 0; - seen = 0; - rssi = WifiConfiguration.INVALID_RSSI; - caps = ""; - break; - case RSSI_KEY: - rssi = Integer.parseInt(value); - break; - case FREQ_KEY: - freq = Integer.parseInt(value); - break; - case DATE_KEY: - /* - * when reading the configuration from file we don't update the date - * so as to avoid reading back stale or non-sensical data that would - * depend on network time. - * The date of a WifiConfiguration should only come from actual scan - * result. - * - String s = key.replace(FREQ_KEY, ""); - seen = Integer.getInteger(s); - */ - break; - case BSSID_KEY_END: - if ((bssid != null) && (ssid != null)) { - if (getScanDetailCache(config, scanDetailCaches) != null) { - WifiSsid wssid = WifiSsid.createFromAsciiEncoded(ssid); - ScanDetail scanDetail = new ScanDetail(wssid, bssid, - caps, rssi, freq, (long) 0, seen); - getScanDetailCache(config, scanDetailCaches).put(scanDetail); - } - } - break; - case DELETED_EPHEMERAL_KEY: - if (!TextUtils.isEmpty(value)) { - deletedEphemeralSSIDs.add(value); - } - break; - case CREATOR_NAME_KEY: - config.creatorName = value; - break; - case UPDATE_NAME_KEY: - config.lastUpdateName = value; - break; - case USER_APPROVED_KEY: - config.userApproved = Integer.parseInt(value); - break; - case SHARED_KEY: - config.shared = Boolean.parseBoolean(value); - break; - case HAS_EVER_CONNECTED_KEY: - networkStatus.setHasEverConnected(Boolean.parseBoolean(value)); - break; - } - } - } - } catch (EOFException e) { - // do nothing - } catch (FileNotFoundException e) { - Log.i(TAG, "readNetworkHistory: no config file, " + e); - } catch (NumberFormatException e) { - Log.e(TAG, "readNetworkHistory: failed to parse, " + e, e); - } catch (IOException e) { - Log.e(TAG, "readNetworkHistory: failed to read, " + e, e); - } - } - - /** - * Ported this out of WifiServiceImpl, I have no idea what it's doing - * <TODO> figure out what/why this is doing - * <TODO> Port it into WifiConfiguration, then remove all the silly business from ServiceImpl - */ - public boolean isValid(WifiConfiguration config) { - if (config.allowedKeyManagement == null) { - return false; - } - if (config.allowedKeyManagement.cardinality() > 1) { - if (config.allowedKeyManagement.cardinality() != 2) { - return false; - } - if (!config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_EAP)) { - return false; - } - if ((!config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.IEEE8021X)) - && (!config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_PSK))) { - return false; - } - } - return true; - } - - private static String makeString(BitSet set, String[] strings) { - StringBuffer buf = new StringBuffer(); - int nextSetBit = -1; - - /* Make sure all set bits are in [0, strings.length) to avoid - * going out of bounds on strings. (Shouldn't happen, but...) */ - set = set.get(0, strings.length); - - while ((nextSetBit = set.nextSetBit(nextSetBit + 1)) != -1) { - buf.append(strings[nextSetBit].replace('_', '-')).append(' '); - } - - // remove trailing space - if (set.cardinality() > 0) { - buf.setLength(buf.length() - 1); - } - - return buf.toString(); - } - - protected void logv(String s) { - Log.v(TAG, s); - } - protected void logd(String s) { - Log.d(TAG, s); - } - protected void log(String s) { - Log.d(TAG, s); - } - protected void loge(String s) { - loge(s, false); - } - protected void loge(String s, boolean stack) { - if (stack) { - Log.e(TAG, s + " stack:" + Thread.currentThread().getStackTrace()[2].getMethodName() - + " - " + Thread.currentThread().getStackTrace()[3].getMethodName() - + " - " + Thread.currentThread().getStackTrace()[4].getMethodName() - + " - " + Thread.currentThread().getStackTrace()[5].getMethodName()); - } else { - Log.e(TAG, s); - } - } - - private ScanDetailCache getScanDetailCache(WifiConfiguration config, - Map<Integer, ScanDetailCache> scanDetailCaches) { - if (config == null || scanDetailCaches == null) return null; - ScanDetailCache cache = scanDetailCaches.get(config.networkId); - if (cache == null && config.networkId != WifiConfiguration.INVALID_NETWORK_ID) { - cache = - new ScanDetailCache( - config, WifiConfigManager.SCAN_CACHE_ENTRIES_MAX_SIZE, - WifiConfigManager.SCAN_CACHE_ENTRIES_TRIM_SIZE); - scanDetailCaches.put(config.networkId, cache); - } - return cache; - } -} diff --git a/service/java/com/android/server/wifi/WifiStateMachine.java b/service/java/com/android/server/wifi/WifiStateMachine.java index 1d26f0448..38c767f94 100644 --- a/service/java/com/android/server/wifi/WifiStateMachine.java +++ b/service/java/com/android/server/wifi/WifiStateMachine.java @@ -4274,10 +4274,6 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss mLastSignalLevel = -1; mWifiInfo.setMacAddress(mWifiNative.getMacAddress()); - // Attempt to migrate data out of legacy store. - if (!mWifiConfigManager.migrateFromLegacyStore()) { - Log.e(TAG, "Failed to migrate from legacy config store"); - } initializeWpsDetails(); sendSupplicantConnectionChangedBroadcast(true); transitionTo(mSupplicantStartedState); diff --git a/service/java/com/android/server/wifi/hotspot2/LegacyPasspointConfigParser.java b/service/java/com/android/server/wifi/hotspot2/LegacyPasspointConfigParser.java deleted file mode 100644 index 31795f126..000000000 --- a/service/java/com/android/server/wifi/hotspot2/LegacyPasspointConfigParser.java +++ /dev/null @@ -1,513 +0,0 @@ -/* - * 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.hotspot2; - -import android.text.TextUtils; -import android.util.Log; -import android.util.Pair; - -import java.io.BufferedReader; -import java.io.FileReader; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * Utility class for parsing legacy (N and older) Passpoint configuration file content - * (/data/misc/wifi/PerProviderSubscription.conf). In N and older, only Release 1 is supported. - * - * This class only retrieve the relevant Release 1 configuration fields that are not backed - * elsewhere. Below are relevant fields: - * - FQDN (used for linking with configuration data stored elsewhere) - * - Friendly Name - * - Roaming Consortium - * - Realm - * - IMSI (for SIM credential) - * - * Below is an example content of a Passpoint configuration file: - * - * tree 3:1.2(urn:wfa:mo:hotspot2dot0-perprovidersubscription:1.0) - * 8:MgmtTree+ - * 17:PerProviderSubscription+ - * 4:r1i1+ - * 6:HomeSP+ - * c:FriendlyName=d:Test Provider - * 4:FQDN=8:test.net - * 13:RoamingConsortiumOI=9:1234,5678 - * . - * a:Credential+ - * 10:UsernamePassword+ - * 8:Username=4:user - * 8:Password=4:pass - * - * 9:EAPMethod+ - * 7:EAPType=2:21 - * b:InnerMethod=3:PAP - * . - * . - * 5:Realm=a:boingo.com - * . - * . - * . - * . - * - * Each string is prefixed with a "|StringBytesInHex|:". - * '+' indicates start of a new internal node. - * '.' indicates end of the current internal node. - * '=' indicates "value" of a leaf node. - * - */ -public class LegacyPasspointConfigParser { - private static final String TAG = "LegacyPasspointConfigParser"; - - private static final String TAG_MANAGEMENT_TREE = "MgmtTree"; - private static final String TAG_PER_PROVIDER_SUBSCRIPTION = "PerProviderSubscription"; - private static final String TAG_HOMESP = "HomeSP"; - private static final String TAG_FQDN = "FQDN"; - private static final String TAG_FRIENDLY_NAME = "FriendlyName"; - private static final String TAG_ROAMING_CONSORTIUM_OI = "RoamingConsortiumOI"; - private static final String TAG_CREDENTIAL = "Credential"; - private static final String TAG_REALM = "Realm"; - private static final String TAG_SIM = "SIM"; - private static final String TAG_IMSI = "IMSI"; - - private static final String LONG_ARRAY_SEPARATOR = ","; - private static final String END_OF_INTERNAL_NODE_INDICATOR = "."; - private static final char START_OF_INTERNAL_NODE_INDICATOR = '+'; - private static final char STRING_PREFIX_INDICATOR = ':'; - private static final char STRING_VALUE_INDICATOR = '='; - - /** - * An abstraction for a node within a tree. A node can be an internal node (contained - * children nodes) or a leaf node (contained a String value). - */ - private abstract static class Node { - private final String mName; - Node(String name) { - mName = name; - } - - /** - * @return the name of the node - */ - public String getName() { - return mName; - } - - /** - * Applies for internal node only. - * - * @return the list of children nodes. - */ - public abstract List<Node> getChildren(); - - /** - * Applies for leaf node only. - * - * @return the string value of the node - */ - public abstract String getValue(); - } - - /** - * Class representing an internal node of a tree. It contained a list of child nodes. - */ - private static class InternalNode extends Node { - private final List<Node> mChildren; - InternalNode(String name, List<Node> children) { - super(name); - mChildren = children; - } - - @Override - public List<Node> getChildren() { - return mChildren; - } - - @Override - public String getValue() { - return null; - } - } - - /** - * Class representing a leaf node of a tree. It contained a String type value. - */ - private static class LeafNode extends Node { - private final String mValue; - LeafNode(String name, String value) { - super(name); - mValue = value; - } - - @Override - public List<Node> getChildren() { - return null; - } - - @Override - public String getValue() { - return mValue; - } - } - - public LegacyPasspointConfigParser() {} - - /** - * Parse the legacy Passpoint configuration file content, only retrieve the relevant - * configurations that are not saved elsewhere. - * - * For both N and M, only Release 1 is supported. Most of the configurations are saved - * elsewhere as part of the {@link android.net.wifi.WifiConfiguration} data. - * The configurations needed from the legacy Passpoint configuration file are: - * - * - FQDN - needed to be able to link to the associated {@link WifiConfiguration} data - * - Friendly Name - * - Roaming Consortium OIs - * - Realm - * - IMSI (for SIM credential) - * - * Make this function non-static so that it can be mocked during unit test. - * - * @param fileName The file name of the configuration file - * @return Map of FQDN to {@link LegacyPasspointConfig} - * @throws IOException - */ - public Map<String, LegacyPasspointConfig> parseConfig(String fileName) - throws IOException { - Map<String, LegacyPasspointConfig> configs = new HashMap<>(); - BufferedReader in = new BufferedReader(new FileReader(fileName)); - in.readLine(); // Ignore the first line which contained the header. - - // Convert the configuration data to a management tree represented by a root {@link Node}. - Node root = buildNode(in); - - if (root == null || root.getChildren() == null) { - Log.d(TAG, "Empty configuration data"); - return configs; - } - - // Verify root node name. - if (!TextUtils.equals(TAG_MANAGEMENT_TREE, root.getName())) { - throw new IOException("Unexpected root node: " + root.getName()); - } - - // Process and retrieve the configuration from each PPS (PerProviderSubscription) node. - List<Node> ppsNodes = root.getChildren(); - for (Node ppsNode : ppsNodes) { - LegacyPasspointConfig config = processPpsNode(ppsNode); - configs.put(config.mFqdn, config); - } - return configs; - } - - /** - * Build a {@link Node} from the current line in the buffer. A node can be an internal - * node (ends with '+') or a leaf node. - * - * @param in Input buffer to read data from - * @return {@link Node} representing the current line - * @throws IOException - */ - private static Node buildNode(BufferedReader in) throws IOException { - // Read until non-empty line. - String currentLine = null; - while ((currentLine = in.readLine()) != null) { - if (!currentLine.isEmpty()) { - break; - } - } - - // Return null if EOF is reached. - if (currentLine == null) { - return null; - } - - // Remove the leading and the trailing whitespaces. - currentLine = currentLine.trim(); - - // Check for the internal node terminator. - if (TextUtils.equals(END_OF_INTERNAL_NODE_INDICATOR, currentLine)) { - return null; - } - - // Parse the name-value of the current line. The value will be null if the current line - // is not a leaf node (e.g. line ends with a '+'). - // Each line is encoded in UTF-8. - Pair<String, String> nameValuePair = - parseLine(currentLine.getBytes(StandardCharsets.UTF_8)); - if (nameValuePair.second != null) { - return new LeafNode(nameValuePair.first, nameValuePair.second); - } - - // Parse the children contained under this internal node. - List<Node> children = new ArrayList<>(); - Node child = null; - while ((child = buildNode(in)) != null) { - children.add(child); - } - return new InternalNode(nameValuePair.first, children); - } - - /** - * Process a PPS (PerProviderSubscription) node to retrieve Passpoint configuration data. - * - * @param ppsNode The PPS node to process - * @return {@link LegacyPasspointConfig} - * @throws IOException - */ - private static LegacyPasspointConfig processPpsNode(Node ppsNode) throws IOException { - if (ppsNode.getChildren() == null || ppsNode.getChildren().size() != 1) { - throw new IOException("PerProviderSubscription node should contain " - + "one instance node"); - } - - if (!TextUtils.equals(TAG_PER_PROVIDER_SUBSCRIPTION, ppsNode.getName())) { - throw new IOException("Unexpected name for PPS node: " + ppsNode.getName()); - } - - // Retrieve the PPS instance node. - Node instanceNode = ppsNode.getChildren().get(0); - if (instanceNode.getChildren() == null) { - throw new IOException("PPS instance node doesn't contained any children"); - } - - // Process and retrieve the relevant configurations under the PPS instance node. - LegacyPasspointConfig config = new LegacyPasspointConfig(); - for (Node node : instanceNode.getChildren()) { - switch (node.getName()) { - case TAG_HOMESP: - processHomeSPNode(node, config); - break; - case TAG_CREDENTIAL: - processCredentialNode(node, config); - break; - default: - Log.d(TAG, "Ignore uninterested field under PPS instance: " + node.getName()); - break; - } - } - if (config.mFqdn == null) { - throw new IOException("PPS instance missing FQDN"); - } - return config; - } - - /** - * Process a HomeSP node to retrieve configuration data into the given |config|. - * - * @param homeSpNode The HomeSP node to process - * @param config The config object to fill in the data - * @throws IOException - */ - private static void processHomeSPNode(Node homeSpNode, LegacyPasspointConfig config) - throws IOException { - if (homeSpNode.getChildren() == null) { - throw new IOException("HomeSP node should contain at least one child node"); - } - - for (Node node : homeSpNode.getChildren()) { - switch (node.getName()) { - case TAG_FQDN: - config.mFqdn = getValue(node); - break; - case TAG_FRIENDLY_NAME: - config.mFriendlyName = getValue(node); - break; - case TAG_ROAMING_CONSORTIUM_OI: - config.mRoamingConsortiumOis = parseLongArray(getValue(node)); - break; - default: - Log.d(TAG, "Ignore uninterested field under HomeSP: " + node.getName()); - break; - } - } - } - - /** - * Process a Credential node to retrieve configuration data into the given |config|. - * - * @param credentialNode The Credential node to process - * @param config The config object to fill in the data - * @throws IOException - */ - private static void processCredentialNode(Node credentialNode, - LegacyPasspointConfig config) - throws IOException { - if (credentialNode.getChildren() == null) { - throw new IOException("Credential node should contain at least one child node"); - } - - for (Node node : credentialNode.getChildren()) { - switch (node.getName()) { - case TAG_REALM: - config.mRealm = getValue(node); - break; - case TAG_SIM: - processSimNode(node, config); - break; - default: - Log.d(TAG, "Ignore uninterested field under Credential: " + node.getName()); - break; - } - } - } - - /** - * Process a SIM node to retrieve configuration data into the given |config|. - * - * @param simNode The SIM node to process - * @param config The config object to fill in the data - * @throws IOException - */ - private static void processSimNode(Node simNode, LegacyPasspointConfig config) - throws IOException { - if (simNode.getChildren() == null) { - throw new IOException("SIM node should contain at least one child node"); - } - - for (Node node : simNode.getChildren()) { - switch (node.getName()) { - case TAG_IMSI: - config.mImsi = getValue(node); - break; - default: - Log.d(TAG, "Ignore uninterested field under SIM: " + node.getName()); - break; - } - } - } - - /** - * Parse the given line in the legacy Passpoint configuration file. - * A line can be in the following formats: - * 2:ab+ // internal node - * 2:ab=2:bc // leaf node - * . // end of internal node - * - * @param line The line to parse - * @return name-value pair, a value of null indicates internal node - * @throws IOException - */ - private static Pair<String, String> parseLine(byte[] lineBytes) throws IOException { - Pair<String, Integer> nameIndexPair = parseString(lineBytes, 0); - int currentIndex = nameIndexPair.second; - try { - if (lineBytes[currentIndex] == START_OF_INTERNAL_NODE_INDICATOR) { - return Pair.create(nameIndexPair.first, null); - } - - if (lineBytes[currentIndex] != STRING_VALUE_INDICATOR) { - throw new IOException("Invalid line - missing both node and value indicator: " - + new String(lineBytes, StandardCharsets.UTF_8)); - } - } catch (IndexOutOfBoundsException e) { - throw new IOException("Invalid line - " + e.getMessage() + ": " - + new String(lineBytes, StandardCharsets.UTF_8)); - } - Pair<String, Integer> valueIndexPair = parseString(lineBytes, currentIndex + 1); - return Pair.create(nameIndexPair.first, valueIndexPair.first); - } - - /** - * Parse a string value in the given line from the given start index. - * A string value is in the following format: - * |HexByteLength|:|String| - * - * The length value indicates the number of UTF-8 bytes in hex for the given string. - * - * For example: 3:abc - * - * @param lineBytes The UTF-8 bytes of the line to parse - * @param startIndex The start index from the given line to parse from - * @return Pair of a string value and an index pointed to character after the string value - * @throws IOException - */ - private static Pair<String, Integer> parseString(byte[] lineBytes, int startIndex) - throws IOException { - // Locate the index that separate length and the string value. - int prefixIndex = -1; - for (int i = startIndex; i < lineBytes.length; i++) { - if (lineBytes[i] == STRING_PREFIX_INDICATOR) { - prefixIndex = i; - break; - } - } - if (prefixIndex == -1) { - throw new IOException("Invalid line - missing string prefix: " - + new String(lineBytes, StandardCharsets.UTF_8)); - } - - try { - String lengthStr = new String(lineBytes, startIndex, prefixIndex - startIndex, - StandardCharsets.UTF_8); - int length = Integer.parseInt(lengthStr, 16); - int strStartIndex = prefixIndex + 1; - // The length might account for bytes for the whitespaces, since the whitespaces are - // already trimmed, ignore them. - if ((strStartIndex + length) > lineBytes.length) { - length = lineBytes.length - strStartIndex; - } - return Pair.create( - new String(lineBytes, strStartIndex, length, StandardCharsets.UTF_8), - strStartIndex + length); - } catch (NumberFormatException | IndexOutOfBoundsException e) { - throw new IOException("Invalid line - " + e.getMessage() + ": " - + new String(lineBytes, StandardCharsets.UTF_8)); - } - } - - /** - * Parse a long array from the given string. - * - * @param str The string to parse - * @return long[] - * @throws IOException - */ - private static long[] parseLongArray(String str) - throws IOException { - String[] strArray = str.split(LONG_ARRAY_SEPARATOR); - long[] longArray = new long[strArray.length]; - for (int i = 0; i < longArray.length; i++) { - try { - longArray[i] = Long.parseLong(strArray[i], 16); - } catch (NumberFormatException e) { - throw new IOException("Invalid long integer value: " + strArray[i]); - } - } - return longArray; - } - - /** - * Get the String value of the given node. An IOException will be thrown if the given - * node doesn't contain a String value (internal node). - * - * @param node The node to get the value from - * @return String - * @throws IOException - */ - private static String getValue(Node node) throws IOException { - if (node.getValue() == null) { - throw new IOException("Attempt to retreive value from non-leaf node: " - + node.getName()); - } - return node.getValue(); - } -} |