summaryrefslogtreecommitdiff
path: root/service
diff options
context:
space:
mode:
authorRoshan Pius <rpius@google.com>2020-03-18 15:34:23 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2020-03-18 15:34:23 +0000
commite5539573fac5594bd6df5d9ec5a4fdf33c655f94 (patch)
tree93328a53412788b7e1541160f4889fbe020c8325 /service
parentcaf73afd677addbf0fc2172e8446562dfcc5db13 (diff)
parentd32c5600ac8a3b78cb5158f24a39d8a6ad996e7f (diff)
Merge "WifiConfigStore: Use new API's for migrating config store data" into rvc-dev
Diffstat (limited to 'service')
-rw-r--r--service/java/com/android/server/wifi/WifiApConfigStore.java32
-rw-r--r--service/java/com/android/server/wifi/WifiConfigStore.java188
-rw-r--r--service/java/com/android/server/wifi/util/Environment.java51
3 files changed, 160 insertions, 111 deletions
diff --git a/service/java/com/android/server/wifi/WifiApConfigStore.java b/service/java/com/android/server/wifi/WifiApConfigStore.java
index 660c99b30..e5d12822b 100644
--- a/service/java/com/android/server/wifi/WifiApConfigStore.java
+++ b/service/java/com/android/server/wifi/WifiApConfigStore.java
@@ -23,6 +23,7 @@ import android.net.MacAddress;
import android.net.util.MacAddressUtils;
import android.net.wifi.SoftApConfiguration;
import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiMigration;
import android.os.Handler;
import android.os.Process;
import android.text.TextUtils;
@@ -30,15 +31,12 @@ import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.wifi.util.ApConfigUtil;
-import com.android.server.wifi.util.Environment;
import com.android.wifi.resources.R;
import java.io.BufferedInputStream;
import java.io.DataInputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
import java.io.IOException;
+import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.Random;
@@ -122,7 +120,8 @@ public class WifiApConfigStore {
WifiConfigManager wifiConfigManager, ActiveModeWarden activeModeWarden) {
this(context, wifiInjector, handler, backupManagerProxy, wifiConfigStore,
wifiConfigManager, activeModeWarden,
- new File(Environment.getLegacyWifiSharedDirectory(), LEGACY_AP_CONFIG_FILE));
+ WifiMigration.convertAndRetrieveSharedConfigStoreFile(
+ WifiMigration.STORE_FILE_SHARED_SOFTAP));
}
WifiApConfigStore(Context context,
@@ -132,7 +131,7 @@ public class WifiApConfigStore {
WifiConfigStore wifiConfigStore,
WifiConfigManager wifiConfigManager,
ActiveModeWarden activeModeWarden,
- File apConfigFile) {
+ InputStream legacyApConfigFileStream) {
mContext = context;
mHandler = handler;
mBackupManagerProxy = backupManagerProxy;
@@ -140,20 +139,21 @@ public class WifiApConfigStore {
mActiveModeWarden = activeModeWarden;
// One time migration from legacy config store.
- try {
- File file = apConfigFile;
- FileInputStream fis = new FileInputStream(apConfigFile);
+ // TODO (b/149418926): softap migration needs to be fixed. Move the logic
+ // below to WifiMigration. This is to allow OEM's who have been supporting some new AOSP R
+ // features like blocklist/allowlist in Q and stored the data using the old key/value
+ // format.
+ if (legacyApConfigFileStream != null) {
/* Load AP configuration from persistent storage. */
- SoftApConfiguration config = loadApConfigurationFromLegacyFile(fis);
+ SoftApConfiguration config =
+ loadApConfigurationFromLegacyFile(legacyApConfigFileStream);
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();
+ Log.i(TAG, "Migrated data out of legacy store file");
+ WifiMigration.removeSharedConfigStoreFile(
+ WifiMigration.STORE_FILE_SHARED_SOFTAP);
}
- } catch (FileNotFoundException e) {
- // Expected on further reboots after the first reboot.
}
// Register store data listener
@@ -271,7 +271,7 @@ public class WifiApConfigStore {
* Load AP configuration from legacy persistent storage.
* Note: This is deprecated and only used for migrating data once on reboot.
*/
- private static SoftApConfiguration loadApConfigurationFromLegacyFile(FileInputStream fis) {
+ private static SoftApConfiguration loadApConfigurationFromLegacyFile(InputStream fis) {
SoftApConfiguration config = null;
DataInputStream in = null;
try {
diff --git a/service/java/com/android/server/wifi/WifiConfigStore.java b/service/java/com/android/server/wifi/WifiConfigStore.java
index b5c3534cc..a891b0588 100644
--- a/service/java/com/android/server/wifi/WifiConfigStore.java
+++ b/service/java/com/android/server/wifi/WifiConfigStore.java
@@ -23,7 +23,9 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.AlarmManager;
import android.content.Context;
+import android.net.wifi.WifiMigration;
import android.os.Handler;
+import android.os.UserHandle;
import android.util.AtomicFile;
import android.util.Log;
import android.util.SparseArray;
@@ -49,11 +51,11 @@ import java.io.FileDescriptor;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -288,19 +290,6 @@ public class WifiConfigStore {
return true;
}
- private static void copyLegacyStoreFileIfNeeded(File legacyStoreFile, File storeFile) {
- try {
- // If the new store file exists, nothing to copy.
- if (storeFile.exists()) return;
- // If the legacy file does not exist, nothing to copy.
- if (!legacyStoreFile.exists()) return;
- Log.d(TAG, "Copying wifi store file from " + legacyStoreFile + " to " + storeFile);
- Files.copy(legacyStoreFile.toPath(), storeFile.toPath());
- } catch (SecurityException | IOException e) {
- Log.e(TAG, "Failed to copy the legacy store file", e);
- }
- }
-
/**
* Helper method to create a store file instance for either the shared store or user store.
* Note: The method creates the store directory if not already present. This may be needed for
@@ -308,15 +297,13 @@ public class WifiConfigStore {
*
* @param storeDir Base directory under which the store file is to be stored. The store file
* will be at <storeDir>/WifiConfigStore.xml.
- * @param legacyStoreDir Base directory under which the store file was stored. The store file
- * will be at <storeDir>/WifiConfigStore.xml. This is needed to perform
- * a one time migration of the files from this folder to |storeDir|.
* @param fileId Identifier for the file. See {@link StoreFileId}.
+ * @param userHandle User handle. Meaningful only for user specific store files.
* @param shouldEncryptCredentials Whether to encrypt credentials or not.
* @return new instance of the store file or null if the directory cannot be created.
*/
- private static @Nullable StoreFile createFile(File storeDir, File legacyStoreDir,
- @StoreFileId int fileId, boolean shouldEncryptCredentials) {
+ private static @Nullable StoreFile createFile(@NonNull File storeDir,
+ @StoreFileId int fileId, UserHandle userHandle, boolean shouldEncryptCredentials) {
if (!storeDir.exists()) {
if (!storeDir.mkdir()) {
Log.w(TAG, "Could not create store directory " + storeDir);
@@ -324,24 +311,19 @@ public class WifiConfigStore {
}
}
File file = new File(storeDir, STORE_ID_TO_FILE_NAME.get(fileId));
- // Note: This performs a one time migration of the existing wifi config store files
- // from the old /data/misc/wifi & /data/misc_ce/<userId>/wifi folder to the
- // wifi apex folder.
- copyLegacyStoreFileIfNeeded(
- new File(legacyStoreDir, STORE_ID_TO_FILE_NAME.get(fileId)), file);
WifiConfigStoreEncryptionUtil encryptionUtil = null;
if (shouldEncryptCredentials) {
encryptionUtil = new WifiConfigStoreEncryptionUtil(file.getName());
}
- return new StoreFile(file, fileId, encryptionUtil);
+ return new StoreFile(file, fileId, userHandle, encryptionUtil);
}
- private static @Nullable List<StoreFile> createFiles(File storeDir, File legacyStoreDir,
- List<Integer> storeFileIds, boolean shouldEncryptCredentials) {
+ private static @Nullable List<StoreFile> createFiles(File storeDir, List<Integer> storeFileIds,
+ UserHandle userHandle, boolean shouldEncryptCredentials) {
List<StoreFile> storeFiles = new ArrayList<>();
for (int fileId : storeFileIds) {
StoreFile storeFile =
- createFile(storeDir, legacyStoreDir, fileId, shouldEncryptCredentials);
+ createFile(storeDir, fileId, userHandle, shouldEncryptCredentials);
if (storeFile == null) {
return null;
}
@@ -359,8 +341,8 @@ public class WifiConfigStore {
public static @NonNull List<StoreFile> createSharedFiles(boolean shouldEncryptCredentials) {
return createFiles(
Environment.getWifiSharedDirectory(),
- Environment.getLegacyWifiSharedDirectory(),
Arrays.asList(STORE_FILE_SHARED_GENERAL, STORE_FILE_SHARED_SOFTAP),
+ UserHandle.ALL,
shouldEncryptCredentials);
}
@@ -375,10 +357,11 @@ public class WifiConfigStore {
*/
public static @Nullable List<StoreFile> createUserFiles(int userId,
boolean shouldEncryptCredentials) {
+ UserHandle userHandle = UserHandle.of(userId);
return createFiles(
Environment.getWifiUserDirectory(userId),
- Environment.getLegacyWifiUserDirectory(userId),
Arrays.asList(STORE_FILE_USER_GENERAL, STORE_FILE_USER_NETWORK_SUGGESTIONS),
+ userHandle,
shouldEncryptCredentials);
}
@@ -536,6 +519,127 @@ public class WifiConfigStore {
}
/**
+ * Note: This is a copy of {@link AtomicFile#readFully()} modified to use the passed in
+ * {@link InputStream} which was returned using {@link AtomicFile#openRead()}.
+ */
+ private static byte[] readAtomicFileFully(InputStream stream) throws IOException {
+ try {
+ int pos = 0;
+ int avail = stream.available();
+ byte[] data = new byte[avail];
+ while (true) {
+ int amt = stream.read(data, pos, data.length - pos);
+ if (amt <= 0) {
+ return data;
+ }
+ pos += amt;
+ avail = stream.available();
+ if (avail > data.length - pos) {
+ byte[] newData = new byte[pos + avail];
+ System.arraycopy(data, 0, newData, 0, pos);
+ data = newData;
+ }
+ }
+ } finally {
+ stream.close();
+ }
+ }
+
+ /**
+ * Conversion for file id's to use in WifiMigration API surface.
+ */
+ private static Integer getMigrationStoreFileId(@StoreFileId int fileId) {
+ switch (fileId) {
+ case STORE_FILE_SHARED_GENERAL:
+ return WifiMigration.STORE_FILE_SHARED_GENERAL;
+ case STORE_FILE_SHARED_SOFTAP:
+ // TODO (b/149418926): softap migration needs to be fixed.
+ return null;
+ case STORE_FILE_USER_GENERAL:
+ return WifiMigration.STORE_FILE_USER_GENERAL;
+ case STORE_FILE_USER_NETWORK_SUGGESTIONS:
+ return WifiMigration.STORE_FILE_USER_NETWORK_SUGGESTIONS;
+ default:
+ return null;
+ }
+ }
+
+ private static byte[] readDataFromMigrationSharedStoreFile(@StoreFileId int fileId)
+ throws IOException {
+ Integer migrationStoreFileId = getMigrationStoreFileId(fileId);
+ if (migrationStoreFileId == null) return null;
+ InputStream migrationIs =
+ WifiMigration.convertAndRetrieveSharedConfigStoreFile(migrationStoreFileId);
+ if (migrationIs == null) return null;
+ return readAtomicFileFully(migrationIs);
+ }
+
+ private static byte[] readDataFromMigrationUserStoreFile(@StoreFileId int fileId,
+ UserHandle userHandle) throws IOException {
+ Integer migrationStoreFileId = getMigrationStoreFileId(fileId);
+ if (migrationStoreFileId == null) return null;
+ InputStream migrationIs =
+ WifiMigration.convertAndRetrieveUserConfigStoreFile(
+ migrationStoreFileId, userHandle);
+ if (migrationIs == null) return null;
+ return readAtomicFileFully(migrationIs);
+ }
+
+ /**
+ * Helper method to read from the shared store files.
+ * @throws XmlPullParserException
+ * @throws IOException
+ */
+ private void readFromSharedStoreFiles() throws XmlPullParserException, IOException {
+ for (StoreFile sharedStoreFile : mSharedStores) {
+ byte[] sharedDataBytes = readDataFromMigrationSharedStoreFile(sharedStoreFile.mFileId);
+ if (sharedDataBytes == null) {
+ sharedDataBytes = sharedStoreFile.readRawData();
+ } else {
+ Log.i(TAG, "Read data out of shared migration store file: "
+ + sharedStoreFile.mAtomicFile.getBaseFile().getName());
+ // Save the migrated file contents to the regular store file and delete the
+ // migrated stored file.
+ sharedStoreFile.storeRawDataToWrite(sharedDataBytes);
+ sharedStoreFile.writeBufferedRawData();
+ // Note: If the migrated store file is at the same location as the store file,
+ // then the OEM implementation should ignore this remove.
+ WifiMigration.removeSharedConfigStoreFile(
+ getMigrationStoreFileId(sharedStoreFile.mFileId));
+ }
+ deserializeData(sharedDataBytes, sharedStoreFile);
+ }
+ }
+
+ /**
+ * Helper method to read from the user store files.
+ * @throws XmlPullParserException
+ * @throws IOException
+ */
+ private void readFromUserStoreFiles() throws XmlPullParserException, IOException {
+ for (StoreFile userStoreFile : mUserStores) {
+ byte[] userDataBytes = readDataFromMigrationUserStoreFile(
+ userStoreFile.mFileId, userStoreFile.mUserHandle);
+ if (userDataBytes == null) {
+ userDataBytes = userStoreFile.readRawData();
+ } else {
+ Log.i(TAG, "Read data out of user migration store file: "
+ + userStoreFile.mAtomicFile.getBaseFile().getName());
+ // Save the migrated file contents to the regular store file and delete the
+ // migrated stored file.
+ userStoreFile.storeRawDataToWrite(userDataBytes);
+ userStoreFile.writeBufferedRawData();
+ // Note: If the migrated store file is at the same location as the store file,
+ // then the OEM implementation should ignore this remove.
+ WifiMigration.removeUserConfigStoreFile(
+ getMigrationStoreFileId(userStoreFile.mFileId),
+ userStoreFile.mUserHandle);
+ }
+ deserializeData(userDataBytes, userStoreFile);
+ }
+ }
+
+ /**
* API to read the store data from the config stores.
* The method reads the user specific configurations from user specific config store and the
* shared configurations from the shared config store.
@@ -550,17 +654,10 @@ public class WifiConfigStore {
resetStoreData(userStoreFile);
}
}
-
long readStartTime = mClock.getElapsedSinceBootMillis();
- for (StoreFile sharedStoreFile : mSharedStores) {
- byte[] sharedDataBytes = sharedStoreFile.readRawData();
- deserializeData(sharedDataBytes, sharedStoreFile);
- }
+ readFromSharedStoreFiles();
if (mUserStores != null) {
- for (StoreFile userStoreFile : mUserStores) {
- byte[] userDataBytes = userStoreFile.readRawData();
- deserializeData(userDataBytes, userStoreFile);
- }
+ readFromUserStoreFiles();
}
long readTime = mClock.getElapsedSinceBootMillis() - readStartTime;
try {
@@ -591,12 +688,9 @@ public class WifiConfigStore {
stopBufferedWriteAlarm();
mUserStores = userStores;
- // Now read from the user store file.
+ // Now read from the user store files.
long readStartTime = mClock.getElapsedSinceBootMillis();
- for (StoreFile userStoreFile : mUserStores) {
- byte[] userDataBytes = userStoreFile.readRawData();
- deserializeData(userDataBytes, userStoreFile);
- }
+ readFromUserStoreFiles();
long readTime = mClock.getElapsedSinceBootMillis() - readStartTime;
mWifiMetrics.noteWifiConfigStoreReadDuration(toIntExact(readTime));
Log.d(TAG, "Reading from user stores completed in " + readTime + " ms.");
@@ -766,15 +860,21 @@ public class WifiConfigStore {
*/
private final @StoreFileId int mFileId;
/**
+ * User handle. Meaningful only for user specific store files.
+ */
+ private final UserHandle mUserHandle;
+ /**
* Integrity checking for the store file.
*/
private final WifiConfigStoreEncryptionUtil mEncryptionUtil;
public StoreFile(File file, @StoreFileId int fileId,
+ @NonNull UserHandle userHandle,
@Nullable WifiConfigStoreEncryptionUtil encryptionUtil) {
mAtomicFile = new AtomicFile(file);
mFileName = file.getAbsolutePath();
mFileId = fileId;
+ mUserHandle = userHandle;
mEncryptionUtil = encryptionUtil;
}
diff --git a/service/java/com/android/server/wifi/util/Environment.java b/service/java/com/android/server/wifi/util/Environment.java
index 8ba7ff9f2..b4df26d8e 100644
--- a/service/java/com/android/server/wifi/util/Environment.java
+++ b/service/java/com/android/server/wifi/util/Environment.java
@@ -33,42 +33,6 @@ public class Environment {
private static final String WIFI_APEX_NAME = "com.android.wifi";
/**
- * Directory to store the wifi config store / shared preference files under.
- */
- private static final String LEGACY_WIFI_STORE_DIRECTORY_NAME = "wifi";
-
- /**
- * Get data/misc directory
- */
- public static File getDataMiscDirectory() {
- return new File(android.os.Environment.getDataDirectory(), "misc");
- }
-
- /**
- * Get data/misc_ce/<userId> directory
- */
- public static File getDataMiscCeDirectory(int userId) {
- return buildPath(android.os.Environment.getDataDirectory(), "misc_ce",
- String.valueOf(userId));
- }
-
- /**
- * Append path segments to given base path, returning result.
- */
- public static File buildPath(File base, String... segments) {
- File cur = base;
- for (String segment : segments) {
- if (cur == null) {
- cur = new File(segment);
- } else {
- cur = new File(cur, segment);
- }
- }
- return cur;
- }
-
-
- /**
* Wifi shared folder.
*/
public static File getWifiSharedDirectory() {
@@ -82,19 +46,4 @@ public class Environment {
return ApexEnvironment.getApexEnvironment(WIFI_APEX_NAME)
.getCredentialProtectedDataDirForUser(UserHandle.of(userId));
}
-
-
- /**
- * Pre apex wifi shared folder.
- */
- public static File getLegacyWifiSharedDirectory() {
- return new File(getDataMiscDirectory(), LEGACY_WIFI_STORE_DIRECTORY_NAME);
- }
-
- /**
- * Pre apex wifi user folder.
- */
- public static File getLegacyWifiUserDirectory(int userId) {
- return new File(getDataMiscCeDirectory(userId), LEGACY_WIFI_STORE_DIRECTORY_NAME);
- }
}