1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.wifi; 18 19 import static org.junit.Assert.*; 20 import static org.mockito.Mockito.*; 21 22 import android.app.test.MockAnswerUtil; 23 import android.app.test.TestAlarmManager; 24 import android.content.Context; 25 import android.content.pm.PackageManager; 26 import android.net.MacAddress; 27 import android.net.wifi.WifiConfiguration; 28 import android.net.wifi.WifiMigration; 29 import android.net.wifi.util.HexEncoding; 30 import android.os.Handler; 31 import android.os.UserHandle; 32 import android.os.test.TestLooper; 33 34 import androidx.test.filters.SmallTest; 35 36 import com.android.dx.mockito.inline.extended.ExtendedMockito; 37 import com.android.internal.util.FastPrintWriter; 38 import com.android.server.wifi.WifiConfigStore.StoreData; 39 import com.android.server.wifi.WifiConfigStore.StoreFile; 40 import com.android.server.wifi.util.ArrayUtils; 41 import com.android.server.wifi.util.EncryptedData; 42 import com.android.server.wifi.util.WifiConfigStoreEncryptionUtil; 43 import com.android.server.wifi.util.XmlUtil; 44 45 import org.junit.After; 46 import org.junit.Before; 47 import org.junit.Test; 48 import org.mockito.Mock; 49 import org.mockito.MockitoAnnotations; 50 import org.mockito.MockitoSession; 51 import org.mockito.stubbing.Answer; 52 import org.xmlpull.v1.XmlPullParser; 53 import org.xmlpull.v1.XmlPullParserException; 54 import org.xmlpull.v1.XmlSerializer; 55 56 import java.io.File; 57 import java.io.FileDescriptor; 58 import java.io.FileOutputStream; 59 import java.io.IOException; 60 import java.io.InputStream; 61 import java.io.PrintWriter; 62 import java.nio.charset.StandardCharsets; 63 import java.util.ArrayList; 64 import java.util.Arrays; 65 import java.util.Collections; 66 import java.util.HashSet; 67 import java.util.List; 68 import java.util.Random; 69 70 /** 71 * Unit tests for {@link com.android.server.wifi.WifiConfigStore}. 72 */ 73 @SmallTest 74 public class WifiConfigStoreTest extends WifiBaseTest { 75 private static final String TEST_USER_DATA = "UserData"; 76 private static final String TEST_SHARE_DATA = "ShareData"; 77 private static final String TEST_CREATOR_NAME = "CreatorName"; 78 private static final MacAddress TEST_RANDOMIZED_MAC = 79 MacAddress.fromString("da:a1:19:c4:26:fa"); 80 private static final int TEST_SUB_ID = 2; 81 82 private static final String TEST_DATA_XML_STRING_FORMAT = 83 "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n" 84 + "<WifiConfigStoreData>\n" 85 + "<int name=\"Version\" value=\"3\" />\n" 86 + "<NetworkList>\n" 87 + "<Network>\n" 88 + "<WifiConfiguration>\n" 89 + "<string name=\"ConfigKey\">%s</string>\n" 90 + "<string name=\"SSID\">%s</string>\n" 91 + "<null name=\"PreSharedKey\" />\n" 92 + "<null name=\"WEPKeys\" />\n" 93 + "<int name=\"WEPTxKeyIndex\" value=\"0\" />\n" 94 + "<boolean name=\"HiddenSSID\" value=\"false\" />\n" 95 + "<boolean name=\"RequirePMF\" value=\"false\" />\n" 96 + "<byte-array name=\"AllowedKeyMgmt\" num=\"1\">01</byte-array>\n" 97 + "<byte-array name=\"AllowedProtocols\" num=\"1\">03</byte-array>\n" 98 + "<byte-array name=\"AllowedAuthAlgos\" num=\"0\"></byte-array>\n" 99 + "<byte-array name=\"AllowedGroupCiphers\" num=\"0\"></byte-array>\n" 100 + "<byte-array name=\"AllowedPairwiseCiphers\" num=\"0\"></byte-array>\n" 101 + "<byte-array name=\"AllowedGroupMgmtCiphers\" num=\"0\"></byte-array>\n" 102 + "<byte-array name=\"AllowedSuiteBCiphers\" num=\"0\"></byte-array>\n" 103 + "<boolean name=\"Shared\" value=\"%s\" />\n" 104 + "<boolean name=\"AutoJoinEnabled\" value=\"true\" />\n" 105 + "<int name=\"DeletionPriority\" value=\"0\" />\n" 106 + "<int name=\"NumRebootsSinceLastUse\" value=\"0\" />\n" 107 + "<SecurityParamsList>\n" 108 + "<SecurityParams>\n" 109 + "<int name=\"SecurityType\" value=\"0\" />\n" 110 + "<boolean name=\"SaeIsH2eOnlyMode\" value=\"false\" />\n" 111 + "<boolean name=\"SaeIsPkOnlyMode\" value=\"false\" />\n" 112 + "<boolean name=\"IsAddedByAutoUpgrade\" value=\"false\" />\n" 113 + "</SecurityParams>\n" 114 + "<SecurityParams>\n" 115 + "<int name=\"SecurityType\" value=\"6\" />\n" 116 + "<boolean name=\"SaeIsH2eOnlyMode\" value=\"false\" />\n" 117 + "<boolean name=\"SaeIsPkOnlyMode\" value=\"false\" />\n" 118 + "<boolean name=\"IsAddedByAutoUpgrade\" value=\"true\" />\n" 119 + "</SecurityParams>\n" 120 + "</SecurityParamsList>\n" 121 + "<boolean name=\"Trusted\" value=\"true\" />\n" 122 + "<boolean name=\"OemPaid\" value=\"false\" />\n" 123 + "<boolean name=\"OemPrivate\" value=\"false\" />\n" 124 + "<boolean name=\"CarrierMerged\" value=\"false\" />\n" 125 + "<null name=\"BSSID\" />\n" 126 + "<int name=\"Status\" value=\"2\" />\n" 127 + "<null name=\"FQDN\" />\n" 128 + "<null name=\"ProviderFriendlyName\" />\n" 129 + "<null name=\"LinkedNetworksList\" />\n" 130 + "<null name=\"DefaultGwMacAddress\" />\n" 131 + "<boolean name=\"ValidatedInternetAccess\" value=\"false\" />\n" 132 + "<boolean name=\"NoInternetAccessExpected\" value=\"false\" />\n" 133 + "<boolean name=\"MeteredHint\" value=\"false\" />\n" 134 + "<int name=\"MeteredOverride\" value=\"0\" />\n" 135 + "<boolean name=\"UseExternalScores\" value=\"false\" />\n" 136 + "<int name=\"CreatorUid\" value=\"%d\" />\n" 137 + "<string name=\"CreatorName\">%s</string>\n" 138 + "<int name=\"LastUpdateUid\" value=\"-1\" />\n" 139 + "<null name=\"LastUpdateName\" />\n" 140 + "<int name=\"LastConnectUid\" value=\"0\" />\n" 141 + "<boolean name=\"IsLegacyPasspointConfig\" value=\"false\" />\n" 142 + "<long-array name=\"RoamingConsortiumOIs\" num=\"0\" />\n" 143 + "<string name=\"RandomizedMacAddress\">%s</string>\n" 144 + "<int name=\"MacRandomizationSetting\" value=\"3\" />\n" 145 + "<int name=\"CarrierId\" value=\"-1\" />\n" 146 + "<boolean name=\"IsMostRecentlyConnected\" value=\"false\" />\n" 147 + "<int name=\"SubscriptionId\" value=\"%d\" />\n" 148 + "</WifiConfiguration>\n" 149 + "<NetworkStatus>\n" 150 + "<string name=\"SelectionStatus\">NETWORK_SELECTION_ENABLED</string>\n" 151 + "<string name=\"DisableReason\">NETWORK_SELECTION_ENABLE</string>\n" 152 + "<null name=\"ConnectChoice\" />\n" 153 + "<int name=\"ConnectChoiceRssi\" value=\"0\" />\n" 154 + "<boolean name=\"HasEverConnected\" value=\"false\" />\n" 155 + "<boolean name=\"CaptivePortalNeverDetected\" value=\"true\" />\n" 156 + "</NetworkStatus>\n" 157 + "<IpConfiguration>\n" 158 + "<string name=\"IpAssignment\">DHCP</string>\n" 159 + "<string name=\"ProxySettings\">NONE</string>\n" 160 + "</IpConfiguration>\n" 161 + "</Network>\n" 162 + "</NetworkList>\n" 163 + "</WifiConfigStoreData>\n"; 164 165 private static final String TEST_DATA_XML_STRING_FORMAT_V1_WITH_ONE_DATA_SOURCE = 166 "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n" 167 + "<WifiConfigStoreData>\n" 168 + "<int name=\"Version\" value=\"1\" />\n" 169 + "<%s/>n" 170 + "</WifiConfigStoreData>\n"; 171 private static final String TEST_DATA_XML_STRING_FORMAT_V1_WITH_TWO_DATA_SOURCE = 172 "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n" 173 + "<WifiConfigStoreData>\n" 174 + "<int name=\"Version\" value=\"1\" />\n" 175 + "<%s/>n" 176 + "<%s/>n" 177 + "</WifiConfigStoreData>\n"; 178 private static final String TEST_DATA_XML_STRING_FORMAT_V2_WITH_ONE_DATA_SOURCE = 179 "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n" 180 + "<WifiConfigStoreData>\n" 181 + "<int name=\"Version\" value=\"2\" />\n" 182 + "<Integrity>\n" 183 + "<byte-array name=\"EncryptedData\" num=\"48\">%s</byte-array>\n" 184 + "<byte-array name=\"IV\" num=\"12\">%s</byte-array>\n" 185 + "</Integrity>\n" 186 + "<%s />\n" 187 + "</WifiConfigStoreData>\n"; 188 private static final String TEST_DATA_XML_STRING_FORMAT_V3_WITH_ONE_DATA_SOURCE = 189 "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n" 190 + "<WifiConfigStoreData>\n" 191 + "<int name=\"Version\" value=\"3\" />\n" 192 + "<%s />\n" 193 + "</WifiConfigStoreData>\n"; 194 // Test mocks 195 @Mock private Context mContext; 196 @Mock private PackageManager mPackageManager; 197 private TestAlarmManager mAlarmManager; 198 private TestLooper mLooper; 199 @Mock private Clock mClock; 200 @Mock private WifiMetrics mWifiMetrics; 201 @Mock private WifiConfigStoreEncryptionUtil mEncryptionUtil; 202 private MockStoreFile mSharedStore; 203 private MockStoreFile mSharedSoftApStore; 204 private MockStoreFile mUserStore; 205 private MockStoreFile mUserNetworkSuggestionsStore; 206 private List<StoreFile> mUserStores = new ArrayList<StoreFile>(); 207 private MockStoreData mSharedStoreData; 208 private MockStoreData mUserStoreData; 209 private MockitoSession mSession; 210 private @Mock WifiCarrierInfoStoreManagerData.DataSource mDataSource; 211 212 /** 213 * Test instance of WifiConfigStore. 214 */ 215 private WifiConfigStore mWifiConfigStore; 216 217 /** 218 * Setup mocks before the test starts. 219 */ setupMocks()220 private void setupMocks() throws Exception { 221 MockitoAnnotations.initMocks(this); 222 mAlarmManager = new TestAlarmManager(); 223 mLooper = new TestLooper(); 224 when(mContext.getSystemService(Context.ALARM_SERVICE)) 225 .thenReturn(mAlarmManager.getAlarmManager()); 226 when(mContext.getPackageManager()).thenReturn(mPackageManager); 227 when(mPackageManager.getNameForUid(anyInt())).thenReturn(TEST_CREATOR_NAME); 228 when(mEncryptionUtil.encrypt(any(byte[].class))) 229 .thenReturn(new EncryptedData(new byte[0], new byte[0])); 230 when(mEncryptionUtil.decrypt(any(EncryptedData.class))) 231 .thenReturn(new byte[0]); 232 mSharedStore = new MockStoreFile(WifiConfigStore.STORE_FILE_SHARED_GENERAL); 233 mSharedSoftApStore = new MockStoreFile(WifiConfigStore.STORE_FILE_SHARED_SOFTAP); 234 mUserStore = new MockStoreFile(WifiConfigStore.STORE_FILE_USER_GENERAL); 235 mUserNetworkSuggestionsStore = 236 new MockStoreFile(WifiConfigStore.STORE_FILE_USER_NETWORK_SUGGESTIONS); 237 mUserStores.add(mUserStore); 238 mUserStores.add(mUserNetworkSuggestionsStore); 239 240 mSharedStoreData = new MockStoreData(WifiConfigStore.STORE_FILE_SHARED_GENERAL); 241 mUserStoreData = new MockStoreData(WifiConfigStore.STORE_FILE_USER_GENERAL); 242 243 mSession = ExtendedMockito.mockitoSession() 244 .mockStatic(WifiMigration.class, withSettings().lenient()) 245 .startMocking(); 246 when(WifiMigration.convertAndRetrieveSharedConfigStoreFile(anyInt())).thenReturn(null); 247 when(WifiMigration.convertAndRetrieveUserConfigStoreFile(anyInt(), any())).thenReturn(null); 248 } 249 250 /** 251 * Setup the test environment. 252 */ 253 @Before setUp()254 public void setUp() throws Exception { 255 setupMocks(); 256 257 mWifiConfigStore = new WifiConfigStore(mContext, new Handler(mLooper.getLooper()), mClock, 258 mWifiMetrics, Arrays.asList(mSharedStore, mSharedSoftApStore)); 259 // Enable verbose logging before tests. 260 mWifiConfigStore.enableVerboseLogging(true); 261 } 262 263 /** 264 * Called after each test 265 */ 266 @After cleanup()267 public void cleanup() { 268 validateMockitoUsage(); 269 if (mSession != null) { 270 mSession.finishMocking(); 271 } 272 } 273 274 /** 275 * Verify that no write occurs if there is {@link StoreData} registered for any 276 * {@link StoreFile}. 277 * 278 * @throws Exception 279 */ 280 @Test testWriteWithNoStoreData()281 public void testWriteWithNoStoreData() throws Exception { 282 // Perform force write to both share and user store file. 283 mWifiConfigStore.setUserStores(mUserStores); 284 mWifiConfigStore.write(true); 285 286 assertFalse(mSharedStore.isStoreWritten()); 287 assertFalse(mUserStore.isStoreWritten()); 288 assertFalse(mUserNetworkSuggestionsStore.isStoreWritten()); 289 290 verify(mWifiMetrics, never()).noteWifiConfigStoreWriteDuration(anyInt()); 291 } 292 293 /** 294 * Tests the write API with the force flag set to true. 295 * Expected behavior: This should trigger an immediate write to the store files and no alarms 296 * should be started. 297 */ 298 @Test testForceWrite()299 public void testForceWrite() throws Exception { 300 // Register data container. 301 mWifiConfigStore.registerStoreData(mSharedStoreData); 302 mWifiConfigStore.registerStoreData(mUserStoreData); 303 304 mWifiConfigStore.switchUserStoresAndRead(mUserStores); 305 mWifiConfigStore.write(true); 306 307 assertFalse(mAlarmManager.isPending(WifiConfigStore.BUFFERED_WRITE_ALARM_TAG)); 308 assertTrue(mSharedStore.isStoreWritten()); 309 assertTrue(mUserStore.isStoreWritten()); 310 assertFalse(mUserNetworkSuggestionsStore.isStoreWritten()); 311 312 verify(mWifiMetrics).noteWifiConfigStoreWriteDuration(anyInt()); 313 } 314 315 /** 316 * Tests the write API with the force flag set to false. 317 * Expected behavior: This should set an alarm to write to the store files. 318 */ 319 @Test testBufferedWrite()320 public void testBufferedWrite() throws Exception { 321 // Register data container. 322 mWifiConfigStore.registerStoreData(mSharedStoreData); 323 mWifiConfigStore.registerStoreData(mUserStoreData); 324 325 mWifiConfigStore.switchUserStoresAndRead(mUserStores); 326 mWifiConfigStore.write(false); 327 328 assertTrue(mAlarmManager.isPending(WifiConfigStore.BUFFERED_WRITE_ALARM_TAG)); 329 assertFalse(mSharedStore.isStoreWritten()); 330 assertFalse(mUserStore.isStoreWritten()); 331 assertFalse(mUserNetworkSuggestionsStore.isStoreWritten()); 332 333 // Now send the alarm and ensure that the writes happen. 334 mAlarmManager.dispatch(WifiConfigStore.BUFFERED_WRITE_ALARM_TAG); 335 mLooper.dispatchAll(); 336 assertTrue(mSharedStore.isStoreWritten()); 337 assertTrue(mUserStore.isStoreWritten()); 338 assertFalse(mUserNetworkSuggestionsStore.isStoreWritten()); 339 340 verify(mWifiMetrics).noteWifiConfigStoreWriteDuration(anyInt()); 341 } 342 343 /** 344 * Tests the force write after a buffered write. 345 * Expected behaviour: The force write should override the previous buffered write and stop the 346 * buffer write alarms. 347 */ 348 @Test testForceWriteAfterBufferedWrite()349 public void testForceWriteAfterBufferedWrite() throws Exception { 350 // Register a test data container with bogus data. 351 mWifiConfigStore.registerStoreData(mSharedStoreData); 352 mWifiConfigStore.registerStoreData(mUserStoreData); 353 354 mSharedStoreData.setData("abcds"); 355 mUserStoreData.setData("asdfa"); 356 357 // Perform buffered write for both user and share store file. 358 mWifiConfigStore.switchUserStoresAndRead(mUserStores); 359 mWifiConfigStore.write(false); 360 361 assertTrue(mAlarmManager.isPending(WifiConfigStore.BUFFERED_WRITE_ALARM_TAG)); 362 assertFalse(mSharedStore.isStoreWritten()); 363 assertFalse(mUserStore.isStoreWritten()); 364 365 // Update the container with new set of data. The send a force write and ensure that the 366 // writes have been performed and alarms have been stopped and updated data are written. 367 mUserStoreData.setData(TEST_USER_DATA); 368 mSharedStoreData.setData(TEST_SHARE_DATA); 369 mWifiConfigStore.write(true); 370 371 assertFalse(mAlarmManager.isPending(WifiConfigStore.BUFFERED_WRITE_ALARM_TAG)); 372 assertTrue(mSharedStore.isStoreWritten()); 373 assertTrue(mUserStore.isStoreWritten()); 374 375 // Verify correct data are loaded to the data container after a read. 376 mWifiConfigStore.read(); 377 assertEquals(TEST_USER_DATA, mUserStoreData.getData()); 378 assertEquals(TEST_SHARE_DATA, mSharedStoreData.getData()); 379 } 380 381 /** 382 * Tests the force write with no new data after a buffered write. 383 * Expected behaviour: The force write should flush the previous buffered write and stop the 384 * buffer write alarms. 385 */ 386 @Test testForceWriteWithNoNewDataAfterBufferedWrite()387 public void testForceWriteWithNoNewDataAfterBufferedWrite() throws Exception { 388 // Register a test data container with bogus data. 389 mWifiConfigStore.registerStoreData(mSharedStoreData); 390 mWifiConfigStore.registerStoreData(mUserStoreData); 391 392 mSharedStoreData.setData("abcds"); 393 mUserStoreData.setData("asdfa"); 394 395 // Perform buffered write for both user and share store file. 396 mWifiConfigStore.switchUserStoresAndRead(mUserStores); 397 mWifiConfigStore.write(false); 398 399 assertTrue(mAlarmManager.isPending(WifiConfigStore.BUFFERED_WRITE_ALARM_TAG)); 400 assertFalse(mSharedStore.isStoreWritten()); 401 assertFalse(mUserStore.isStoreWritten()); 402 403 // Containers have no new data. 404 mUserStoreData.setHasAnyNewData(false); 405 mSharedStoreData.setHasAnyNewData(false); 406 mWifiConfigStore.write(true); 407 408 assertFalse(mAlarmManager.isPending(WifiConfigStore.BUFFERED_WRITE_ALARM_TAG)); 409 assertTrue(mSharedStore.isStoreWritten()); 410 assertTrue(mUserStore.isStoreWritten()); 411 412 // Verify correct data are loaded to the data container after a read. 413 mWifiConfigStore.read(); 414 assertEquals("abcds", mSharedStoreData.getData()); 415 assertEquals("asdfa", mUserStoreData.getData()); 416 } 417 418 419 /** 420 * Tests the read API behaviour after a write to the store files. 421 * Expected behaviour: The read should return the same data that was last written. 422 */ 423 @Test testReadAfterWrite()424 public void testReadAfterWrite() throws Exception { 425 // Register data container. 426 mWifiConfigStore.registerStoreData(mSharedStoreData); 427 mWifiConfigStore.registerStoreData(mUserStoreData); 428 429 // Read both share and user config store. 430 mWifiConfigStore.switchUserStoresAndRead(mUserStores); 431 432 // Verify no data is read. 433 assertNull(mUserStoreData.getData()); 434 assertNull(mSharedStoreData.getData()); 435 436 // Write share and user data. 437 mUserStoreData.setData(TEST_USER_DATA); 438 mSharedStoreData.setData(TEST_SHARE_DATA); 439 mWifiConfigStore.write(true); 440 441 // Read and verify the data content in the data container. 442 mWifiConfigStore.read(); 443 assertEquals(TEST_USER_DATA, mUserStoreData.getData()); 444 assertEquals(TEST_SHARE_DATA, mSharedStoreData.getData()); 445 446 verify(mWifiMetrics, times(2)).noteWifiConfigStoreReadDuration(anyInt()); 447 verify(mWifiMetrics).noteWifiConfigStoreWriteDuration(anyInt()); 448 } 449 450 /** 451 * Tests the read API behaviour when the shared store file is empty and the user store 452 * is not yet visible (user not yet unlocked). 453 * Expected behaviour: The read should return an empty store data instance when the file not 454 * found exception is raised. 455 */ 456 @Test testReadWithNoSharedStoreFileAndUserStoreNotVisible()457 public void testReadWithNoSharedStoreFileAndUserStoreNotVisible() throws Exception { 458 StoreData sharedStoreData = mock(StoreData.class); 459 when(sharedStoreData.getStoreFileId()) 460 .thenReturn(WifiConfigStore.STORE_FILE_SHARED_GENERAL); 461 StoreData userStoreData = mock(StoreData.class); 462 when(userStoreData.getStoreFileId()) 463 .thenReturn(WifiConfigStore.STORE_FILE_USER_GENERAL); 464 465 // Reading the mock store without a write should simulate the file not found case because 466 // |readRawData| would return null. 467 mWifiConfigStore.registerStoreData(sharedStoreData); 468 mWifiConfigStore.registerStoreData(userStoreData); 469 mWifiConfigStore.read(); 470 471 // Ensure that we got the call to deserialize empty shared data, but no user data. 472 verify(sharedStoreData).resetData(); 473 verify(sharedStoreData).deserializeData(eq(null), anyInt(), anyInt(), any()); 474 verify(userStoreData, never()).resetData(); 475 verify(userStoreData, never()).deserializeData(any(), anyInt(), anyInt(), any()); 476 } 477 478 /** 479 * Tests the read API behaviour when there are no user/shared store files on the device. 480 * Expected behaviour: The read should return an empty store data instance when the file not 481 * found exception is raised. 482 */ 483 @Test testReadWithNoStoreFiles()484 public void testReadWithNoStoreFiles() throws Exception { 485 StoreData sharedStoreData = mock(StoreData.class); 486 when(sharedStoreData.getStoreFileId()) 487 .thenReturn(WifiConfigStore.STORE_FILE_SHARED_GENERAL); 488 StoreData userStoreData = mock(StoreData.class); 489 when(userStoreData.getStoreFileId()) 490 .thenReturn(WifiConfigStore.STORE_FILE_USER_GENERAL); 491 492 // Reading the mock store without a write should simulate the file not found case because 493 // |readRawData| would return null. 494 mWifiConfigStore.registerStoreData(sharedStoreData); 495 mWifiConfigStore.registerStoreData(userStoreData); 496 // Read both share and user config store. 497 mWifiConfigStore.setUserStores(mUserStores); 498 mWifiConfigStore.read(); 499 500 // Ensure that we got the call to deserialize empty shared & user data. 501 verify(userStoreData).resetData(); 502 verify(userStoreData).deserializeData(eq(null), anyInt(), anyInt(), any()); 503 verify(sharedStoreData).resetData(); 504 verify(sharedStoreData).deserializeData(eq(null), anyInt(), anyInt(), any()); 505 } 506 507 /** 508 * Tests the read API behaviour after a write to the shared store file when the user 509 * store file is null. 510 * Expected behaviour: The read should return the same data that was last written. 511 */ 512 @Test testReadAfterWriteWithNoUserStore()513 public void testReadAfterWriteWithNoUserStore() throws Exception { 514 // Setup data container. 515 mWifiConfigStore.registerStoreData(mSharedStoreData); 516 mSharedStoreData.setData(TEST_SHARE_DATA); 517 518 // Perform write for the share store file. 519 mWifiConfigStore.write(true); 520 mWifiConfigStore.read(); 521 // Verify data content for both user and share data. 522 assertEquals(TEST_SHARE_DATA, mSharedStoreData.getData()); 523 } 524 525 /** 526 * Verifies that a read operation will reset the data in the data container, to avoid 527 * any stale data from previous read. 528 * 529 * @throws Exception 530 */ 531 @Test testReadWillResetStoreData()532 public void testReadWillResetStoreData() throws Exception { 533 // Register and setup store data. 534 mWifiConfigStore.registerStoreData(mSharedStoreData); 535 mWifiConfigStore.registerStoreData(mUserStoreData); 536 537 // Perform force write with empty data content to both user and share store file. 538 mWifiConfigStore.switchUserStoresAndRead(mUserStores); 539 mWifiConfigStore.write(true); 540 541 // Setup data container with some value. 542 mUserStoreData.setData(TEST_USER_DATA); 543 mSharedStoreData.setData(TEST_SHARE_DATA); 544 545 // Perform read of both user and share store file and verify data in the data container 546 // is in sync (empty) with what is in the file. 547 mWifiConfigStore.read(); 548 assertNull(mSharedStoreData.getData()); 549 assertNull(mUserStoreData.getData()); 550 } 551 552 /** 553 * Verify that a store file contained WiFi configuration store data (network list and 554 * deleted ephemeral SSID list) using the predefined test XML data is read and parsed 555 * correctly. 556 * 557 * @throws Exception 558 */ 559 @Test testReadWifiConfigStoreData()560 public void testReadWifiConfigStoreData() throws Exception { 561 // Setup network list. 562 NetworkListStoreData networkList = new NetworkListUserStoreData(mContext); 563 mWifiConfigStore.registerStoreData(networkList); 564 WifiConfiguration openNetwork = WifiConfigurationTestUtil.createOpenNetwork(); 565 openNetwork.creatorName = TEST_CREATOR_NAME; 566 openNetwork.setIpConfiguration( 567 WifiConfigurationTestUtil.createDHCPIpConfigurationWithNoProxy()); 568 openNetwork.setRandomizedMacAddress(TEST_RANDOMIZED_MAC); 569 List<WifiConfiguration> userConfigs = new ArrayList<>(); 570 openNetwork.subscriptionId = TEST_SUB_ID; 571 userConfigs.add(openNetwork); 572 573 // Setup user store XML bytes. 574 String xmlString = String.format(TEST_DATA_XML_STRING_FORMAT, 575 openNetwork.getKey().replaceAll("\"", """), 576 openNetwork.SSID.replaceAll("\"", """), 577 openNetwork.shared, openNetwork.creatorUid, openNetwork.creatorName, 578 openNetwork.getRandomizedMacAddress(), openNetwork.subscriptionId); 579 byte[] xmlBytes = xmlString.getBytes(StandardCharsets.UTF_8); 580 mUserStore.storeRawDataToWrite(xmlBytes); 581 582 mWifiConfigStore.switchUserStoresAndRead(mUserStores); 583 WifiConfigurationTestUtil.assertConfigurationsEqualForConfigStore( 584 userConfigs, networkList.getConfigurations()); 585 } 586 587 /** 588 * Verify that the WiFi configuration store data containing network list and deleted 589 * ephemeral SSID list are serialized correctly, matches the predefined test XML data. 590 * 591 * @throws Exception 592 */ 593 @Test testWriteWifiConfigStoreData()594 public void testWriteWifiConfigStoreData() throws Exception { 595 // Setup user store. 596 mWifiConfigStore.switchUserStoresAndRead(mUserStores); 597 598 // Setup network list store data. 599 NetworkListStoreData networkList = new NetworkListUserStoreData(mContext); 600 mWifiConfigStore.registerStoreData(networkList); 601 WifiConfiguration openNetwork = WifiConfigurationTestUtil.createOpenOweNetwork(); 602 openNetwork.creatorName = TEST_CREATOR_NAME; 603 openNetwork.setIpConfiguration( 604 WifiConfigurationTestUtil.createDHCPIpConfigurationWithNoProxy()); 605 openNetwork.setRandomizedMacAddress(TEST_RANDOMIZED_MAC); 606 openNetwork.subscriptionId = TEST_SUB_ID; 607 List<WifiConfiguration> userConfigs = new ArrayList<>(); 608 userConfigs.add(openNetwork); 609 networkList.setConfigurations(userConfigs); 610 611 // Setup expected XML bytes. 612 String xmlString = String.format(TEST_DATA_XML_STRING_FORMAT, 613 openNetwork.getKey().replaceAll("\"", """), 614 openNetwork.SSID.replaceAll("\"", """), 615 openNetwork.shared, openNetwork.creatorUid, openNetwork.creatorName, 616 openNetwork.getRandomizedMacAddress(), openNetwork.subscriptionId); 617 618 mWifiConfigStore.write(true); 619 // Verify the user store content. 620 assertEquals(xmlString, new String(mUserStore.getStoreBytes())); 621 } 622 623 /** 624 * Verify that a store file contained WiFi configuration store data (network list and 625 * deleted ephemeral SSID list) using the predefined test XML data is read and parsed 626 * correctly. 627 * 628 * @throws Exception 629 */ 630 @Test testReadWifiConfigStoreDataIndicateClientsThatThereIsNoDataForThem()631 public void testReadWifiConfigStoreDataIndicateClientsThatThereIsNoDataForThem() 632 throws Exception { 633 // Set both the user store & shared store files. 634 mWifiConfigStore.switchUserStoresAndRead(mUserStores); 635 636 String storeData1Name = "test1"; 637 String storeData2Name = "test2"; 638 StoreData storeData1 = mock(StoreData.class); 639 StoreData storeData2 = mock(StoreData.class); 640 641 assertTrue(mWifiConfigStore.registerStoreData(storeData1)); 642 assertTrue(mWifiConfigStore.registerStoreData(storeData2)); 643 644 String fileContentsXmlStringWithOnlyStoreData1 = 645 String.format(TEST_DATA_XML_STRING_FORMAT_V1_WITH_ONE_DATA_SOURCE, storeData1Name); 646 String fileContentsXmlStringWithOnlyStoreData2 = 647 String.format(TEST_DATA_XML_STRING_FORMAT_V1_WITH_ONE_DATA_SOURCE, storeData2Name); 648 String fileContentsXmlStringWithStoreData1AndStoreData2 = 649 String.format(TEST_DATA_XML_STRING_FORMAT_V1_WITH_TWO_DATA_SOURCE, 650 storeData1Name, storeData2Name); 651 652 // Scenario 1: StoreData1 in shared store file. 653 when(storeData1.getName()).thenReturn(storeData1Name); 654 when(storeData2.getName()).thenReturn(storeData2Name); 655 when(storeData1.getSectionsToParse()) 656 .thenReturn(new HashSet<>(Collections.singleton(storeData1Name))); 657 when(storeData2.getSectionsToParse()) 658 .thenReturn(new HashSet<>(Collections.singleton(storeData2Name))); 659 when(storeData1.getStoreFileId()) 660 .thenReturn(WifiConfigStore.STORE_FILE_SHARED_GENERAL); 661 when(storeData2.getStoreFileId()) 662 .thenReturn(WifiConfigStore.STORE_FILE_SHARED_GENERAL); 663 mSharedStore.storeRawDataToWrite(fileContentsXmlStringWithOnlyStoreData1.getBytes()); 664 mUserStore.storeRawDataToWrite(null); 665 666 mWifiConfigStore.read(); 667 verify(storeData1) 668 .deserializeDataForSection(notNull(), anyInt(), anyInt(), any(), anyString()); 669 verify(storeData1, never()).deserializeData(eq(null), anyInt(), anyInt(), any()); 670 verify(storeData2).deserializeData(eq(null), anyInt(), anyInt(), any()); 671 reset(storeData1, storeData2); 672 673 // Scenario 2: StoreData2 in user store file. 674 when(storeData1.getName()).thenReturn(storeData1Name); 675 when(storeData2.getName()).thenReturn(storeData2Name); 676 when(storeData1.getSectionsToParse()) 677 .thenReturn(new HashSet<>(Collections.singleton(storeData1Name))); 678 when(storeData2.getSectionsToParse()) 679 .thenReturn(new HashSet<>(Collections.singleton(storeData2Name))); 680 when(storeData1.getStoreFileId()) 681 .thenReturn(WifiConfigStore.STORE_FILE_USER_GENERAL); 682 when(storeData2.getStoreFileId()) 683 .thenReturn(WifiConfigStore.STORE_FILE_USER_GENERAL); 684 mSharedStore.storeRawDataToWrite(null); 685 mUserStore.storeRawDataToWrite(fileContentsXmlStringWithOnlyStoreData2.getBytes()); 686 687 mWifiConfigStore.read(); 688 verify(storeData1).deserializeData(eq(null), anyInt(), anyInt(), any()); 689 verify(storeData2) 690 .deserializeDataForSection(notNull(), anyInt(), anyInt(), any(), anyString()); 691 verify(storeData2, never()).deserializeData(eq(null), anyInt(), anyInt(), any()); 692 reset(storeData1, storeData2); 693 694 // Scenario 3: StoreData1 in shared store file & StoreData2 in user store file. 695 when(storeData1.getName()).thenReturn(storeData1Name); 696 when(storeData2.getName()).thenReturn(storeData2Name); 697 when(storeData1.getSectionsToParse()) 698 .thenReturn(new HashSet<>(Collections.singleton(storeData1Name))); 699 when(storeData2.getSectionsToParse()) 700 .thenReturn(new HashSet<>(Collections.singleton(storeData2Name))); 701 when(storeData1.getStoreFileId()) 702 .thenReturn(WifiConfigStore.STORE_FILE_SHARED_GENERAL); 703 when(storeData2.getStoreFileId()) 704 .thenReturn(WifiConfigStore.STORE_FILE_USER_GENERAL); 705 mSharedStore.storeRawDataToWrite(fileContentsXmlStringWithOnlyStoreData1.getBytes()); 706 mUserStore.storeRawDataToWrite(fileContentsXmlStringWithOnlyStoreData2.getBytes()); 707 708 mWifiConfigStore.read(); 709 verify(storeData1) 710 .deserializeDataForSection(notNull(), anyInt(), anyInt(), any(), anyString()); 711 verify(storeData1, never()).deserializeData(eq(null), anyInt(), anyInt(), any()); 712 verify(storeData2) 713 .deserializeDataForSection(notNull(), anyInt(), anyInt(), any(), anyString()); 714 verify(storeData2, never()).deserializeData(eq(null), anyInt(), anyInt(), any()); 715 reset(storeData1, storeData2); 716 717 // Scenario 4: StoreData1 & StoreData2 in shared store file. 718 when(storeData1.getName()).thenReturn(storeData1Name); 719 when(storeData2.getName()).thenReturn(storeData2Name); 720 when(storeData1.getSectionsToParse()) 721 .thenReturn(new HashSet<>(Collections.singleton(storeData1Name))); 722 when(storeData2.getSectionsToParse()) 723 .thenReturn(new HashSet<>(Collections.singleton(storeData2Name))); 724 when(storeData1.getStoreFileId()) 725 .thenReturn(WifiConfigStore.STORE_FILE_SHARED_GENERAL); 726 when(storeData2.getStoreFileId()) 727 .thenReturn(WifiConfigStore.STORE_FILE_SHARED_GENERAL); 728 mSharedStore.storeRawDataToWrite( 729 fileContentsXmlStringWithStoreData1AndStoreData2.getBytes()); 730 mUserStore.storeRawDataToWrite(null); 731 732 mWifiConfigStore.read(); 733 verify(storeData1) 734 .deserializeDataForSection(notNull(), anyInt(), anyInt(), any(), anyString()); 735 verify(storeData1, never()).deserializeData(eq(null), anyInt(), anyInt(), any()); 736 verify(storeData2) 737 .deserializeDataForSection(notNull(), anyInt(), anyInt(), any(), anyString()); 738 verify(storeData2, never()).deserializeData(eq(null), anyInt(), anyInt(), any()); 739 reset(storeData1, storeData2); 740 } 741 742 /** 743 * Tests the write API behavior when all the store data's registered for a given store file 744 * has no new data to write. 745 * Expected behaviour: The write should not trigger a new file write for that specific store 746 * file. 747 */ 748 @Test testWriteWithNoNewData()749 public void testWriteWithNoNewData() throws Exception { 750 StoreData sharedStoreData = mock(StoreData.class); 751 when(sharedStoreData.getStoreFileId()) 752 .thenReturn(WifiConfigStore.STORE_FILE_SHARED_GENERAL); 753 when(sharedStoreData.hasNewDataToSerialize()).thenReturn(true); 754 when(sharedStoreData.getName()).thenReturn("sharedStoreData"); 755 756 StoreData userStoreData = mock(StoreData.class); 757 when(userStoreData.getStoreFileId()) 758 .thenReturn(WifiConfigStore.STORE_FILE_USER_GENERAL); 759 when(userStoreData.hasNewDataToSerialize()).thenReturn(true); 760 when(userStoreData.getName()).thenReturn("userStoreData"); 761 762 StoreData userStoreNetworkSuggestionsData = 763 mock(StoreData.class); 764 when(userStoreNetworkSuggestionsData.getStoreFileId()) 765 .thenReturn(WifiConfigStore.STORE_FILE_USER_NETWORK_SUGGESTIONS); 766 when(userStoreNetworkSuggestionsData.hasNewDataToSerialize()).thenReturn(false); 767 when(userStoreNetworkSuggestionsData.getName()) 768 .thenReturn("userStoreNetworkSuggestionsData"); 769 770 assertTrue(mWifiConfigStore.registerStoreData(sharedStoreData)); 771 assertTrue(mWifiConfigStore.registerStoreData(userStoreData)); 772 assertTrue(mWifiConfigStore.registerStoreData(userStoreNetworkSuggestionsData)); 773 774 // Write both share and user config store. 775 mWifiConfigStore.setUserStores(mUserStores); 776 777 // Now trigger a write. 778 mWifiConfigStore.write(true); 779 780 verify(sharedStoreData).hasNewDataToSerialize(); 781 verify(userStoreData).hasNewDataToSerialize(); 782 verify(userStoreNetworkSuggestionsData).hasNewDataToSerialize(); 783 784 // Verify that we serialized data from the first 2 data source, but not from the last one. 785 verify(sharedStoreData).serializeData(any(), any()); 786 verify(userStoreData).serializeData(any(), any()); 787 verify(userStoreNetworkSuggestionsData, never()).serializeData(any(), any()); 788 } 789 790 /** 791 * Verify that we gracefully skip unknown section when reading an user store file. 792 */ 793 @Test testReadUserStoreContainedUnknownSection()794 public void testReadUserStoreContainedUnknownSection() throws Exception { 795 String storeFileData = 796 "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n" 797 + "<WifiConfigStoreData>\n" 798 + "<int name=\"Version\" value=\"1\" />\n" 799 + "<UnknownTag>\n" // No StoreData registered to handle this tag. 800 + "</UnknownTag>\n" 801 + "</WifiConfigStoreData>\n"; 802 mUserStore.storeRawDataToWrite(storeFileData.getBytes(StandardCharsets.UTF_8)); 803 mWifiConfigStore.switchUserStoresAndRead(mUserStores); 804 } 805 806 /** 807 * Verify that we gracefully skip unknown section when reading a shared store file. 808 */ 809 @Test testReadShareStoreContainedUnknownSection()810 public void testReadShareStoreContainedUnknownSection() throws Exception { 811 String storeFileData = 812 "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n" 813 + "<WifiConfigStoreData>\n" 814 + "<int name=\"Version\" value=\"1\" />\n" 815 + "<UnknownTag>\n" // No StoreData registered to handle this tag. 816 + "</UnknownTag>\n" 817 + "</WifiConfigStoreData>\n"; 818 mSharedStore.storeRawDataToWrite(storeFileData.getBytes(StandardCharsets.UTF_8)); 819 mWifiConfigStore.read(); 820 } 821 822 /** 823 * Tests the read API behaviour when the config store file is version 1. 824 * Expected behaviour: The read should be successful and send the data to the corresponding 825 * {@link StoreData} instance. 826 */ 827 @Test testReadVersion1StoreFile()828 public void testReadVersion1StoreFile() throws Exception { 829 // Register data container. 830 StoreData sharedStoreData = mock(StoreData.class); 831 when(sharedStoreData.getStoreFileId()) 832 .thenReturn(WifiConfigStore.STORE_FILE_SHARED_GENERAL); 833 when(sharedStoreData.getName()).thenReturn(TEST_SHARE_DATA); 834 when(sharedStoreData.getSectionsToParse()) 835 .thenReturn(new HashSet<>(Collections.singleton(TEST_SHARE_DATA))); 836 StoreData userStoreData = mock(StoreData.class); 837 when(userStoreData.getStoreFileId()) 838 .thenReturn(WifiConfigStore.STORE_FILE_USER_GENERAL); 839 when(userStoreData.getName()).thenReturn(TEST_USER_DATA); 840 when(userStoreData.getSectionsToParse()) 841 .thenReturn(new HashSet<>(Collections.singleton(TEST_USER_DATA))); 842 mWifiConfigStore.registerStoreData(sharedStoreData); 843 mWifiConfigStore.registerStoreData(userStoreData); 844 845 // Read both share and user config store. 846 mWifiConfigStore.setUserStores(mUserStores); 847 848 // Now store some content in the shared and user data files. 849 mUserStore.storeRawDataToWrite( 850 String.format(TEST_DATA_XML_STRING_FORMAT_V1_WITH_ONE_DATA_SOURCE, 851 TEST_USER_DATA).getBytes()); 852 mSharedStore.storeRawDataToWrite( 853 String.format(TEST_DATA_XML_STRING_FORMAT_V1_WITH_ONE_DATA_SOURCE, 854 TEST_SHARE_DATA).getBytes()); 855 856 // Read and verify the data content in the store file (metadata stripped out) has been sent 857 // to the corresponding store data when integrity check passes. 858 mWifiConfigStore.read(); 859 verify(sharedStoreData, times(1)).deserializeDataForSection( 860 any(XmlPullParser.class), anyInt(), 861 eq(WifiConfigStore.INITIAL_CONFIG_STORE_DATA_VERSION), any(), eq(TEST_SHARE_DATA)); 862 verify(userStoreData, times(1)).deserializeDataForSection( 863 any(XmlPullParser.class), anyInt(), 864 eq(WifiConfigStore.INITIAL_CONFIG_STORE_DATA_VERSION), any(), eq(TEST_USER_DATA)); 865 } 866 867 /** 868 * Tests the read API behaviour to ensure that the integrity data is parsed from the file. 869 */ 870 @Test testReadVersion2StoreFile()871 public void testReadVersion2StoreFile() throws Exception { 872 byte[] encryptedData = new byte[0]; 873 byte[] iv = new byte[0]; 874 Random random = new Random(); 875 random.nextBytes(encryptedData); 876 random.nextBytes(iv); 877 878 // Register data container. 879 StoreData sharedStoreData = mock(StoreData.class); 880 when(sharedStoreData.getStoreFileId()) 881 .thenReturn(WifiConfigStore.STORE_FILE_SHARED_GENERAL); 882 when(sharedStoreData.getName()).thenReturn(TEST_SHARE_DATA); 883 when(sharedStoreData.getSectionsToParse()) 884 .thenReturn(new HashSet<>(Collections.singleton(TEST_SHARE_DATA))); 885 when(sharedStoreData.hasNewDataToSerialize()).thenReturn(true); 886 StoreData userStoreData = mock(StoreData.class); 887 when(userStoreData.getStoreFileId()) 888 .thenReturn(WifiConfigStore.STORE_FILE_USER_GENERAL); 889 when(userStoreData.getName()).thenReturn(TEST_USER_DATA); 890 when(userStoreData.getSectionsToParse()) 891 .thenReturn(new HashSet<>(Collections.singleton(TEST_USER_DATA))); 892 when(userStoreData.hasNewDataToSerialize()).thenReturn(true); 893 mWifiConfigStore.registerStoreData(sharedStoreData); 894 mWifiConfigStore.registerStoreData(userStoreData); 895 896 // Read both share and user config store. 897 mWifiConfigStore.setUserStores(mUserStores); 898 899 // Now store some content in the shared and user data files with encrypted data from above. 900 mUserStore.storeRawDataToWrite( 901 String.format(TEST_DATA_XML_STRING_FORMAT_V2_WITH_ONE_DATA_SOURCE, 902 HexEncoding.encodeToString(encryptedData), 903 HexEncoding.encodeToString(iv), 904 TEST_USER_DATA).getBytes()); 905 mSharedStore.storeRawDataToWrite( 906 String.format(TEST_DATA_XML_STRING_FORMAT_V2_WITH_ONE_DATA_SOURCE, 907 HexEncoding.encodeToString(encryptedData), 908 HexEncoding.encodeToString(iv), 909 TEST_SHARE_DATA).getBytes()); 910 911 // Read and verify the data content in the store file (metadata stripped out) has been sent 912 // to the corresponding store data. 913 mWifiConfigStore.read(); 914 verify(sharedStoreData, times(1)) 915 .deserializeDataForSection(any(XmlPullParser.class), anyInt(), 916 eq(WifiConfigStore.INTEGRITY_CONFIG_STORE_DATA_VERSION), any(), 917 eq(TEST_SHARE_DATA)); 918 verify(userStoreData, times(1)) 919 .deserializeDataForSection(any(XmlPullParser.class), anyInt(), 920 eq(WifiConfigStore.INTEGRITY_CONFIG_STORE_DATA_VERSION), any(), 921 eq(TEST_USER_DATA)); 922 } 923 924 /** 925 * Tests the complete migration path all the way from reading from the migration stream to 926 * parsing the XML data and sending it to the appropriate registered data sources. 927 */ 928 @Test testMigration()929 public void testMigration() throws Exception { 930 // Setup both shared & user store migrations. 931 StoreFile sharedStoreFile1 = mock(StoreFile.class); 932 when(sharedStoreFile1.getFileId()) 933 .thenReturn(WifiConfigStore.STORE_FILE_SHARED_GENERAL); 934 StoreFile sharedStoreFile2 = mock(StoreFile.class); 935 when(sharedStoreFile2.getFileId()) 936 .thenReturn(WifiConfigStore.STORE_FILE_SHARED_SOFTAP); 937 StoreFile userStoreFile1 = mock(StoreFile.class); 938 when(userStoreFile1.getFileId()) 939 .thenReturn(WifiConfigStore.STORE_FILE_USER_GENERAL); 940 StoreFile userStoreFile2 = mock(StoreFile.class); 941 when(userStoreFile2.getFileId()) 942 .thenReturn(WifiConfigStore.STORE_FILE_USER_NETWORK_SUGGESTIONS); 943 mWifiConfigStore = new WifiConfigStore(mContext, new Handler(mLooper.getLooper()), mClock, 944 mWifiMetrics, Arrays.asList(sharedStoreFile1, sharedStoreFile2)); 945 mWifiConfigStore.setUserStores(Arrays.asList(userStoreFile1, userStoreFile2)); 946 947 // Register data container. 948 StoreData sharedStoreData = mock(StoreData.class); 949 when(sharedStoreData.getStoreFileId()) 950 .thenReturn(WifiConfigStore.STORE_FILE_SHARED_GENERAL); 951 when(sharedStoreData.getName()).thenReturn(TEST_SHARE_DATA); 952 when(sharedStoreData.getSectionsToParse()) 953 .thenReturn(new HashSet<>(Collections.singleton(TEST_SHARE_DATA))); 954 StoreData userStoreData = mock(StoreData.class); 955 when(userStoreData.getStoreFileId()) 956 .thenReturn(WifiConfigStore.STORE_FILE_USER_GENERAL); 957 when(userStoreData.getName()).thenReturn(TEST_USER_DATA); 958 when(userStoreData.getSectionsToParse()) 959 .thenReturn(new HashSet<>(Collections.singleton(TEST_USER_DATA))); 960 mWifiConfigStore.registerStoreData(sharedStoreData); 961 mWifiConfigStore.registerStoreData(userStoreData); 962 963 // Migration data 964 InputStream sharedStream1 = mock(InputStream.class); 965 InputStream sharedStream2 = mock(InputStream.class); 966 InputStream userStream1 = mock(InputStream.class); 967 InputStream userStream2 = mock(InputStream.class); 968 when(WifiMigration.convertAndRetrieveSharedConfigStoreFile( 969 WifiMigration.STORE_FILE_SHARED_GENERAL)) 970 .thenReturn(sharedStream1); 971 when(WifiMigration.convertAndRetrieveSharedConfigStoreFile( 972 WifiMigration.STORE_FILE_SHARED_SOFTAP)) 973 .thenReturn(sharedStream2); 974 when(WifiMigration.convertAndRetrieveUserConfigStoreFile( 975 eq(WifiMigration.STORE_FILE_USER_GENERAL), any())) 976 .thenReturn(userStream1); 977 when(WifiMigration.convertAndRetrieveUserConfigStoreFile( 978 eq(WifiMigration.STORE_FILE_USER_NETWORK_SUGGESTIONS), any())) 979 .thenReturn(userStream2); 980 981 byte[] sharedStoreXmlBytes = 982 String.format(TEST_DATA_XML_STRING_FORMAT_V3_WITH_ONE_DATA_SOURCE, 983 TEST_SHARE_DATA).getBytes(); 984 byte[] userStoreXmlBytes = 985 String.format(TEST_DATA_XML_STRING_FORMAT_V3_WITH_ONE_DATA_SOURCE, 986 TEST_USER_DATA).getBytes(); 987 when(sharedStream1.available()) 988 .thenReturn(sharedStoreXmlBytes.length) // first time return file contents, then 0. 989 .thenReturn(0); 990 when(sharedStream2.available()) 991 .thenReturn(sharedStoreXmlBytes.length) // first time return file contents, then 0. 992 .thenReturn(0); 993 when(userStream1.available()) 994 .thenReturn(userStoreXmlBytes.length) // first time return file contents, then 0. 995 .thenReturn(0); 996 when(userStream2.available()) 997 .thenReturn(userStoreXmlBytes.length) // first time return file contents, then 0. 998 .thenReturn(0); 999 Answer sharedStreamReadAnswer = new MockAnswerUtil.AnswerWithArguments() { 1000 public int answer(byte[] b, int off, int len) { 1001 System.arraycopy(sharedStoreXmlBytes, 0, b, 0, sharedStoreXmlBytes.length); 1002 return sharedStoreXmlBytes.length; 1003 } 1004 }; 1005 Answer userStreamReadAnswer = new MockAnswerUtil.AnswerWithArguments() { 1006 public int answer(byte[] b, int off, int len) { 1007 System.arraycopy(userStoreXmlBytes, 0, b, 0, userStoreXmlBytes.length); 1008 return userStoreXmlBytes.length; 1009 } 1010 }; 1011 when(sharedStream1.read(any(byte[].class), anyInt(), anyInt())) 1012 .thenAnswer(sharedStreamReadAnswer) // first time return file contents, then 0. 1013 .thenReturn(0); 1014 when(sharedStream2.read(any(byte[].class), anyInt(), anyInt())) 1015 .thenAnswer(sharedStreamReadAnswer) // first time return file contents, then 0. 1016 .thenReturn(0); 1017 when(userStream1.read(any(byte[].class), anyInt(), anyInt())) 1018 .thenAnswer(userStreamReadAnswer) // first time return file contents, then 0. 1019 .thenReturn(0); 1020 when(userStream2.read(any(byte[].class), anyInt(), anyInt())) 1021 .thenAnswer(userStreamReadAnswer) // first time return file contents, then 0. 1022 .thenReturn(0); 1023 1024 // Trigger read. 1025 mWifiConfigStore.read(); 1026 1027 // Verify that we read the data out of all the migration streams & we didn't read 1028 // from the files on disk. 1029 verify(sharedStream1, times(2)).available(); 1030 verify(sharedStream1, times(2)).read(any(), anyInt(), anyInt()); 1031 verify(sharedStream2, times(2)).available(); 1032 verify(sharedStream2, times(2)).read(any(), anyInt(), anyInt()); 1033 verify(userStream1, times(2)).available(); 1034 verify(userStream1, times(2)).read(any(), anyInt(), anyInt()); 1035 verify(userStream2, times(2)).available(); 1036 verify(userStream2, times(2)).read(any(), anyInt(), anyInt()); 1037 1038 // Verify that we correctly deserialized the data and sent it to the corresponding sources. 1039 verify(sharedStoreData, times(1)) 1040 .deserializeDataForSection(any(XmlPullParser.class), anyInt(), 1041 eq(WifiConfigStore.ENCRYPT_CREDENTIALS_CONFIG_STORE_DATA_VERSION), any(), 1042 eq(TEST_SHARE_DATA)); 1043 verify(userStoreData, times(1)) 1044 .deserializeDataForSection(any(XmlPullParser.class), anyInt(), 1045 eq(WifiConfigStore.ENCRYPT_CREDENTIALS_CONFIG_STORE_DATA_VERSION), any(), 1046 eq(TEST_USER_DATA)); 1047 1048 // Verify we did not read from the real store files. 1049 verify(sharedStoreFile1, never()).readRawData(); 1050 verify(sharedStoreFile2, never()).readRawData(); 1051 verify(userStoreFile1, never()).readRawData(); 1052 verify(userStoreFile2, never()).readRawData(); 1053 } 1054 1055 /** 1056 * Mock Store File to redirect all file writes from WifiConfigStore to local buffers. 1057 * This can be used to examine the data output by WifiConfigStore. 1058 */ 1059 private class MockStoreFile extends StoreFile { 1060 private byte[] mStoreBytes; 1061 private boolean mStoreWritten; 1062 MockStoreFile(@ifiConfigStore.StoreFileId int fileId)1063 MockStoreFile(@WifiConfigStore.StoreFileId int fileId) { 1064 super(new File("MockStoreFile"), fileId, UserHandle.ALL, mEncryptionUtil); 1065 } 1066 1067 @Override readRawData()1068 public byte[] readRawData() { 1069 return mStoreBytes; 1070 } 1071 1072 @Override storeRawDataToWrite(byte[] data)1073 public void storeRawDataToWrite(byte[] data) { 1074 mStoreBytes = data; 1075 mStoreWritten = false; 1076 } 1077 1078 @Override writeBufferedRawData()1079 public void writeBufferedRawData() { 1080 if (!ArrayUtils.isEmpty(mStoreBytes)) { 1081 mStoreWritten = true; 1082 } 1083 } 1084 getStoreBytes()1085 public byte[] getStoreBytes() { 1086 return mStoreBytes; 1087 } 1088 isStoreWritten()1089 public boolean isStoreWritten() { 1090 return mStoreWritten; 1091 } 1092 } 1093 1094 /** 1095 * Mock data container for providing test data for the store file. 1096 */ 1097 private class MockStoreData implements StoreData { 1098 private static final String XML_TAG_TEST_HEADER = "TestHeader"; 1099 private static final String XML_TAG_TEST_DATA = "TestData"; 1100 1101 private @WifiConfigStore.StoreFileId int mFileId; 1102 private String mData; 1103 private boolean mHasAnyNewData = true; 1104 MockStoreData(@ifiConfigStore.StoreFileId int fileId)1105 MockStoreData(@WifiConfigStore.StoreFileId int fileId) { 1106 mFileId = fileId; 1107 } 1108 1109 @Override serializeData(XmlSerializer out, WifiConfigStoreEncryptionUtil encryptionUtil)1110 public void serializeData(XmlSerializer out, WifiConfigStoreEncryptionUtil encryptionUtil) 1111 throws XmlPullParserException, IOException { 1112 XmlUtil.writeNextValue(out, XML_TAG_TEST_DATA, mData); 1113 } 1114 1115 @Override deserializeData(XmlPullParser in, int outerTagDepth, int version, WifiConfigStoreEncryptionUtil encryptionUtil)1116 public void deserializeData(XmlPullParser in, int outerTagDepth, int version, 1117 WifiConfigStoreEncryptionUtil encryptionUtil) 1118 throws XmlPullParserException, IOException { 1119 if (in == null) { 1120 return; 1121 } 1122 mData = (String) XmlUtil.readNextValueWithName(in, XML_TAG_TEST_DATA); 1123 } 1124 1125 @Override resetData()1126 public void resetData() { 1127 mData = null; 1128 } 1129 1130 @Override hasNewDataToSerialize()1131 public boolean hasNewDataToSerialize() { 1132 return mHasAnyNewData; 1133 } 1134 1135 @Override getName()1136 public String getName() { 1137 return XML_TAG_TEST_HEADER; 1138 } 1139 1140 @Override getStoreFileId()1141 public @WifiConfigStore.StoreFileId int getStoreFileId() { 1142 return mFileId; 1143 } 1144 getData()1145 public String getData() { 1146 return mData; 1147 } 1148 setData(String data)1149 public void setData(String data) { 1150 mData = data; 1151 } 1152 setHasAnyNewData(boolean hasAnyNewData)1153 public void setHasAnyNewData(boolean hasAnyNewData) { 1154 mHasAnyNewData = hasAnyNewData; 1155 } 1156 } 1157 1158 /** 1159 * Verify dump will not crash when no UserStores set. 1160 */ 1161 @Test testDump()1162 public void testDump() { 1163 final FileDescriptor fd = new FileDescriptor(); 1164 final FileOutputStream fout = new FileOutputStream(fd); 1165 final PrintWriter pw = new FastPrintWriter(fout); 1166 mWifiConfigStore.dump(fd, pw, new String[0]); 1167 1168 mWifiConfigStore.setUserStores(mUserStores); 1169 mWifiConfigStore.dump(fd, pw, new String[0]); 1170 } 1171 } 1172