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