summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--service/java/com/android/server/wifi/SoftApStoreData.java172
-rw-r--r--service/java/com/android/server/wifi/WifiApConfigStore.java144
-rw-r--r--service/java/com/android/server/wifi/WifiConfigStore.java109
-rw-r--r--service/java/com/android/server/wifi/WifiInjector.java18
-rw-r--r--service/wifi.rc1
-rw-r--r--service/wifi_inprocess.rc1
-rw-r--r--tests/wifitests/Android.bp1
-rw-r--r--tests/wifitests/src/com/android/server/wifi/SoftApStoreDataTest.java205
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiApConfigStoreTest.java191
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java6
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiConfigStoreTest.java5
11 files changed, 665 insertions, 188 deletions
diff --git a/service/java/com/android/server/wifi/SoftApStoreData.java b/service/java/com/android/server/wifi/SoftApStoreData.java
new file mode 100644
index 000000000..2879c2aad
--- /dev/null
+++ b/service/java/com/android/server/wifi/SoftApStoreData.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2019 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.annotation.Nullable;
+import android.net.wifi.WifiConfiguration;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.server.wifi.util.WifiConfigStoreEncryptionUtil;
+import com.android.server.wifi.util.XmlUtil;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.IOException;
+import java.util.BitSet;
+
+/**
+ * Store data for SoftAp
+ */
+public class SoftApStoreData implements WifiConfigStore.StoreData {
+ private static final String TAG = "SoftApStoreData";
+ private static final String XML_TAG_SECTION_HEADER_SOFTAP = "SoftAp";
+ private static final String XML_TAG_SSID = "SSID";
+ private static final String XML_TAG_BAND = "Band";
+ private static final String XML_TAG_CHANNEL = "Channel";
+ private static final String XML_TAG_HIDDEN_SSID = "HiddenSSID";
+ private static final String XML_TAG_ALLOWED_KEY_MGMT = "AllowedKeyMgmt";
+ private static final String XML_TAG_PRE_SHARED_KEY = "PreSharedKey";
+
+ private final DataSource mDataSource;
+
+ /**
+ * Interface define the data source for the notifier store data.
+ */
+ public interface DataSource {
+ /**
+ * Retrieve the SoftAp configuration from the data source to serialize them to disk.
+ *
+ * @return {@link WifiConfiguration} Instance of WifiConfiguration.
+ */
+ WifiConfiguration toSerialize();
+
+ /**
+ * Set the SoftAp configuration in the data source after serializing them from disk.
+ *
+ * @param config {@link WifiConfiguration} Instance of WifiConfiguration.
+ */
+ void fromDeserialized(WifiConfiguration config);
+
+ /**
+ * Clear internal data structure in preparation for user switch or initial store read.
+ */
+ void reset();
+
+ /**
+ * Indicates whether there is new data to serialize.
+ */
+ boolean hasNewDataToSerialize();
+ }
+
+ /**
+ * Creates the SSID Set store data.
+ *
+ * @param dataSource The DataSource that implements the update and retrieval of the SSID set.
+ */
+ SoftApStoreData(DataSource dataSource) {
+ mDataSource = dataSource;
+ }
+
+ @Override
+ public void serializeData(XmlSerializer out,
+ @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)
+ throws XmlPullParserException, IOException {
+ WifiConfiguration softApConfig = mDataSource.toSerialize();
+ if (softApConfig != null) {
+ XmlUtil.writeNextValue(out, XML_TAG_SSID, softApConfig.SSID);
+ XmlUtil.writeNextValue(out, XML_TAG_BAND, softApConfig.apBand);
+ XmlUtil.writeNextValue(out, XML_TAG_CHANNEL, softApConfig.apChannel);
+ XmlUtil.writeNextValue(out, XML_TAG_HIDDEN_SSID, softApConfig.hiddenSSID);
+ XmlUtil.writeNextValue(
+ out, XML_TAG_ALLOWED_KEY_MGMT,
+ softApConfig.allowedKeyManagement.toByteArray());
+ XmlUtil.writeNextValue(out, XML_TAG_PRE_SHARED_KEY, softApConfig.preSharedKey);
+ }
+ }
+
+ @Override
+ public void deserializeData(XmlPullParser in, int outerTagDepth,
+ @WifiConfigStore.Version int version,
+ @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)
+ throws XmlPullParserException, IOException {
+ // Ignore empty reads.
+ if (in == null) {
+ return;
+ }
+ WifiConfiguration softApConfig = new WifiConfiguration();
+ while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) {
+ String[] valueName = new String[1];
+ Object value = XmlUtil.readCurrentValue(in, valueName);
+ if (TextUtils.isEmpty(valueName[0])) {
+ throw new XmlPullParserException("Missing value name");
+ }
+ switch (valueName[0]) {
+ case XML_TAG_SSID:
+ softApConfig.SSID = (String) value;
+ break;
+ case XML_TAG_BAND:
+ softApConfig.apBand = (int) value;
+ break;
+ case XML_TAG_CHANNEL:
+ softApConfig.apChannel = (int) value;
+ break;
+ case XML_TAG_HIDDEN_SSID:
+ softApConfig.hiddenSSID = (boolean) value;
+ break;
+ case XML_TAG_ALLOWED_KEY_MGMT:
+ byte[] allowedKeyMgmt = (byte[]) value;
+ softApConfig.allowedKeyManagement = BitSet.valueOf(allowedKeyMgmt);
+ break;
+ case XML_TAG_PRE_SHARED_KEY:
+ softApConfig.preSharedKey = (String) value;
+ break;
+ default:
+ Log.w(TAG, "Ignoring unknown value name " + valueName[0]);
+ break;
+ }
+ }
+ // We should at-least have SSID restored from store.
+ if (softApConfig.SSID == null) {
+ Log.e(TAG, "Failed to parse SSID");
+ return;
+ }
+ mDataSource.fromDeserialized(softApConfig);
+ }
+
+ @Override
+ public void resetData() {
+ mDataSource.reset();
+ }
+
+ @Override
+ public boolean hasNewDataToSerialize() {
+ return mDataSource.hasNewDataToSerialize();
+ }
+
+ @Override
+ public String getName() {
+ return XML_TAG_SECTION_HEADER_SOFTAP;
+ }
+
+ @Override
+ public @WifiConfigStore.StoreFileId int getStoreFileId() {
+ return WifiConfigStore.STORE_FILE_SHARED_SOFTAP; // Shared softap store.
+ }
+}
diff --git a/service/java/com/android/server/wifi/WifiApConfigStore.java b/service/java/com/android/server/wifi/WifiApConfigStore.java
index 7cb7a4cef..48ad9b1c0 100644
--- a/service/java/com/android/server/wifi/WifiApConfigStore.java
+++ b/service/java/com/android/server/wifi/WifiApConfigStore.java
@@ -39,11 +39,10 @@ import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.wifi.R;
import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
import java.io.DataInputStream;
-import java.io.DataOutputStream;
+import java.io.File;
import java.io.FileInputStream;
-import java.io.FileOutputStream;
+import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
@@ -64,10 +63,13 @@ public class WifiApConfigStore {
private static final String TAG = "WifiApConfigStore";
- private static final String DEFAULT_AP_CONFIG_FILE =
+ // Note: This is the legacy Softap config file. This is only used for migrating data out
+ // of this file on first reboot.
+ private static final String LEGACY_AP_CONFIG_FILE =
Environment.getDataDirectory() + "/misc/wifi/softap.conf";
- private static final int AP_CONFIG_FILE_VERSION = 3;
+ @VisibleForTesting
+ public static final int AP_CONFIG_FILE_VERSION = 3;
private static final int RAND_SSID_INT_MIN = 1000;
private static final int RAND_SSID_INT_MAX = 9999;
@@ -84,24 +86,57 @@ public class WifiApConfigStore {
@VisibleForTesting
static final int AP_CHANNEL_DEFAULT = 0;
- private WifiConfiguration mWifiApConfig = null;
+ private WifiConfiguration mPersistentWifiApConfig = null;
private ArrayList<Integer> mAllowed2GChannel = null;
private final Context mContext;
private final WifiInjector mWifiInjector;
private final Handler mHandler;
- private final String mApConfigFile;
private final BackupManagerProxy mBackupManagerProxy;
private final FrameworkFacade mFrameworkFacade;
private final MacAddressUtil mMacAddressUtil;
private final Mac mMac;
+ private final WifiConfigStore mWifiConfigStore;
+ private final WifiConfigManager mWifiConfigManager;
private boolean mRequiresApBandConversion = false;
+ private boolean mHasNewDataToSerialize = false;
+
+ /**
+ * Module to interact with the wifi config store.
+ */
+ private class SoftApStoreDataSource implements SoftApStoreData.DataSource {
+
+ public WifiConfiguration toSerialize() {
+ mHasNewDataToSerialize = false;
+ return mPersistentWifiApConfig;
+ }
+
+ public void fromDeserialized(WifiConfiguration config) {
+ mPersistentWifiApConfig = new WifiConfiguration(config);
+ }
+
+ public void reset() {
+ if (mPersistentWifiApConfig != null) {
+ // Note: Reset is invoked when WifiConfigStore.read() is invoked on boot completed.
+ // If we had migrated data from the legacy store before that (which is most likely
+ // true because we read the legacy file in the constructor here, whereas
+ // WifiConfigStore.read() is only triggered on boot completed), trigger a write to
+ // persist the migrated data.
+ mHandler.post(() -> mWifiConfigManager.saveToStore(true));
+ }
+ }
+
+ public boolean hasNewDataToSerialize() {
+ return mHasNewDataToSerialize;
+ }
+ }
WifiApConfigStore(Context context, WifiInjector wifiInjector, Handler handler,
- BackupManagerProxy backupManagerProxy, FrameworkFacade frameworkFacade) {
- this(context, wifiInjector, handler, backupManagerProxy, frameworkFacade,
- DEFAULT_AP_CONFIG_FILE);
+ BackupManagerProxy backupManagerProxy, FrameworkFacade frameworkFacade,
+ WifiConfigStore wifiConfigStore, WifiConfigManager wifiConfigManager) {
+ this(context, wifiInjector, handler, backupManagerProxy, frameworkFacade, wifiConfigStore,
+ wifiConfigManager, LEGACY_AP_CONFIG_FILE);
}
WifiApConfigStore(Context context,
@@ -109,13 +144,16 @@ public class WifiApConfigStore {
Handler handler,
BackupManagerProxy backupManagerProxy,
FrameworkFacade frameworkFacade,
+ WifiConfigStore wifiConfigStore,
+ WifiConfigManager wifiConfigManager,
String apConfigFile) {
mContext = context;
mWifiInjector = wifiInjector;
mHandler = handler;
mBackupManagerProxy = backupManagerProxy;
mFrameworkFacade = frameworkFacade;
- mApConfigFile = apConfigFile;
+ mWifiConfigStore = wifiConfigStore;
+ mWifiConfigManager = wifiConfigManager;
String ap2GChannelListStr = mContext.getResources().getString(
R.string.config_wifi_framework_sap_2G_channel_list);
@@ -132,17 +170,27 @@ public class WifiApConfigStore {
mRequiresApBandConversion = mContext.getResources().getBoolean(
R.bool.config_wifi_convert_apband_5ghz_to_any);
- /* Load AP configuration from persistent storage. */
- mWifiApConfig = loadApConfiguration(mApConfigFile);
- if (mWifiApConfig == null) {
- /* Use default configuration. */
- Log.d(TAG, "Fallback to use default AP configuration");
- mWifiApConfig = getDefaultApConfiguration();
-
- /* Save the default configuration to persistent storage. */
- writeApConfiguration(mApConfigFile, mWifiApConfig);
+ // One time migration from legacy config store.
+ try {
+ File file = new File(apConfigFile);
+ FileInputStream fis = new FileInputStream(apConfigFile);
+ /* Load AP configuration from persistent storage. */
+ WifiConfiguration config = loadApConfigurationFromLegacyFile(fis);
+ if (config != null) {
+ // Persist in the new store.
+ persistConfigAndTriggerBackupManagerProxy(config);
+ Log.i(TAG, "Migrated data out of legacy store file " + apConfigFile);
+ // delete the legacy file.
+ file.delete();
+ }
+ } catch (FileNotFoundException e) {
+ // Expected on further reboots after the first reboot.
}
+ // Register store data listener
+ mWifiConfigStore.registerStoreData(
+ mWifiInjector.makeSoftApStoreData(new SoftApStoreDataSource()));
+
IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_HOTSPOT_CONFIG_USER_TAPPED_CONTENT);
mContext.registerReceiver(
@@ -176,13 +224,18 @@ public class WifiApConfigStore {
* Return the current soft access point configuration.
*/
public synchronized WifiConfiguration getApConfiguration() {
- WifiConfiguration config = sanitizePersistentApConfig(mWifiApConfig);
- if (mWifiApConfig != config) {
+ if (mPersistentWifiApConfig == null) {
+ /* Use default configuration. */
+ Log.d(TAG, "Fallback to use default AP configuration");
+ persistConfigAndTriggerBackupManagerProxy(getDefaultApConfiguration());
+ }
+ WifiConfiguration sanitizedPersistentconfig =
+ sanitizePersistentApConfig(mPersistentWifiApConfig);
+ if (mPersistentWifiApConfig != sanitizedPersistentconfig) {
Log.d(TAG, "persisted config was converted, need to resave it");
- mWifiApConfig = config;
- persistConfigAndTriggerBackupManagerProxy(mWifiApConfig);
+ persistConfigAndTriggerBackupManagerProxy(sanitizedPersistentconfig);
}
- return mWifiApConfig;
+ return mPersistentWifiApConfig;
}
/**
@@ -193,11 +246,11 @@ public class WifiApConfigStore {
*/
public synchronized void setApConfiguration(WifiConfiguration config) {
if (config == null) {
- mWifiApConfig = getDefaultApConfiguration();
+ config = getDefaultApConfiguration();
} else {
- mWifiApConfig = sanitizePersistentApConfig(config);
+ config = sanitizePersistentApConfig(config);
}
- persistConfigAndTriggerBackupManagerProxy(mWifiApConfig);
+ persistConfigAndTriggerBackupManagerProxy(config);
}
public ArrayList<Integer> getAllowed2GChannel() {
@@ -280,21 +333,22 @@ public class WifiApConfigStore {
}
private void persistConfigAndTriggerBackupManagerProxy(WifiConfiguration config) {
- writeApConfiguration(mApConfigFile, mWifiApConfig);
- // Stage the backup of the SettingsProvider package which backs this up
+ mPersistentWifiApConfig = config;
+ mHasNewDataToSerialize = true;
+ mWifiConfigManager.saveToStore(true);
mBackupManagerProxy.notifyDataChanged();
}
/**
- * Load AP configuration from persistent storage.
+ * Load AP configuration from legacy persistent storage.
+ * Note: This is deprecated and only used for migrating data once on reboot.
*/
- private static WifiConfiguration loadApConfiguration(final String filename) {
+ private static WifiConfiguration loadApConfigurationFromLegacyFile(FileInputStream fis) {
WifiConfiguration config = null;
DataInputStream in = null;
try {
config = new WifiConfiguration();
- in = new DataInputStream(
- new BufferedInputStream(new FileInputStream(filename)));
+ in = new DataInputStream(new BufferedInputStream(fis));
int version = in.readInt();
if (version < 1 || version > AP_CONFIG_FILE_VERSION) {
@@ -333,28 +387,6 @@ public class WifiApConfigStore {
}
/**
- * Write AP configuration to persistent storage.
- */
- private static void writeApConfiguration(final String filename,
- final WifiConfiguration config) {
- try (DataOutputStream out = new DataOutputStream(new BufferedOutputStream(
- new FileOutputStream(filename)))) {
- out.writeInt(AP_CONFIG_FILE_VERSION);
- out.writeUTF(config.SSID);
- out.writeInt(config.apBand);
- out.writeInt(config.apChannel);
- out.writeBoolean(config.hiddenSSID);
- int authType = config.getAuthType();
- out.writeInt(authType);
- if (authType != KeyMgmt.NONE) {
- out.writeUTF(config.preSharedKey);
- }
- } catch (IOException e) {
- Log.e(TAG, "Error writing hotspot configuration" + e);
- }
- }
-
- /**
* Generate a default WPA2 based configuration with a random password.
* We are changing the Wifi Ap configuration storage from secure settings to a
* flat file accessible only by the system. A WPA2 based default configuration
diff --git a/service/java/com/android/server/wifi/WifiConfigStore.java b/service/java/com/android/server/wifi/WifiConfigStore.java
index 7696d73b4..cff7b7fe6 100644
--- a/service/java/com/android/server/wifi/WifiConfigStore.java
+++ b/service/java/com/android/server/wifi/WifiConfigStore.java
@@ -81,16 +81,21 @@ public class WifiConfigStore {
*/
public static final int STORE_FILE_SHARED_GENERAL = 0;
/**
+ * Config store file for softap shared store file.
+ */
+ public static final int STORE_FILE_SHARED_SOFTAP = 1;
+ /**
* Config store file for general user store file.
*/
- public static final int STORE_FILE_USER_GENERAL = 1;
+ public static final int STORE_FILE_USER_GENERAL = 2;
/**
* Config store file for network suggestions user store file.
*/
- public static final int STORE_FILE_USER_NETWORK_SUGGESTIONS = 2;
+ public static final int STORE_FILE_USER_NETWORK_SUGGESTIONS = 3;
@IntDef(prefix = { "STORE_FILE_" }, value = {
STORE_FILE_SHARED_GENERAL,
+ STORE_FILE_SHARED_SOFTAP,
STORE_FILE_USER_GENERAL,
STORE_FILE_USER_NETWORK_SUGGESTIONS
})
@@ -153,6 +158,10 @@ public class WifiConfigStore {
*/
private static final String STORE_FILE_NAME_SHARED_GENERAL = "WifiConfigStore.xml";
/**
+ * Config store file name for SoftAp shared store file.
+ */
+ private static final String STORE_FILE_NAME_SHARED_SOFTAP = "WifiConfigStoreSoftAp.xml";
+ /**
* Config store file name for general user store file.
*/
private static final String STORE_FILE_NAME_USER_GENERAL = "WifiConfigStore.xml";
@@ -167,6 +176,7 @@ public class WifiConfigStore {
private static final SparseArray<String> STORE_ID_TO_FILE_NAME =
new SparseArray<String>() {{
put(STORE_FILE_SHARED_GENERAL, STORE_FILE_NAME_SHARED_GENERAL);
+ put(STORE_FILE_SHARED_SOFTAP, STORE_FILE_NAME_SHARED_SOFTAP);
put(STORE_FILE_USER_GENERAL, STORE_FILE_NAME_USER_GENERAL);
put(STORE_FILE_USER_NETWORK_SUGGESTIONS, STORE_FILE_NAME_USER_NETWORK_SUGGESTIONS);
}};
@@ -184,10 +194,10 @@ public class WifiConfigStore {
private final Clock mClock;
private final WifiMetrics mWifiMetrics;
/**
- * Shared config store file instance. There is 1 shared store file:
- * {@link #STORE_FILE_NAME_SHARED_GENERAL}.
+ * Shared config store file instance. There are 2 shared store files:
+ * {@link #STORE_FILE_NAME_SHARED_GENERAL} & {@link #STORE_FILE_NAME_SHARED_SOFTAP}.
*/
- private StoreFile mSharedStore;
+ private final List<StoreFile> mSharedStores;
/**
* User specific store file instances. There are 2 user store files:
* {@link #STORE_FILE_NAME_USER_GENERAL} & {@link #STORE_FILE_NAME_USER_NETWORK_SUGGESTIONS}.
@@ -228,11 +238,12 @@ public class WifiConfigStore {
* @param handler handler instance to post alarm timeouts to.
* @param clock clock instance to retrieve timestamps for alarms.
* @param wifiMetrics Metrics instance.
- * @param sharedStore StoreFile instance pointing to the shared store file. This should
- * be retrieved using {@link #createSharedFile()} method.
+ * @param sharedStores List of {@link StoreFile} instances pointing to the shared store files.
+ * This should be retrieved using {@link #createSharedFiles(boolean)}
+ * method.
*/
public WifiConfigStore(Context context, Handler handler, Clock clock, WifiMetrics wifiMetrics,
- StoreFile sharedStore) {
+ List<StoreFile> sharedStores) {
mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
mEventHandler = handler;
@@ -241,7 +252,7 @@ public class WifiConfigStore {
mStoreDataList = new ArrayList<>();
// Initialize the store files.
- mSharedStore = sharedStore;
+ mSharedStores = sharedStores;
// The user store is initialized to null, this will be set when the user unlocks and
// CE storage is accessible via |switchUserStoresAndRead|.
mUserStores = null;
@@ -250,7 +261,8 @@ public class WifiConfigStore {
/**
* Set the user store files.
* (Useful for mocking in unit tests).
- * @param userStores List of {@link StoreFile} created using {@link #createUserFiles(int)}.
+ * @param userStores List of {@link StoreFile} created using
+ * {@link #createUserFiles(int, boolean)}.
*/
public void setUserStores(@NonNull List<StoreFile> userStores) {
Preconditions.checkNotNull(userStores);
@@ -307,14 +319,29 @@ public class WifiConfigStore {
return new StoreFile(file, fileId, encryptionUtil);
}
+ private static @Nullable List<StoreFile> createFiles(File storeBaseDir,
+ List<Integer> storeFileIds, boolean shouldEncryptCredentials) {
+ List<StoreFile> storeFiles = new ArrayList<>();
+ for (int fileId : storeFileIds) {
+ StoreFile storeFile = createFile(storeBaseDir, fileId, shouldEncryptCredentials);
+ if (storeFile == null) {
+ return null;
+ }
+ storeFiles.add(storeFile);
+ }
+ return storeFiles;
+ }
+
/**
* Create a new instance of the shared store file.
*
* @param shouldEncryptCredentials Whether to encrypt credentials or not.
* @return new instance of the store file or null if the directory cannot be created.
*/
- public static @Nullable StoreFile createSharedFile(boolean shouldEncryptCredentials) {
- return createFile(Environment.getDataMiscDirectory(), STORE_FILE_SHARED_GENERAL,
+ public static @NonNull List<StoreFile> createSharedFiles(boolean shouldEncryptCredentials) {
+ return createFiles(
+ Environment.getDataMiscDirectory(),
+ Arrays.asList(STORE_FILE_SHARED_GENERAL, STORE_FILE_SHARED_SOFTAP),
shouldEncryptCredentials);
}
@@ -329,18 +356,10 @@ public class WifiConfigStore {
*/
public static @Nullable List<StoreFile> createUserFiles(int userId,
boolean shouldEncryptCredentials) {
- List<StoreFile> storeFiles = new ArrayList<>();
- for (int fileId : Arrays.asList(
- STORE_FILE_USER_GENERAL, STORE_FILE_USER_NETWORK_SUGGESTIONS)) {
- StoreFile storeFile =
- createFile(Environment.getDataMiscCeDirectory(userId), fileId,
- shouldEncryptCredentials);
- if (storeFile == null) {
- return null;
- }
- storeFiles.add(storeFile);
- }
- return storeFiles;
+ return createFiles(
+ Environment.getDataMiscCeDirectory(userId),
+ Arrays.asList(STORE_FILE_USER_GENERAL, STORE_FILE_USER_NETWORK_SUGGESTIONS),
+ shouldEncryptCredentials);
}
/**
@@ -351,18 +370,6 @@ public class WifiConfigStore {
}
/**
- * API to check if any of the store files are present on the device. This can be used
- * to detect if the device needs to perform data migration from legacy stores.
- *
- * @return true if any of the store file is present, false otherwise.
- */
- public boolean areStoresPresent() {
- // Checking for the shared store file existence is sufficient since this is guaranteed
- // to be present on migrated devices.
- return mSharedStore.exists();
- }
-
- /**
* Retrieve the list of {@link StoreData} instances registered for the provided
* {@link StoreFile}.
*/
@@ -395,10 +402,12 @@ public class WifiConfigStore {
boolean hasAnyNewData = false;
// Serialize the provided data and send it to the respective stores. The actual write will
// be performed later depending on the |forceSync| flag .
- if (hasNewDataToSerialize(mSharedStore)) {
- byte[] sharedDataBytes = serializeData(mSharedStore);
- mSharedStore.storeRawDataToWrite(sharedDataBytes);
- hasAnyNewData = true;
+ for (StoreFile sharedStoreFile : mSharedStores) {
+ if (hasNewDataToSerialize(sharedStoreFile)) {
+ byte[] sharedDataBytes = serializeData(sharedStoreFile);
+ sharedStoreFile.storeRawDataToWrite(sharedDataBytes);
+ hasAnyNewData = true;
+ }
}
if (mUserStores != null) {
for (StoreFile userStoreFile : mUserStores) {
@@ -489,7 +498,9 @@ public class WifiConfigStore {
stopBufferedWriteAlarm();
long writeStartTime = mClock.getElapsedSinceBootMillis();
- mSharedStore.writeBufferedRawData();
+ for (StoreFile sharedStoreFile : mSharedStores) {
+ sharedStoreFile.writeBufferedRawData();
+ }
if (mUserStores != null) {
for (StoreFile userStoreFile : mUserStores) {
userStoreFile.writeBufferedRawData();
@@ -511,7 +522,9 @@ public class WifiConfigStore {
*/
public void read() throws XmlPullParserException, IOException {
// Reset both share and user store data.
- resetStoreData(mSharedStore);
+ for (StoreFile sharedStoreFile : mSharedStores) {
+ resetStoreData(sharedStoreFile);
+ }
if (mUserStores != null) {
for (StoreFile userStoreFile : mUserStores) {
resetStoreData(userStoreFile);
@@ -519,8 +532,10 @@ public class WifiConfigStore {
}
long readStartTime = mClock.getElapsedSinceBootMillis();
- byte[] sharedDataBytes = mSharedStore.readRawData();
- deserializeData(sharedDataBytes, mSharedStore);
+ for (StoreFile sharedStoreFile : mSharedStores) {
+ byte[] sharedDataBytes = sharedStoreFile.readRawData();
+ deserializeData(sharedDataBytes, sharedStoreFile);
+ }
if (mUserStores != null) {
for (StoreFile userStoreFile : mUserStores) {
byte[] userDataBytes = userStoreFile.readRawData();
@@ -681,11 +696,13 @@ public class WifiConfigStore {
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("Dump of WifiConfigStore");
pw.println("WifiConfigStore - Store File Begin ----");
- Stream.of(Arrays.asList(mSharedStore), mUserStores)
+ Stream.of(mSharedStores, mUserStores)
.flatMap(List::stream)
.forEach((storeFile) -> {
pw.print("Name: " + storeFile.mFileName);
- pw.println(", Credentials encrypted: " + storeFile.getEncryptionUtil() != null);
+ pw.print(", File Id: " + storeFile.mFileId);
+ pw.println(", Credentials encrypted: "
+ + (storeFile.getEncryptionUtil() != null));
});
pw.println("WifiConfigStore - Store Data Begin ----");
for (StoreData storeData : mStoreDataList) {
diff --git a/service/java/com/android/server/wifi/WifiInjector.java b/service/java/com/android/server/wifi/WifiInjector.java
index a53c4ec32..683db73f6 100644
--- a/service/java/com/android/server/wifi/WifiInjector.java
+++ b/service/java/com/android/server/wifi/WifiInjector.java
@@ -241,9 +241,6 @@ public class WifiInjector {
SystemProperties.get(BOOT_DEFAULT_WIFI_COUNTRY_CODE),
mContext.getResources()
.getBoolean(R.bool.config_wifi_revert_country_code_on_cellular_loss));
- mWifiApConfigStore = new WifiApConfigStore(
- mContext,this, wifiHandler, mBackupManagerProxy, mFrameworkFacade);
-
// WifiConfigManager/Store objects and their dependencies.
KeyStore keyStore = null;
try {
@@ -254,7 +251,7 @@ public class WifiInjector {
mWifiKeyStore = new WifiKeyStore(mKeyStore);
// New config store
mWifiConfigStore = new WifiConfigStore(mContext, wifiHandler, mClock, mWifiMetrics,
- WifiConfigStore.createSharedFile(mFrameworkFacade.isNiapModeOn(mContext)));
+ WifiConfigStore.createSharedFiles(mFrameworkFacade.isNiapModeOn(mContext)));
SubscriptionManager subscriptionManager =
mContext.getSystemService(SubscriptionManager.class);
mTelephonyUtil = new TelephonyUtil(makeTelephonyManager(), subscriptionManager);
@@ -267,6 +264,11 @@ public class WifiInjector {
new DeletedEphemeralSsidsStoreData(mClock), new RandomizedMacStoreData(),
mFrameworkFacade, wifiHandler, mDeviceConfigFacade);
mWifiMetrics.setWifiConfigManager(mWifiConfigManager);
+
+ mWifiApConfigStore = new WifiApConfigStore(
+ mContext, this, wifiHandler, mBackupManagerProxy, mFrameworkFacade,
+ mWifiConfigStore, mWifiConfigManager);
+
mWifiConnectivityHelper = new WifiConnectivityHelper(mWifiNative);
mConnectivityLocalLog = new LocalLog(
mContext.getSystemService(ActivityManager.class).isLowRamDevice() ? 256 : 512);
@@ -654,6 +656,14 @@ public class WifiInjector {
return new NetworkSuggestionStoreData(dataSource);
}
+ /**
+ * Construct an instance of {@link SoftApStoreData}.
+ */
+ public SoftApStoreData makeSoftApStoreData(
+ SoftApStoreData.DataSource dataSource) {
+ return new SoftApStoreData(dataSource);
+ }
+
public WifiPermissionsUtil getWifiPermissionsUtil() {
return mWifiPermissionsUtil;
}
diff --git a/service/wifi.rc b/service/wifi.rc
index 9a04252dc..5362ee69f 100644
--- a/service/wifi.rc
+++ b/service/wifi.rc
@@ -19,6 +19,7 @@
on post-fs-data
chown network_stack network_stack /data/misc/wifi
chown network_stack network_stack /data/misc/wifi/WifiConfigStore.xml
+ chown network_stack network_stack /data/misc/wifi/WifiConfigStoreSoftAp.xml
chown network_stack network_stack /data/misc/wifi/softap.conf
on property:sys.user.0.ce_available=true
diff --git a/service/wifi_inprocess.rc b/service/wifi_inprocess.rc
index 286d18063..43e4866b5 100644
--- a/service/wifi_inprocess.rc
+++ b/service/wifi_inprocess.rc
@@ -19,6 +19,7 @@
on post-fs-data
chown system system /data/misc/wifi
chown system system /data/misc/wifi/WifiConfigStore.xml
+ chown system system /data/misc/wifi/WifiConfigStoreSoftAp.xml
chown system system /data/misc/wifi/softap.conf
on property:sys.user.0.ce_available=true
diff --git a/tests/wifitests/Android.bp b/tests/wifitests/Android.bp
index 3bbbc46c2..341ab0982 100644
--- a/tests/wifitests/Android.bp
+++ b/tests/wifitests/Android.bp
@@ -250,6 +250,7 @@ android_test {
"com.android.server.wifi.SoftApManager",
"com.android.server.wifi.SoftApManager.*",
"com.android.server.wifi.SoftApModeConfiguration",
+ "com.android.server.wifi.SoftApStoreData",
"com.android.server.wifi.SsidSetStoreData",
"com.android.server.wifi.SsidSetStoreData.*",
"com.android.server.wifi.StateChangeResult",
diff --git a/tests/wifitests/src/com/android/server/wifi/SoftApStoreDataTest.java b/tests/wifitests/src/com/android/server/wifi/SoftApStoreDataTest.java
new file mode 100644
index 000000000..577767c16
--- /dev/null
+++ b/tests/wifitests/src/com/android/server/wifi/SoftApStoreDataTest.java
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wifi;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.net.wifi.WifiConfiguration;
+import android.util.Xml;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.util.FastXmlSerializer;
+import com.android.server.wifi.util.WifiConfigStoreEncryptionUtil;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.nio.charset.StandardCharsets;
+
+/**
+ * Unit tests for {@link com.android.server.wifi.SoftApStoreData}.
+ */
+@SmallTest
+public class SoftApStoreDataTest extends WifiBaseTest {
+ private static final String TEST_SSID = "SSID";
+ private static final String TEST_PRESHARED_KEY = "Test";
+ private static final boolean TEST_HIDDEN = false;
+ private static final int TEST_BAND = WifiConfiguration.AP_BAND_ANY;
+ private static final int TEST_CHANNEL = 0;
+
+ private static final String TEST_SOFTAP_CONFIG_XML_STRING =
+ "<string name=\"SSID\">" + TEST_SSID + "</string>\n"
+ + "<int name=\"Band\" value=\"" + TEST_BAND + "\" />\n"
+ + "<int name=\"Channel\" value=\"" + TEST_CHANNEL + "\" />\n"
+ + "<boolean name=\"HiddenSSID\" value=\"" + TEST_HIDDEN + "\" />\n"
+ + "<byte-array name=\"AllowedKeyMgmt\" num=\"1\">02</byte-array>\n"
+ + "<string name=\"PreSharedKey\">" + TEST_PRESHARED_KEY + "</string>\n";
+
+ @Mock SoftApStoreData.DataSource mDataSource;
+ SoftApStoreData mSoftApStoreData;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ mSoftApStoreData = new SoftApStoreData(mDataSource);
+ }
+
+ /**
+ * Helper function for serializing configuration data to a XML block.
+ *
+ * @return byte[] of the XML data
+ * @throws Exception
+ */
+ private byte[] serializeData() throws Exception {
+ final XmlSerializer out = new FastXmlSerializer();
+ final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ out.setOutput(outputStream, StandardCharsets.UTF_8.name());
+ mSoftApStoreData.serializeData(out, mock(WifiConfigStoreEncryptionUtil.class));
+ out.flush();
+ return outputStream.toByteArray();
+ }
+
+ /**
+ * Helper function for parsing configuration data from a XML block.
+ *
+ * @param data XML data to parse from
+ * @throws Exception
+ */
+ private void deserializeData(byte[] data) throws Exception {
+ final XmlPullParser in = Xml.newPullParser();
+ final ByteArrayInputStream inputStream = new ByteArrayInputStream(data);
+ in.setInput(inputStream, StandardCharsets.UTF_8.name());
+ mSoftApStoreData.deserializeData(in, in.getDepth(),
+ WifiConfigStore.ENCRYPT_CREDENTIALS_CONFIG_STORE_DATA_VERSION,
+ mock(WifiConfigStoreEncryptionUtil.class));
+ }
+
+ /**
+ * Verify that parsing an empty data doesn't cause any crash and no configuration should
+ * be deserialized.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void deserializeEmptyStoreData() throws Exception {
+ deserializeData(new byte[0]);
+ verify(mDataSource, never()).fromDeserialized(any());
+ }
+
+ /**
+ * Verify that SoftApStoreData is written to
+ * {@link WifiConfigStore#STORE_FILE_SHARED_SOFTAP}.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void getUserStoreFileId() throws Exception {
+ assertEquals(WifiConfigStore.STORE_FILE_SHARED_SOFTAP,
+ mSoftApStoreData.getStoreFileId());
+ }
+
+ /**
+ * Verify that the store data is serialized correctly, matches the predefined test XML data.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void serializeSoftAp() throws Exception {
+ WifiConfiguration softApConfig = new WifiConfiguration();
+ softApConfig.SSID = TEST_SSID;
+ softApConfig.preSharedKey = TEST_PRESHARED_KEY;
+ softApConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ softApConfig.apBand = TEST_BAND;
+ softApConfig.apChannel = TEST_CHANNEL;
+
+ when(mDataSource.toSerialize()).thenReturn(softApConfig);
+ byte[] actualData = serializeData();
+ assertEquals(TEST_SOFTAP_CONFIG_XML_STRING, new String(actualData));
+ }
+
+ /**
+ * Verify that the store data is deserialized correctly using the predefined test XML data.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void deserializeSoftAp() throws Exception {
+ deserializeData(TEST_SOFTAP_CONFIG_XML_STRING.getBytes());
+
+ ArgumentCaptor<WifiConfiguration> softapConfigCaptor =
+ ArgumentCaptor.forClass(WifiConfiguration.class);
+ verify(mDataSource).fromDeserialized(softapConfigCaptor.capture());
+ WifiConfiguration softApConfig = softapConfigCaptor.getValue();
+ assertNotNull(softApConfig);
+ assertEquals(softApConfig.SSID, TEST_SSID);
+ assertEquals(softApConfig.preSharedKey, TEST_PRESHARED_KEY);
+ assertTrue(softApConfig.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_PSK));
+ assertEquals(softApConfig.hiddenSSID, TEST_HIDDEN);
+ assertEquals(softApConfig.apBand, TEST_BAND);
+ assertEquals(softApConfig.apChannel, TEST_CHANNEL);
+ }
+
+ /**
+ * Verify that the store data is serialized/deserialized correctly.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void serializeDeserializeSoftAp() throws Exception {
+ WifiConfiguration softApConfig = new WifiConfiguration();
+ softApConfig.SSID = TEST_SSID;
+ softApConfig.preSharedKey = TEST_PRESHARED_KEY;
+ softApConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ softApConfig.apBand = TEST_BAND;
+ softApConfig.apChannel = TEST_CHANNEL;
+
+ // Serialize first.
+ when(mDataSource.toSerialize()).thenReturn(softApConfig);
+ byte[] serializedData = serializeData();
+
+ // Now deserialize first.
+ deserializeData(serializedData);
+ ArgumentCaptor<WifiConfiguration> softapConfigCaptor =
+ ArgumentCaptor.forClass(WifiConfiguration.class);
+ verify(mDataSource).fromDeserialized(softapConfigCaptor.capture());
+ WifiConfiguration softApConfigDeserialized = softapConfigCaptor.getValue();
+ assertNotNull(softApConfigDeserialized);
+
+ assertEquals(softApConfig.SSID, softApConfigDeserialized.SSID);
+ assertEquals(softApConfig.preSharedKey, softApConfigDeserialized.preSharedKey);
+ assertEquals(softApConfig.allowedKeyManagement,
+ softApConfigDeserialized.allowedKeyManagement);
+ assertEquals(softApConfig.hiddenSSID, softApConfigDeserialized.hiddenSSID);
+ assertEquals(softApConfig.apBand, softApConfigDeserialized.apBand);
+ assertEquals(softApConfig.apChannel, softApConfigDeserialized.apChannel);
+ }
+}
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiApConfigStoreTest.java b/tests/wifitests/src/com/android/server/wifi/WifiApConfigStoreTest.java
index f150bf797..71b034a2e 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiApConfigStoreTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiApConfigStoreTest.java
@@ -21,9 +21,11 @@ import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -46,15 +48,17 @@ import androidx.test.filters.SmallTest;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.wifi.R;
-import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.io.BufferedOutputStream;
+import java.io.DataOutputStream;
import java.io.File;
-import java.lang.reflect.Method;
+import java.io.FileOutputStream;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Random;
@@ -89,30 +93,32 @@ public class WifiApConfigStoreTest extends WifiBaseTest {
@Mock private Context mContext;
@Mock private WifiInjector mWifiInjector;
+ private TestLooper mLooper;
private Handler mHandler;
@Mock private BackupManagerProxy mBackupManagerProxy;
@Mock private FrameworkFacade mFrameworkFacade;
- private File mApConfigFile;
+ @Mock private WifiConfigStore mWifiConfigStore;
+ @Mock private WifiConfigManager mWifiConfigManager;
+ private File mLegacyApConfigFile;
private Random mRandom;
private MockResources mResources;
@Mock private ApplicationInfo mMockApplInfo;
private BroadcastReceiver mBroadcastReceiver;
@Mock private NotificationManager mNotificationManager;
@Mock private MacAddressUtil mMacAddressUtil;
+ private SoftApStoreData.DataSource mDataStoreSource;
private ArrayList<Integer> mKnownGood2GChannelList;
@Before
public void setUp() throws Exception {
- mHandler = new Handler(new TestLooper().getLooper());
+ mLooper = new TestLooper();
+ mHandler = new Handler(mLooper.getLooper());
MockitoAnnotations.initMocks(this);
when(mContext.getSystemService(Context.NOTIFICATION_SERVICE))
.thenReturn(mNotificationManager);
mMockApplInfo.targetSdkVersion = Build.VERSION_CODES.P;
when(mContext.getApplicationInfo()).thenReturn(mMockApplInfo);
- /* Create a temporary file for AP config file storage. */
- mApConfigFile = File.createTempFile(TEST_AP_CONFIG_FILE_PREFIX, "");
-
/* Setup expectations for Resources to return some default settings. */
mResources = new MockResources();
mResources.setString(R.string.config_wifi_framework_sap_2G_channel_list,
@@ -139,28 +145,39 @@ public class WifiApConfigStoreTest extends WifiBaseTest {
when(mMacAddressUtil.calculatePersistentMac(any(), any())).thenReturn(TEST_RANDOMIZED_MAC);
}
- @After
- public void cleanUp() {
- /* Remove the temporary AP config file. */
- mApConfigFile.delete();
- }
-
/**
* Helper method to create and verify actions for the ApConfigStore used in the following tests.
*/
- private WifiApConfigStore createWifiApConfigStore() {
- WifiApConfigStore store = new WifiApConfigStore(
- mContext, mWifiInjector, mHandler, mBackupManagerProxy, mFrameworkFacade,
- mApConfigFile.getPath());
+ private WifiApConfigStore createWifiApConfigStore(String legacyFilePath) {
+ WifiApConfigStore store;
+ if (legacyFilePath == null) {
+ store = new WifiApConfigStore(
+ mContext, mWifiInjector, mHandler, mBackupManagerProxy, mFrameworkFacade,
+ mWifiConfigStore, mWifiConfigManager);
+ } else {
+ store = new WifiApConfigStore(
+ mContext, mWifiInjector, mHandler, mBackupManagerProxy, mFrameworkFacade,
+ mWifiConfigStore, mWifiConfigManager, legacyFilePath);
+ }
ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor =
ArgumentCaptor.forClass(BroadcastReceiver.class);
verify(mContext).registerReceiver(broadcastReceiverCaptor.capture(), any(), any(), any());
mBroadcastReceiver = broadcastReceiverCaptor.getValue();
+ verify(mWifiConfigStore).registerStoreData(any());
+ ArgumentCaptor<SoftApStoreData.DataSource> dataStoreSourceArgumentCaptor =
+ ArgumentCaptor.forClass(SoftApStoreData.DataSource.class);
+ verify(mWifiInjector).makeSoftApStoreData(dataStoreSourceArgumentCaptor.capture());
+ mDataStoreSource = dataStoreSourceArgumentCaptor.getValue();
+
return store;
}
+ private WifiApConfigStore createWifiApConfigStore() {
+ return createWifiApConfigStore(null);
+ }
+
/**
* Generate a WifiConfiguration based on the specified parameters.
*/
@@ -177,16 +194,28 @@ public class WifiApConfigStoreTest extends WifiBaseTest {
return config;
}
- private void writeApConfigFile(WifiConfiguration config) throws Exception {
- Method m = WifiApConfigStore.class.getDeclaredMethod(
- "writeApConfiguration", String.class, WifiConfiguration.class);
- m.setAccessible(true);
- m.invoke(null, mApConfigFile.getPath(), config);
+ private void writeLegacyApConfigFile(WifiConfiguration config) throws Exception {
+ try (DataOutputStream out = new DataOutputStream(new BufferedOutputStream(
+ new FileOutputStream(mLegacyApConfigFile)))) {
+ out.writeInt(WifiApConfigStore.AP_CONFIG_FILE_VERSION);
+ out.writeUTF(config.SSID);
+ out.writeInt(config.apBand);
+ out.writeInt(config.apChannel);
+ out.writeBoolean(config.hiddenSSID);
+ int authType = config.getAuthType();
+ out.writeInt(authType);
+ if (authType != KeyMgmt.NONE) {
+ out.writeUTF(config.preSharedKey);
+ }
+ } catch (IOException e) {
+ fail("Error writing hotspot configuration" + e);
+ }
}
private void verifyApConfig(WifiConfiguration config1, WifiConfiguration config2) {
assertEquals(config1.SSID, config2.SSID);
assertEquals(config1.preSharedKey, config2.preSharedKey);
+ assertEquals(config1.allowedKeyManagement, config2.allowedKeyManagement);
assertEquals(config1.getAuthType(), config2.getAuthType());
assertEquals(config1.apBand, config2.apBand);
assertEquals(config1.apChannel, config2.apChannel);
@@ -224,18 +253,17 @@ public class WifiApConfigStoreTest extends WifiBaseTest {
*/
@Test
public void initWithDefaultConfiguration() throws Exception {
- WifiApConfigStore store = new WifiApConfigStore(
- mContext, mWifiInjector, mHandler, mBackupManagerProxy, mFrameworkFacade,
- mApConfigFile.getPath());
+ WifiApConfigStore store = createWifiApConfigStore();
verifyDefaultApConfig(store.getApConfiguration(), TEST_DEFAULT_AP_SSID);
+ verify(mWifiConfigManager).saveToStore(true);
}
/**
* Verify WifiApConfigStore can correctly load the existing configuration
- * from the config file.
+ * from the legacy config file and migrate it to the new config store.
*/
@Test
- public void initWithExistingConfiguration() throws Exception {
+ public void initWithExistingConfigurationInLegacyFile() throws Exception {
WifiConfiguration expectedConfig = setupApConfig(
"ConfiguredAP", /* SSID */
"randomKey", /* preshared key */
@@ -243,11 +271,25 @@ public class WifiApConfigStoreTest extends WifiBaseTest {
1, /* AP band (5GHz) */
40, /* AP channel */
true /* Hidden SSID */);
- writeApConfigFile(expectedConfig);
- WifiApConfigStore store = new WifiApConfigStore(
- mContext, mWifiInjector, mHandler, mBackupManagerProxy, mFrameworkFacade,
- mApConfigFile.getPath());
+ /* Create a temporary file for AP config file storage. */
+ mLegacyApConfigFile = File.createTempFile(TEST_AP_CONFIG_FILE_PREFIX, "");
+
+ writeLegacyApConfigFile(expectedConfig);
+ WifiApConfigStore store = createWifiApConfigStore(mLegacyApConfigFile.getPath());
+ verify(mWifiConfigManager).saveToStore(true);
+ verify(mBackupManagerProxy).notifyDataChanged();
verifyApConfig(expectedConfig, store.getApConfiguration());
+ verifyApConfig(expectedConfig, mDataStoreSource.toSerialize());
+ // Simulate the config store read to trigger the write to new config store.
+ mDataStoreSource.reset();
+ mLooper.dispatchAll();
+ // Triggers write twice:
+ // a) On reading the legacy file (new config store not ready yet)
+ // b) When the new config store is ready.
+ verify(mWifiConfigManager, times(2)).saveToStore(true);
+
+ // The temporary legacy AP config file should be removed after migration.
+ assertFalse(mLegacyApConfigFile.exists());
}
/**
@@ -265,14 +307,14 @@ public class WifiApConfigStoreTest extends WifiBaseTest {
1, /* AP band (5GHz) */
40, /* AP channel */
true /* Hidden SSID */);
- writeApConfigFile(expectedConfig);
- WifiApConfigStore store = new WifiApConfigStore(
- mContext, mWifiInjector, mHandler, mBackupManagerProxy, mFrameworkFacade,
- mApConfigFile.getPath());
+ WifiApConfigStore store = createWifiApConfigStore();
+ mDataStoreSource.fromDeserialized(expectedConfig);
verifyApConfig(expectedConfig, store.getApConfiguration());
store.setApConfiguration(null);
verifyDefaultApConfig(store.getApConfiguration(), TEST_DEFAULT_AP_SSID);
+ verifyDefaultApConfig(mDataStoreSource.toSerialize(), TEST_DEFAULT_AP_SSID);
+ verify(mWifiConfigManager).saveToStore(true);
verify(mBackupManagerProxy).notifyDataChanged();
}
@@ -282,10 +324,10 @@ public class WifiApConfigStoreTest extends WifiBaseTest {
@Test
public void updateApConfiguration() throws Exception {
/* Initialize WifiApConfigStore with default configuration. */
- WifiApConfigStore store = new WifiApConfigStore(
- mContext, mWifiInjector, mHandler, mBackupManagerProxy, mFrameworkFacade,
- mApConfigFile.getPath());
+ WifiApConfigStore store = createWifiApConfigStore();
+
verifyDefaultApConfig(store.getApConfiguration(), TEST_DEFAULT_AP_SSID);
+ verify(mWifiConfigManager).saveToStore(true);
/* Update with a valid configuration. */
WifiConfiguration expectedConfig = setupApConfig(
@@ -297,7 +339,9 @@ public class WifiApConfigStoreTest extends WifiBaseTest {
true /* Hidden SSID */);
store.setApConfiguration(expectedConfig);
verifyApConfig(expectedConfig, store.getApConfiguration());
- verify(mBackupManagerProxy).notifyDataChanged();
+ verifyApConfig(expectedConfig, mDataStoreSource.toSerialize());
+ verify(mWifiConfigManager, times(2)).saveToStore(true);
+ verify(mBackupManagerProxy, times(2)).notifyDataChanged();
}
/**
@@ -308,10 +352,9 @@ public class WifiApConfigStoreTest extends WifiBaseTest {
@Test
public void convertSingleModeDeviceAnyTo5Ghz() throws Exception {
/* Initialize WifiApConfigStore with default configuration. */
- WifiApConfigStore store = new WifiApConfigStore(
- mContext, mWifiInjector, mHandler, mBackupManagerProxy, mFrameworkFacade,
- mApConfigFile.getPath());
+ WifiApConfigStore store = createWifiApConfigStore();
verifyDefaultApConfig(store.getApConfiguration(), TEST_DEFAULT_AP_SSID);
+ verify(mWifiConfigManager).saveToStore(true);
/* Update with a valid configuration. */
WifiConfiguration providedConfig = setupApConfig(
@@ -331,7 +374,9 @@ public class WifiApConfigStoreTest extends WifiBaseTest {
false /* Hidden SSID */);
store.setApConfiguration(providedConfig);
verifyApConfig(expectedConfig, store.getApConfiguration());
- verify(mBackupManagerProxy).notifyDataChanged();
+ verifyApConfig(expectedConfig, mDataStoreSource.toSerialize());
+ verify(mWifiConfigManager, times(2)).saveToStore(true);
+ verify(mBackupManagerProxy, times(2)).notifyDataChanged();
}
/**
@@ -342,10 +387,9 @@ public class WifiApConfigStoreTest extends WifiBaseTest {
@Test
public void singleModeDevice5GhzNotConverted() throws Exception {
/* Initialize WifiApConfigStore with default configuration. */
- WifiApConfigStore store = new WifiApConfigStore(
- mContext, mWifiInjector, mHandler, mBackupManagerProxy, mFrameworkFacade,
- mApConfigFile.getPath());
+ WifiApConfigStore store = createWifiApConfigStore();
verifyDefaultApConfig(store.getApConfiguration(), TEST_DEFAULT_AP_SSID);
+ verify(mWifiConfigManager).saveToStore(true);
/* Update with a valid configuration. */
WifiConfiguration expectedConfig = setupApConfig(
@@ -357,6 +401,9 @@ public class WifiApConfigStoreTest extends WifiBaseTest {
false /* Hidden SSID */);
store.setApConfiguration(expectedConfig);
verifyApConfig(expectedConfig, store.getApConfiguration());
+ verifyApConfig(expectedConfig, mDataStoreSource.toSerialize());
+ verify(mWifiConfigManager, times(2)).saveToStore(true);
+ verify(mBackupManagerProxy, times(2)).notifyDataChanged();
}
/**
@@ -369,10 +416,9 @@ public class WifiApConfigStoreTest extends WifiBaseTest {
mResources.setBoolean(R.bool.config_wifi_convert_apband_5ghz_to_any, true);
/* Initialize WifiApConfigStore with default configuration. */
- WifiApConfigStore store = new WifiApConfigStore(
- mContext, mWifiInjector, mHandler, mBackupManagerProxy, mFrameworkFacade,
- mApConfigFile.getPath());
+ WifiApConfigStore store = createWifiApConfigStore();
verifyDefaultApConfig(store.getApConfiguration(), TEST_DEFAULT_AP_SSID);
+ verify(mWifiConfigManager).saveToStore(true);
/* Update with a valid configuration. */
WifiConfiguration providedConfig = setupApConfig(
@@ -392,7 +438,9 @@ public class WifiApConfigStoreTest extends WifiBaseTest {
false /* Hidden SSID */);
store.setApConfiguration(providedConfig);
verifyApConfig(expectedConfig, store.getApConfiguration());
- verify(mBackupManagerProxy).notifyDataChanged();
+ verifyApConfig(expectedConfig, mDataStoreSource.toSerialize());
+ verify(mWifiConfigManager, times(2)).saveToStore(true);
+ verify(mBackupManagerProxy, times(2)).notifyDataChanged();
}
/**
@@ -405,10 +453,9 @@ public class WifiApConfigStoreTest extends WifiBaseTest {
mResources.setBoolean(R.bool.config_wifi_convert_apband_5ghz_to_any, true);
/* Initialize WifiApConfigStore with default configuration. */
- WifiApConfigStore store = new WifiApConfigStore(
- mContext, mWifiInjector, mHandler, mBackupManagerProxy, mFrameworkFacade,
- mApConfigFile.getPath());
+ WifiApConfigStore store = createWifiApConfigStore();
verifyDefaultApConfig(store.getApConfiguration(), TEST_DEFAULT_AP_SSID);
+ verify(mWifiConfigManager).saveToStore(true);
/* Update with a valid configuration. */
WifiConfiguration expectedConfig = setupApConfig(
@@ -419,8 +466,10 @@ public class WifiApConfigStoreTest extends WifiBaseTest {
40, /* AP channel */
false /* Hidden SSID */);
store.setApConfiguration(expectedConfig);
- verify(mBackupManagerProxy).notifyDataChanged();
verifyApConfig(expectedConfig, store.getApConfiguration());
+ verifyApConfig(expectedConfig, mDataStoreSource.toSerialize());
+ verify(mWifiConfigManager, times(2)).saveToStore(true);
+ verify(mBackupManagerProxy, times(2)).notifyDataChanged();
}
/**
@@ -445,11 +494,11 @@ public class WifiApConfigStoreTest extends WifiBaseTest {
WifiConfiguration.AP_BAND_5GHZ, /* AP band */
WifiApConfigStore.AP_CHANNEL_DEFAULT, /* AP channel */
false /* Hidden SSID */);
- writeApConfigFile(persistedConfig);
- WifiApConfigStore store = new WifiApConfigStore(
- mContext, mWifiInjector, mHandler, mBackupManagerProxy, mFrameworkFacade,
- mApConfigFile.getPath());
+ WifiApConfigStore store = createWifiApConfigStore();
+ mDataStoreSource.fromDeserialized(persistedConfig);
verifyApConfig(expectedConfig, store.getApConfiguration());
+ verifyApConfig(expectedConfig, mDataStoreSource.toSerialize());
+ verify(mWifiConfigManager).saveToStore(true);
verify(mBackupManagerProxy).notifyDataChanged();
}
@@ -468,11 +517,10 @@ public class WifiApConfigStoreTest extends WifiBaseTest {
40, /* AP channel */
false /* Hidden SSID */);
- writeApConfigFile(persistedConfig);
- WifiApConfigStore store = new WifiApConfigStore(
- mContext, mWifiInjector, mHandler, mBackupManagerProxy, mFrameworkFacade,
- mApConfigFile.getPath());
+ WifiApConfigStore store = createWifiApConfigStore();
+ mDataStoreSource.fromDeserialized(persistedConfig);
verifyApConfig(persistedConfig, store.getApConfiguration());
+ verify(mWifiConfigManager, never()).saveToStore(true);
verify(mBackupManagerProxy, never()).notifyDataChanged();
}
@@ -500,11 +548,11 @@ public class WifiApConfigStoreTest extends WifiBaseTest {
WifiApConfigStore.AP_CHANNEL_DEFAULT, /* AP channel */
false /* Hidden SSID */);
- writeApConfigFile(persistedConfig);
- WifiApConfigStore store = new WifiApConfigStore(
- mContext, mWifiInjector, mHandler, mBackupManagerProxy, mFrameworkFacade,
- mApConfigFile.getPath());
+ WifiApConfigStore store = createWifiApConfigStore();
+ mDataStoreSource.fromDeserialized(persistedConfig);
verifyApConfig(expectedConfig, store.getApConfiguration());
+ verifyApConfig(expectedConfig, mDataStoreSource.toSerialize());
+ verify(mWifiConfigManager).saveToStore(true);
verify(mBackupManagerProxy).notifyDataChanged();
}
@@ -525,11 +573,10 @@ public class WifiApConfigStoreTest extends WifiBaseTest {
40, /* AP channel */
false /* Hidden SSID */);
- writeApConfigFile(persistedConfig);
- WifiApConfigStore store = new WifiApConfigStore(
- mContext, mWifiInjector, mHandler, mBackupManagerProxy, mFrameworkFacade,
- mApConfigFile.getPath());
+ WifiApConfigStore store = createWifiApConfigStore();
+ mDataStoreSource.fromDeserialized(persistedConfig);
verifyApConfig(persistedConfig, store.getApConfiguration());
+ verify(mWifiConfigManager, never()).saveToStore(true);
verify(mBackupManagerProxy, never()).notifyDataChanged();
}
@@ -538,9 +585,7 @@ public class WifiApConfigStoreTest extends WifiBaseTest {
*/
@Test
public void getDefaultApConfigurationIsValid() {
- WifiApConfigStore store = new WifiApConfigStore(
- mContext, mWifiInjector, mHandler, mBackupManagerProxy, mFrameworkFacade,
- mApConfigFile.getPath());
+ WifiApConfigStore store = createWifiApConfigStore();
WifiConfiguration config = store.getApConfiguration();
assertTrue(WifiApConfigStore.validateApWifiConfiguration(config));
}
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java b/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java
index d48966143..edbd5cb7e 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java
@@ -213,7 +213,6 @@ public class WifiConfigManagerTest extends WifiBaseTest {
.updateNetworkKeys(any(WifiConfiguration.class), any()))
.thenReturn(true);
- when(mWifiConfigStore.areStoresPresent()).thenReturn(true);
setupStoreDataForRead(new ArrayList<>(), new ArrayList<>(), new HashMap<>());
when(mWifiPermissionsUtil.checkNetworkSettingsPermission(anyInt())).thenReturn(true);
@@ -3758,8 +3757,6 @@ public class WifiConfigManagerTest extends WifiBaseTest {
*/
@Test
public void testFreshInstallLoadFromStore() throws Exception {
- when(mWifiConfigStore.areStoresPresent()).thenReturn(false);
-
assertTrue(mWifiConfigManager.loadFromStore());
verify(mWifiConfigStore).read();
@@ -3774,8 +3771,6 @@ public class WifiConfigManagerTest extends WifiBaseTest {
*/
@Test
public void testFreshInstallLoadFromStoreAfterUserUnlock() throws Exception {
- when(mWifiConfigStore.areStoresPresent()).thenReturn(false);
-
int user1 = TEST_DEFAULT_USER;
// Unlock the user1 (default user) for the first time and ensure that we don't read the
@@ -3797,7 +3792,6 @@ public class WifiConfigManagerTest extends WifiBaseTest {
@Test
public void testHandleUserSwitchAfterFreshInstall() throws Exception {
int user2 = TEST_DEFAULT_USER + 1;
- when(mWifiConfigStore.areStoresPresent()).thenReturn(false);
assertTrue(mWifiConfigManager.loadFromStore());
verify(mWifiConfigStore).read();
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiConfigStoreTest.java b/tests/wifitests/src/com/android/server/wifi/WifiConfigStoreTest.java
index 06a246593..814dc6134 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiConfigStoreTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiConfigStoreTest.java
@@ -51,6 +51,7 @@ import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -212,7 +213,7 @@ public class WifiConfigStoreTest extends WifiBaseTest {
setupMocks();
mWifiConfigStore = new WifiConfigStore(mContext, new Handler(mLooper.getLooper()), mClock,
- mWifiMetrics, mSharedStore);
+ mWifiMetrics, Arrays.asList(mSharedStore));
// Enable verbose logging before tests.
mWifiConfigStore.enableVerboseLogging(true);
}
@@ -420,7 +421,6 @@ public class WifiConfigStoreTest extends WifiBaseTest {
// |readRawData| would return null.
mWifiConfigStore.registerStoreData(sharedStoreData);
mWifiConfigStore.registerStoreData(userStoreData);
- assertFalse(mWifiConfigStore.areStoresPresent());
mWifiConfigStore.read();
// Ensure that we got the call to deserialize empty shared data, but no user data.
@@ -450,7 +450,6 @@ public class WifiConfigStoreTest extends WifiBaseTest {
mWifiConfigStore.registerStoreData(userStoreData);
// Read both share and user config store.
mWifiConfigStore.setUserStores(mUserStores);
- assertFalse(mWifiConfigStore.areStoresPresent());
mWifiConfigStore.read();
// Ensure that we got the call to deserialize empty shared & user data.