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