diff options
author | Roshan Pius <rpius@google.com> | 2020-03-18 08:23:36 -0700 |
---|---|---|
committer | Roshan Pius <rpius@google.com> | 2020-03-18 15:41:11 -0700 |
commit | d9f6a328b3f97cdd365fc434cad43a1f222f2faf (patch) | |
tree | 722c4a0b20c739ede5de901d34beefa5d529a7f7 | |
parent | d36cf04e2fc563ac2d0039d7595b54fa35a26b97 (diff) |
WifiSoftApConfigStore: Move softap.conf conversion to WifiMigration
Also,
a) added a unit test for the complete migration flow in WifiConfigStore.
b) Fixed a corner case with wificonfiguration to softapconfiguration
band conversion.
Bug: 149418926
Test: atest com.android.server.wifi
Test: Device boots up and able to turn on hotspot.
Test: Manual tests:
a) Flash Q build
b) Add hotspot config
c) Upgrade to RVC build with this CL.
d) Ensure all data has migrated over.
e) Modified hotspot config and reboot.
f) Ensured old data has not migrated over.
Change-Id: Iaca7ccc4cd650898846c855f656f312abfcde831
5 files changed, 163 insertions, 247 deletions
diff --git a/service/java/com/android/server/wifi/WifiApConfigStore.java b/service/java/com/android/server/wifi/WifiApConfigStore.java index e5d12822b..df901a321 100644 --- a/service/java/com/android/server/wifi/WifiApConfigStore.java +++ b/service/java/com/android/server/wifi/WifiApConfigStore.java @@ -22,8 +22,6 @@ import android.content.IntentFilter; 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; @@ -33,10 +31,6 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.server.wifi.util.ApConfigUtil; import com.android.wifi.resources.R; -import java.io.BufferedInputStream; -import java.io.DataInputStream; -import java.io.IOException; -import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.security.SecureRandom; import java.util.Random; @@ -55,13 +49,6 @@ public class WifiApConfigStore { private static final String TAG = "WifiApConfigStore"; - // 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 = "softap.conf"; - - @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; @@ -100,14 +87,7 @@ public class WifiApConfigStore { } 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)); - } + mPersistentWifiApConfig = null; } public boolean hasNewDataToSerialize() { @@ -115,47 +95,19 @@ public class WifiApConfigStore { } } - WifiApConfigStore(Context context, WifiInjector wifiInjector, Handler handler, - BackupManagerProxy backupManagerProxy, WifiConfigStore wifiConfigStore, - WifiConfigManager wifiConfigManager, ActiveModeWarden activeModeWarden) { - this(context, wifiInjector, handler, backupManagerProxy, wifiConfigStore, - wifiConfigManager, activeModeWarden, - WifiMigration.convertAndRetrieveSharedConfigStoreFile( - WifiMigration.STORE_FILE_SHARED_SOFTAP)); - } - WifiApConfigStore(Context context, WifiInjector wifiInjector, Handler handler, BackupManagerProxy backupManagerProxy, WifiConfigStore wifiConfigStore, WifiConfigManager wifiConfigManager, - ActiveModeWarden activeModeWarden, - InputStream legacyApConfigFileStream) { + ActiveModeWarden activeModeWarden) { mContext = context; mHandler = handler; mBackupManagerProxy = backupManagerProxy; mWifiConfigManager = wifiConfigManager; mActiveModeWarden = activeModeWarden; - // One time migration from legacy config store. - // 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(legacyApConfigFileStream); - if (config != null) { - // Persist in the new store. - persistConfigAndTriggerBackupManagerProxy(config); - Log.i(TAG, "Migrated data out of legacy store file"); - WifiMigration.removeSharedConfigStoreFile( - WifiMigration.STORE_FILE_SHARED_SOFTAP); - } - } - // Register store data listener wifiConfigStore.registerStoreData( wifiInjector.makeSoftApStoreData(new SoftApStoreDataSource())); @@ -268,65 +220,6 @@ 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(InputStream fis) { - SoftApConfiguration config = null; - DataInputStream in = null; - try { - SoftApConfiguration.Builder configBuilder = new SoftApConfiguration.Builder(); - in = new DataInputStream(new BufferedInputStream(fis)); - - int version = in.readInt(); - if (version < 1 || version > AP_CONFIG_FILE_VERSION) { - Log.e(TAG, "Bad version on hotspot configuration file"); - return null; - } - configBuilder.setSsid(in.readUTF()); - - if (version >= 2) { - int band = in.readInt(); - int channel = in.readInt(); - - if (channel == 0) { - configBuilder.setBand( - ApConfigUtil.convertWifiConfigBandToSoftApConfigBand(band)); - } else { - configBuilder.setChannel(channel, - ApConfigUtil.convertWifiConfigBandToSoftApConfigBand(band)); - } - } - - if (version >= 3) { - configBuilder.setHiddenSsid(in.readBoolean()); - } - - int authType = in.readInt(); - if (authType == WifiConfiguration.KeyMgmt.WPA2_PSK) { - configBuilder.setPassphrase(in.readUTF(), - SoftApConfiguration.SECURITY_TYPE_WPA2_PSK); - } - config = configBuilder.build(); - } catch (IOException e) { - Log.e(TAG, "Error reading hotspot configuration " + e); - config = null; - } catch (IllegalArgumentException ie) { - Log.e(TAG, "Invalid hotspot configuration " + ie); - config = null; - } finally { - if (in != null) { - try { - in.close(); - } catch (IOException e) { - Log.e(TAG, "Error closing hotspot configuration during read" + e); - } - } - } - return config; - } - - /** * Generate a default WPA3 SAE transition (if supported) or WPA2 based * configuration with a random password. * We are changing the Wifi Ap configuration storage from secure settings to a diff --git a/service/java/com/android/server/wifi/WifiConfigStore.java b/service/java/com/android/server/wifi/WifiConfigStore.java index a891b0588..9a73f52d5 100644 --- a/service/java/com/android/server/wifi/WifiConfigStore.java +++ b/service/java/com/android/server/wifi/WifiConfigStore.java @@ -379,7 +379,7 @@ public class WifiConfigStore { private List<StoreData> retrieveStoreDataListForStoreFile(@NonNull StoreFile storeFile) { return mStoreDataList .stream() - .filter(s -> s.getStoreFileId() == storeFile.mFileId) + .filter(s -> s.getStoreFileId() == storeFile.getFileId()) .collect(Collectors.toList()); } @@ -553,8 +553,7 @@ public class WifiConfigStore { 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; + return WifiMigration.STORE_FILE_SHARED_SOFTAP; case STORE_FILE_USER_GENERAL: return WifiMigration.STORE_FILE_USER_GENERAL; case STORE_FILE_USER_NETWORK_SUGGESTIONS: @@ -592,12 +591,14 @@ public class WifiConfigStore { */ private void readFromSharedStoreFiles() throws XmlPullParserException, IOException { for (StoreFile sharedStoreFile : mSharedStores) { - byte[] sharedDataBytes = readDataFromMigrationSharedStoreFile(sharedStoreFile.mFileId); + byte[] sharedDataBytes = + readDataFromMigrationSharedStoreFile(sharedStoreFile.getFileId()); if (sharedDataBytes == null) { + // nothing to migrate, do normal read. sharedDataBytes = sharedStoreFile.readRawData(); } else { Log.i(TAG, "Read data out of shared migration store file: " - + sharedStoreFile.mAtomicFile.getBaseFile().getName()); + + sharedStoreFile.getName()); // Save the migrated file contents to the regular store file and delete the // migrated stored file. sharedStoreFile.storeRawDataToWrite(sharedDataBytes); @@ -605,7 +606,7 @@ public class WifiConfigStore { // 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)); + getMigrationStoreFileId(sharedStoreFile.getFileId())); } deserializeData(sharedDataBytes, sharedStoreFile); } @@ -619,12 +620,13 @@ public class WifiConfigStore { private void readFromUserStoreFiles() throws XmlPullParserException, IOException { for (StoreFile userStoreFile : mUserStores) { byte[] userDataBytes = readDataFromMigrationUserStoreFile( - userStoreFile.mFileId, userStoreFile.mUserHandle); + userStoreFile.getFileId(), userStoreFile.mUserHandle); if (userDataBytes == null) { + // nothing to migrate, do normal read. userDataBytes = userStoreFile.readRawData(); } else { Log.i(TAG, "Read data out of user migration store file: " - + userStoreFile.mAtomicFile.getBaseFile().getName()); + + userStoreFile.getName()); // Save the migrated file contents to the regular store file and delete the // migrated stored file. userStoreFile.storeRawDataToWrite(userDataBytes); @@ -632,7 +634,7 @@ public class WifiConfigStore { // 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), + getMigrationStoreFileId(userStoreFile.getFileId()), userStoreFile.mUserHandle); } deserializeData(userDataBytes, userStoreFile); @@ -878,6 +880,14 @@ public class WifiConfigStore { mEncryptionUtil = encryptionUtil; } + public String getName() { + return mAtomicFile.getBaseFile().getName(); + } + + public @StoreFileId int getFileId() { + return mFileId; + } + /** * @return Returns the encryption util used for this store file. */ diff --git a/service/java/com/android/server/wifi/util/ApConfigUtil.java b/service/java/com/android/server/wifi/util/ApConfigUtil.java index 552231ed2..d385e3edc 100644 --- a/service/java/com/android/server/wifi/util/ApConfigUtil.java +++ b/service/java/com/android/server/wifi/util/ApConfigUtil.java @@ -178,7 +178,7 @@ public class ApConfigUtil { case WifiConfiguration.AP_BAND_ANY: return SoftApConfiguration.BAND_2GHZ | SoftApConfiguration.BAND_5GHZ; default: - return -1; + return SoftApConfiguration.BAND_2GHZ; } } diff --git a/tests/wifitests/src/com/android/server/wifi/WifiApConfigStoreTest.java b/tests/wifitests/src/com/android/server/wifi/WifiApConfigStoreTest.java index 14cb6043a..54761e2be 100644 --- a/tests/wifitests/src/com/android/server/wifi/WifiApConfigStoreTest.java +++ b/tests/wifitests/src/com/android/server/wifi/WifiApConfigStoreTest.java @@ -24,7 +24,6 @@ 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.never; import static org.mockito.Mockito.times; @@ -36,15 +35,12 @@ import android.content.pm.ApplicationInfo; import android.net.MacAddress; import android.net.wifi.SoftApConfiguration; import android.net.wifi.SoftApConfiguration.Builder; -import android.net.wifi.WifiConfiguration; -import android.net.wifi.WifiConfiguration.KeyMgmt; import android.os.Build; import android.os.Handler; import android.os.test.TestLooper; import androidx.test.filters.SmallTest; -import com.android.server.wifi.util.ApConfigUtil; import com.android.wifi.resources.R; import org.junit.Before; @@ -53,12 +49,6 @@ 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.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Random; @@ -71,11 +61,9 @@ public class WifiApConfigStoreTest extends WifiBaseTest { private static final String TAG = "WifiApConfigStoreTest"; - private static final String TEST_AP_CONFIG_FILE_PREFIX = "APConfig_"; private static final String TEST_DEFAULT_2G_CHANNEL_LIST = "1,2,3,4,5,6"; private static final String TEST_DEFAULT_AP_SSID = "TestAP"; private static final String TEST_DEFAULT_HOTSPOT_SSID = "TestShare"; - private static final String TEST_DEFAULT_HOTSPOT_PSK = "TestPassword"; private static final int RAND_SSID_INT_MIN = 1000; private static final int RAND_SSID_INT_MAX = 9999; private static final String TEST_CHAR_SET_AS_STRING = "abcdefghijklmnopqrstuvwxyz0123456789"; @@ -96,7 +84,6 @@ public class WifiApConfigStoreTest extends WifiBaseTest { @Mock private WifiConfigStore mWifiConfigStore; @Mock private WifiConfigManager mWifiConfigManager; @Mock private ActiveModeWarden mActiveModeWarden; - private File mLegacyApConfigFile; private Random mRandom; private MockResources mResources; @Mock private ApplicationInfo mMockApplInfo; @@ -136,19 +123,10 @@ public class WifiApConfigStoreTest extends WifiBaseTest { /** * Helper method to create and verify actions for the ApConfigStore used in the following tests. */ - private WifiApConfigStore createWifiApConfigStore(File legacyFile) throws Exception { - WifiApConfigStore store; - if (legacyFile == null) { - store = new WifiApConfigStore( - mContext, mWifiInjector, mHandler, mBackupManagerProxy, - mWifiConfigStore, mWifiConfigManager, mActiveModeWarden); - } else { - store = new WifiApConfigStore( - mContext, mWifiInjector, mHandler, mBackupManagerProxy, - mWifiConfigStore, mWifiConfigManager, mActiveModeWarden, - new FileInputStream(legacyFile)); - } - + private WifiApConfigStore createWifiApConfigStore() throws Exception { + WifiApConfigStore store = new WifiApConfigStore( + mContext, mWifiInjector, mHandler, mBackupManagerProxy, + mWifiConfigStore, mWifiConfigManager, mActiveModeWarden); verify(mWifiConfigStore).registerStoreData(any()); ArgumentCaptor<SoftApStoreData.DataSource> dataStoreSourceArgumentCaptor = ArgumentCaptor.forClass(SoftApStoreData.DataSource.class); @@ -158,10 +136,6 @@ public class WifiApConfigStoreTest extends WifiBaseTest { return store; } - private WifiApConfigStore createWifiApConfigStore() throws Exception { - return createWifiApConfigStore(null); - } - /** * Generate a SoftApConfiguration based on the specified parameters. */ @@ -180,62 +154,6 @@ public class WifiApConfigStoreTest extends WifiBaseTest { return configBuilder.build(); } - /** - * Generate a WifiConfiguration based on the specified parameters. - */ - private WifiConfiguration setupWifiConfigurationApConfig( - String ssid, String preSharedKey, int keyManagement, int band, int channel, - boolean hiddenSSID) { - WifiConfiguration config = new WifiConfiguration(); - config.SSID = ssid; - config.preSharedKey = preSharedKey; - config.allowedKeyManagement.set(keyManagement); - config.apBand = band; - config.apChannel = channel; - config.hiddenSSID = hiddenSSID; - return 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); - } - } - - /** - * Asserts that the WifiConfigurations equal to SoftApConfiguration. - * This only compares the elements saved - * for softAp used. - */ - public static void assertWifiConfigurationEqualSoftApConfiguration( - WifiConfiguration backup, SoftApConfiguration restore) { - assertEquals(backup.SSID, restore.getSsid()); - assertEquals(backup.BSSID, restore.getBssid()); - assertEquals(ApConfigUtil.convertWifiConfigBandToSoftApConfigBand(backup.apBand), - restore.getBand()); - assertEquals(backup.apChannel, restore.getChannel()); - assertEquals(backup.preSharedKey, restore.getPassphrase()); - int authType = backup.getAuthType(); - if (backup.getAuthType() == WifiConfiguration.KeyMgmt.WPA2_PSK) { - assertEquals(SoftApConfiguration.SECURITY_TYPE_WPA2_PSK, restore.getSecurityType()); - } else { - assertEquals(SoftApConfiguration.SECURITY_TYPE_OPEN, restore.getSecurityType()); - } - assertEquals(backup.hiddenSSID, restore.isHiddenSsid()); - } - private void verifyApConfig(SoftApConfiguration config1, SoftApConfiguration config2) { assertEquals(config1.getSsid(), config2.getSsid()); assertEquals(config1.getPassphrase(), config2.getPassphrase()); @@ -299,47 +217,6 @@ public class WifiApConfigStoreTest extends WifiBaseTest { verify(mWifiConfigManager).saveToStore(true); } - /** - * Verify WifiApConfigStore can correctly load the existing configuration - * from the legacy config file and migrate it to the new config store. - */ - @Test - public void initWithExistingConfigurationInLegacyFile() throws Exception { - WifiConfiguration backupConfig = setupWifiConfigurationApConfig( - "ConfiguredAP", /* SSID */ - "randomKey", /* preshared key */ - KeyMgmt.WPA2_PSK, /* key management */ - 1, /* AP band (5GHz) */ - 40, /* AP channel */ - true /* Hidden SSID */); - - /* Create a temporary file for AP config file storage. */ - mLegacyApConfigFile = File.createTempFile(TEST_AP_CONFIG_FILE_PREFIX, ""); - - SoftApConfiguration expectedConfig = setupApConfig( - "ConfiguredAP", /* SSID */ - "randomKey", /* preshared key */ - SECURITY_TYPE_WPA2_PSK, /* security type */ - SoftApConfiguration.BAND_5GHZ, /* AP band (5GHz) */ - 40, /* AP channel */ - true /* Hidden SSID */); - - assertWifiConfigurationEqualSoftApConfiguration(backupConfig, expectedConfig); - - writeLegacyApConfigFile(backupConfig); - WifiApConfigStore store = createWifiApConfigStore(mLegacyApConfigFile); - 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); - } /** * Verify the handling of setting a null ap configuration. diff --git a/tests/wifitests/src/com/android/server/wifi/WifiConfigStoreTest.java b/tests/wifitests/src/com/android/server/wifi/WifiConfigStoreTest.java index 967c029ba..ca368733a 100644 --- a/tests/wifitests/src/com/android/server/wifi/WifiConfigStoreTest.java +++ b/tests/wifitests/src/com/android/server/wifi/WifiConfigStoreTest.java @@ -19,6 +19,7 @@ package com.android.server.wifi; import static org.junit.Assert.*; import static org.mockito.Mockito.*; +import android.app.test.MockAnswerUtil; import android.app.test.TestAlarmManager; import android.content.Context; import android.content.pm.PackageManager; @@ -46,12 +47,14 @@ import org.junit.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.MockitoSession; +import org.mockito.stubbing.Answer; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; import java.io.File; import java.io.IOException; +import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; @@ -153,6 +156,12 @@ public class WifiConfigStoreTest extends WifiBaseTest { + "</Integrity>\n" + "<%s />\n" + "</WifiConfigStoreData>\n"; + private static final String TEST_DATA_XML_STRING_FORMAT_V3_WITH_ONE_DATA_SOURCE = + "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n" + + "<WifiConfigStoreData>\n" + + "<int name=\"Version\" value=\"3\" />\n" + + "<%s />\n" + + "</WifiConfigStoreData>\n"; // Test mocks @Mock private Context mContext; @Mock private PackageManager mPackageManager; @@ -162,6 +171,7 @@ public class WifiConfigStoreTest extends WifiBaseTest { @Mock private WifiMetrics mWifiMetrics; @Mock private WifiConfigStoreEncryptionUtil mEncryptionUtil; private MockStoreFile mSharedStore; + private MockStoreFile mSharedSoftApStore; private MockStoreFile mUserStore; private MockStoreFile mUserNetworkSuggestionsStore; private List<StoreFile> mUserStores = new ArrayList<StoreFile>(); @@ -190,6 +200,7 @@ public class WifiConfigStoreTest extends WifiBaseTest { when(mEncryptionUtil.decrypt(any(EncryptedData.class))) .thenReturn(new byte[0]); mSharedStore = new MockStoreFile(WifiConfigStore.STORE_FILE_SHARED_GENERAL); + mSharedSoftApStore = new MockStoreFile(WifiConfigStore.STORE_FILE_SHARED_SOFTAP); mUserStore = new MockStoreFile(WifiConfigStore.STORE_FILE_USER_GENERAL); mUserNetworkSuggestionsStore = new MockStoreFile(WifiConfigStore.STORE_FILE_USER_NETWORK_SUGGESTIONS); @@ -214,7 +225,7 @@ public class WifiConfigStoreTest extends WifiBaseTest { setupMocks(); mWifiConfigStore = new WifiConfigStore(mContext, new Handler(mLooper.getLooper()), mClock, - mWifiMetrics, Arrays.asList(mSharedStore)); + mWifiMetrics, Arrays.asList(mSharedStore, mSharedSoftApStore)); // Enable verbose logging before tests. mWifiConfigStore.enableVerboseLogging(true); } @@ -847,6 +858,131 @@ public class WifiConfigStoreTest extends WifiBaseTest { } /** + * Tests the complete migration path all the way from reading from the migration stream to + * parsing the XML data and sending it to the appropriate registered data sources. + */ + @Test + public void testMigration() throws Exception { + // Setup both shared & user store migrations. + StoreFile sharedStoreFile1 = mock(StoreFile.class); + when(sharedStoreFile1.getFileId()) + .thenReturn(WifiConfigStore.STORE_FILE_SHARED_GENERAL); + StoreFile sharedStoreFile2 = mock(StoreFile.class); + when(sharedStoreFile2.getFileId()) + .thenReturn(WifiConfigStore.STORE_FILE_SHARED_SOFTAP); + StoreFile userStoreFile1 = mock(StoreFile.class); + when(userStoreFile1.getFileId()) + .thenReturn(WifiConfigStore.STORE_FILE_USER_GENERAL); + StoreFile userStoreFile2 = mock(StoreFile.class); + when(userStoreFile2.getFileId()) + .thenReturn(WifiConfigStore.STORE_FILE_USER_NETWORK_SUGGESTIONS); + mWifiConfigStore = new WifiConfigStore(mContext, new Handler(mLooper.getLooper()), mClock, + mWifiMetrics, Arrays.asList(sharedStoreFile1, sharedStoreFile2)); + mWifiConfigStore.setUserStores(Arrays.asList(userStoreFile1, userStoreFile2)); + + // Register data container. + StoreData sharedStoreData = mock(StoreData.class); + when(sharedStoreData.getStoreFileId()) + .thenReturn(WifiConfigStore.STORE_FILE_SHARED_GENERAL); + when(sharedStoreData.getName()).thenReturn(TEST_SHARE_DATA); + StoreData userStoreData = mock(StoreData.class); + when(userStoreData.getStoreFileId()) + .thenReturn(WifiConfigStore.STORE_FILE_USER_GENERAL); + when(userStoreData.getName()).thenReturn(TEST_USER_DATA); + mWifiConfigStore.registerStoreData(sharedStoreData); + mWifiConfigStore.registerStoreData(userStoreData); + + // Migration data + InputStream sharedStream1 = mock(InputStream.class); + InputStream sharedStream2 = mock(InputStream.class); + InputStream userStream1 = mock(InputStream.class); + InputStream userStream2 = mock(InputStream.class); + when(WifiMigration.convertAndRetrieveSharedConfigStoreFile( + WifiMigration.STORE_FILE_SHARED_GENERAL)) + .thenReturn(sharedStream1); + when(WifiMigration.convertAndRetrieveSharedConfigStoreFile( + WifiMigration.STORE_FILE_SHARED_SOFTAP)) + .thenReturn(sharedStream2); + when(WifiMigration.convertAndRetrieveUserConfigStoreFile( + eq(WifiMigration.STORE_FILE_USER_GENERAL), any())) + .thenReturn(userStream1); + when(WifiMigration.convertAndRetrieveUserConfigStoreFile( + eq(WifiMigration.STORE_FILE_USER_NETWORK_SUGGESTIONS), any())) + .thenReturn(userStream2); + + byte[] sharedStoreXmlBytes = + String.format(TEST_DATA_XML_STRING_FORMAT_V3_WITH_ONE_DATA_SOURCE, + TEST_SHARE_DATA).getBytes(); + byte[] userStoreXmlBytes = + String.format(TEST_DATA_XML_STRING_FORMAT_V3_WITH_ONE_DATA_SOURCE, + TEST_USER_DATA).getBytes(); + when(sharedStream1.available()) + .thenReturn(sharedStoreXmlBytes.length) // first time return file contents, then 0. + .thenReturn(0); + when(sharedStream2.available()) + .thenReturn(sharedStoreXmlBytes.length) // first time return file contents, then 0. + .thenReturn(0); + when(userStream1.available()) + .thenReturn(userStoreXmlBytes.length) // first time return file contents, then 0. + .thenReturn(0); + when(userStream2.available()) + .thenReturn(userStoreXmlBytes.length) // first time return file contents, then 0. + .thenReturn(0); + Answer sharedStreamReadAnswer = new MockAnswerUtil.AnswerWithArguments() { + public int answer(byte[] b, int off, int len) { + System.arraycopy(sharedStoreXmlBytes, 0, b, 0, sharedStoreXmlBytes.length); + return sharedStoreXmlBytes.length; + } + }; + Answer userStreamReadAnswer = new MockAnswerUtil.AnswerWithArguments() { + public int answer(byte[] b, int off, int len) { + System.arraycopy(userStoreXmlBytes, 0, b, 0, userStoreXmlBytes.length); + return userStoreXmlBytes.length; + } + }; + when(sharedStream1.read(any(byte[].class), anyInt(), anyInt())) + .thenAnswer(sharedStreamReadAnswer) // first time return file contents, then 0. + .thenReturn(0); + when(sharedStream2.read(any(byte[].class), anyInt(), anyInt())) + .thenAnswer(sharedStreamReadAnswer) // first time return file contents, then 0. + .thenReturn(0); + when(userStream1.read(any(byte[].class), anyInt(), anyInt())) + .thenAnswer(userStreamReadAnswer) // first time return file contents, then 0. + .thenReturn(0); + when(userStream2.read(any(byte[].class), anyInt(), anyInt())) + .thenAnswer(userStreamReadAnswer) // first time return file contents, then 0. + .thenReturn(0); + + // Trigger read. + mWifiConfigStore.read(); + + // Verify that we read the data out of all the migration streams & we didn't read + // from the files on disk. + verify(sharedStream1, times(2)).available(); + verify(sharedStream1, times(2)).read(any(), anyInt(), anyInt()); + verify(sharedStream2, times(2)).available(); + verify(sharedStream2, times(2)).read(any(), anyInt(), anyInt()); + verify(userStream1, times(2)).available(); + verify(userStream1, times(2)).read(any(), anyInt(), anyInt()); + verify(userStream2, times(2)).available(); + verify(userStream2, times(2)).read(any(), anyInt(), anyInt()); + + // Verify that we correctly deserialized the data and sent it to the corresponding sources. + verify(sharedStoreData, times(1)) + .deserializeData(any(XmlPullParser.class), anyInt(), + eq(WifiConfigStore.ENCRYPT_CREDENTIALS_CONFIG_STORE_DATA_VERSION), any()); + verify(userStoreData, times(1)) + .deserializeData(any(XmlPullParser.class), anyInt(), + eq(WifiConfigStore.ENCRYPT_CREDENTIALS_CONFIG_STORE_DATA_VERSION), any()); + + // Verify we did not read from the real store files. + verify(sharedStoreFile1, never()).readRawData(); + verify(sharedStoreFile2, never()).readRawData(); + verify(userStoreFile1, never()).readRawData(); + verify(userStoreFile2, never()).readRawData(); + } + + /** * Mock Store File to redirect all file writes from WifiConfigStore to local buffers. * This can be used to examine the data output by WifiConfigStore. */ |