diff options
author | Roshan Pius <rpius@google.com> | 2020-03-18 15:34:23 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2020-03-18 15:34:23 +0000 |
commit | e5539573fac5594bd6df5d9ec5a4fdf33c655f94 (patch) | |
tree | 93328a53412788b7e1541160f4889fbe020c8325 /service | |
parent | caf73afd677addbf0fc2172e8446562dfcc5db13 (diff) | |
parent | d32c5600ac8a3b78cb5158f24a39d8a6ad996e7f (diff) |
Merge "WifiConfigStore: Use new API's for migrating config store data" into rvc-dev
Diffstat (limited to 'service')
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); - } } |