summaryrefslogtreecommitdiff
path: root/service
diff options
context:
space:
mode:
Diffstat (limited to 'service')
-rw-r--r--service/java/com/android/server/wifi/WifiConfigManager.java50
-rw-r--r--service/java/com/android/server/wifi/WifiConfigStoreLegacy.java354
-rw-r--r--service/java/com/android/server/wifi/WifiInjector.java9
-rw-r--r--service/java/com/android/server/wifi/WifiNetworkHistory.java630
-rw-r--r--service/java/com/android/server/wifi/WifiStateMachine.java4
-rw-r--r--service/java/com/android/server/wifi/hotspot2/LegacyPasspointConfigParser.java513
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();
- }
-}