1 /* <lambda>null2 * Copyright (C) 2021 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.pm.test.verify.domain 18 19 import android.content.Intent 20 import android.content.pm.PackageManager 21 import android.content.pm.PackageUserState 22 import android.content.pm.Signature 23 import android.content.pm.parsing.component.ParsedActivity 24 import android.content.pm.parsing.component.ParsedIntentInfo 25 import android.content.pm.verify.domain.DomainOwner 26 import android.content.pm.verify.domain.DomainVerificationInfo.STATE_MODIFIABLE_VERIFIED 27 import android.content.pm.verify.domain.DomainVerificationInfo.STATE_NO_RESPONSE 28 import android.content.pm.verify.domain.DomainVerificationInfo.STATE_SUCCESS 29 import android.content.pm.verify.domain.DomainVerificationInfo.STATE_UNMODIFIABLE 30 import android.content.pm.verify.domain.DomainVerificationManager 31 import android.content.pm.verify.domain.DomainVerificationState 32 import android.content.pm.verify.domain.DomainVerificationUserState.DOMAIN_STATE_NONE 33 import android.content.pm.verify.domain.DomainVerificationUserState.DOMAIN_STATE_SELECTED 34 import android.content.pm.verify.domain.DomainVerificationUserState.DOMAIN_STATE_VERIFIED 35 import android.os.Build 36 import android.os.PatternMatcher 37 import android.os.Process 38 import android.util.ArraySet 39 import android.util.Xml 40 import com.android.server.pm.PackageSetting 41 import com.android.server.pm.parsing.pkg.AndroidPackage 42 import com.android.server.pm.test.verify.domain.DomainVerificationTestUtils.mockPackageSettings 43 import com.android.server.pm.verify.domain.DomainVerificationService 44 import com.android.server.testutils.mockThrowOnUnmocked 45 import com.android.server.testutils.whenever 46 import com.google.common.truth.Truth.assertThat 47 import org.junit.Test 48 import org.mockito.ArgumentMatchers.any 49 import org.mockito.ArgumentMatchers.anyInt 50 import org.mockito.ArgumentMatchers.anyLong 51 import org.mockito.ArgumentMatchers.anyString 52 import java.io.ByteArrayInputStream 53 import java.io.ByteArrayOutputStream 54 import java.util.UUID 55 56 class DomainVerificationPackageTest { 57 58 companion object { 59 private const val PKG_ONE = "com.test.one" 60 private const val PKG_TWO = "com.test.two" 61 private val UUID_ONE = UUID.fromString("1b041c96-8d37-4932-a858-561bfac5947c") 62 private val UUID_TWO = UUID.fromString("a3389c16-7f9f-4e86-85e3-500d1249c74c") 63 private const val SIGNATURE_ONE = "AA" 64 private const val DIGEST_ONE = 65 "BCEEF655B5A034911F1C3718CE056531B45EF03B4C7B1F15629E867294011A7D" 66 private const val SIGNATURE_TWO = "BB" 67 68 private val DOMAIN_BASE = DomainVerificationPackageTest::class.java.packageName 69 private val DOMAIN_1 = "one.$DOMAIN_BASE" 70 private val DOMAIN_2 = "two.$DOMAIN_BASE" 71 private val DOMAIN_3 = "three.$DOMAIN_BASE" 72 private val DOMAIN_4 = "four.$DOMAIN_BASE" 73 74 private const val USER_ID = 0 75 } 76 77 private val pkg1 = mockPkgSetting(PKG_ONE, UUID_ONE, SIGNATURE_ONE) 78 private val pkg2 = mockPkgSetting(PKG_TWO, UUID_TWO, SIGNATURE_TWO) 79 80 @Test 81 fun addPackageFirstTime() { 82 val service = makeService(pkg1, pkg2) 83 service.addPackage(pkg1) 84 val info = service.getInfo(pkg1.getName()) 85 assertThat(info.packageName).isEqualTo(pkg1.getName()) 86 assertThat(info.identifier).isEqualTo(pkg1.domainSetId) 87 assertThat(info.hostToStateMap).containsExactlyEntriesIn(mapOf( 88 DOMAIN_1 to STATE_NO_RESPONSE, 89 DOMAIN_2 to STATE_NO_RESPONSE, 90 )) 91 92 val userState = service.getUserState(pkg1.getName()) 93 assertThat(userState.packageName).isEqualTo(pkg1.getName()) 94 assertThat(userState.identifier).isEqualTo(pkg1.domainSetId) 95 assertThat(userState.isLinkHandlingAllowed).isEqualTo(true) 96 assertThat(userState.user.identifier).isEqualTo(USER_ID) 97 assertThat(userState.hostToStateMap).containsExactlyEntriesIn(mapOf( 98 DOMAIN_1 to DOMAIN_STATE_NONE, 99 DOMAIN_2 to DOMAIN_STATE_NONE, 100 )) 101 102 assertThat(service.queryValidVerificationPackageNames()) 103 .containsExactly(pkg1.getName()) 104 } 105 106 @Test 107 fun addPackageSystemConfigured() { 108 val pkg1 = mockPkgSetting(PKG_ONE, UUID_ONE, SIGNATURE_ONE, isSystemApp = false) 109 val pkg2 = mockPkgSetting(PKG_TWO, UUID_TWO, SIGNATURE_TWO, isSystemApp = true) 110 111 val service = makeService( 112 systemConfiguredPackageNames = ArraySet(setOf(pkg1.getName(), pkg2.getName())), 113 pkg1, pkg2 114 ) 115 service.addPackage(pkg1) 116 service.addPackage(pkg2) 117 118 service.getInfo(pkg1.getName()).apply { 119 assertThat(packageName).isEqualTo(pkg1.getName()) 120 assertThat(identifier).isEqualTo(pkg1.domainSetId) 121 assertThat(hostToStateMap).containsExactlyEntriesIn( 122 mapOf( 123 DOMAIN_1 to STATE_NO_RESPONSE, 124 DOMAIN_2 to STATE_NO_RESPONSE, 125 ) 126 ) 127 } 128 129 service.getUserState(pkg1.getName()).apply { 130 assertThat(packageName).isEqualTo(pkg1.getName()) 131 assertThat(identifier).isEqualTo(pkg1.domainSetId) 132 assertThat(isLinkHandlingAllowed).isEqualTo(true) 133 assertThat(user.identifier).isEqualTo(USER_ID) 134 assertThat(hostToStateMap).containsExactlyEntriesIn( 135 mapOf( 136 DOMAIN_1 to DOMAIN_STATE_NONE, 137 DOMAIN_2 to DOMAIN_STATE_NONE, 138 ) 139 ) 140 } 141 142 service.getInfo(pkg2.getName()).apply { 143 assertThat(packageName).isEqualTo(pkg2.getName()) 144 assertThat(identifier).isEqualTo(pkg2.domainSetId) 145 assertThat(hostToStateMap).containsExactlyEntriesIn( 146 mapOf( 147 DOMAIN_1 to STATE_UNMODIFIABLE, 148 DOMAIN_2 to STATE_UNMODIFIABLE, 149 ) 150 ) 151 } 152 153 service.getUserState(pkg2.getName()).apply { 154 assertThat(packageName).isEqualTo(pkg2.getName()) 155 assertThat(identifier).isEqualTo(pkg2.domainSetId) 156 assertThat(isLinkHandlingAllowed).isEqualTo(true) 157 assertThat(user.identifier).isEqualTo(USER_ID) 158 assertThat(hostToStateMap).containsExactlyEntriesIn( 159 mapOf( 160 DOMAIN_1 to DOMAIN_STATE_VERIFIED, 161 DOMAIN_2 to DOMAIN_STATE_VERIFIED, 162 ) 163 ) 164 } 165 166 assertThat(service.queryValidVerificationPackageNames()) 167 .containsExactly(pkg1.getName(), pkg2.getName()) 168 } 169 170 @Test 171 fun addPackageRestoredMatchingSignature() { 172 // language=XML 173 val xml = """ 174 <?xml?> 175 <domain-verifications> 176 <active> 177 <package-state 178 packageName="${pkg1.getName()}" 179 id="${pkg1.domainSetId}" 180 signature="$DIGEST_ONE" 181 > 182 <state> 183 <domain name="$DOMAIN_1" state="1"/> 184 </state> 185 </package-state> 186 </active> 187 </domain-verifications> 188 """ 189 190 val service = makeService(pkg1, pkg2) 191 service.restoreSettings(Xml.resolvePullParser(xml.byteInputStream())) 192 service.addPackage(pkg1) 193 val info = service.getInfo(pkg1.getName()) 194 assertThat(info.packageName).isEqualTo(pkg1.getName()) 195 assertThat(info.identifier).isEqualTo(pkg1.domainSetId) 196 assertThat(info.hostToStateMap).containsExactlyEntriesIn( 197 mapOf( 198 DOMAIN_1 to STATE_MODIFIABLE_VERIFIED, 199 DOMAIN_2 to STATE_NO_RESPONSE, 200 ) 201 ) 202 203 val userState = service.getUserState(pkg1.getName()) 204 assertThat(userState.packageName).isEqualTo(pkg1.getName()) 205 assertThat(userState.identifier).isEqualTo(pkg1.domainSetId) 206 assertThat(userState.isLinkHandlingAllowed).isEqualTo(true) 207 assertThat(userState.user.identifier).isEqualTo(USER_ID) 208 assertThat(userState.hostToStateMap).containsExactlyEntriesIn( 209 mapOf( 210 DOMAIN_1 to DOMAIN_STATE_VERIFIED, 211 DOMAIN_2 to DOMAIN_STATE_NONE, 212 ) 213 ) 214 215 assertThat(service.queryValidVerificationPackageNames()) 216 .containsExactly(pkg1.getName()) 217 } 218 219 @Test 220 fun addPackageRestoredMismatchSignature() { 221 // language=XML 222 val xml = """ 223 <?xml?> 224 <domain-verifications> 225 <active> 226 <package-state 227 packageName="${pkg1.getName()}" 228 id="${pkg1.domainSetId}" 229 signature="INVALID_SIGNATURE" 230 > 231 <state> 232 <domain name="$DOMAIN_1" state="1"/> 233 </state> 234 </package-state> 235 </active> 236 </domain-verifications> 237 """ 238 239 val service = makeService(pkg1, pkg2) 240 service.restoreSettings(Xml.resolvePullParser(xml.byteInputStream())) 241 service.addPackage(pkg1) 242 val info = service.getInfo(pkg1.getName()) 243 assertThat(info.packageName).isEqualTo(pkg1.getName()) 244 assertThat(info.identifier).isEqualTo(pkg1.domainSetId) 245 assertThat(info.hostToStateMap).containsExactlyEntriesIn( 246 mapOf( 247 DOMAIN_1 to STATE_NO_RESPONSE, 248 DOMAIN_2 to STATE_NO_RESPONSE, 249 ) 250 ) 251 252 val userState = service.getUserState(pkg1.getName()) 253 assertThat(userState.packageName).isEqualTo(pkg1.getName()) 254 assertThat(userState.identifier).isEqualTo(pkg1.domainSetId) 255 assertThat(userState.isLinkHandlingAllowed).isEqualTo(true) 256 assertThat(userState.user.identifier).isEqualTo(USER_ID) 257 assertThat(userState.hostToStateMap).containsExactlyEntriesIn( 258 mapOf( 259 DOMAIN_1 to DOMAIN_STATE_NONE, 260 DOMAIN_2 to DOMAIN_STATE_NONE, 261 ) 262 ) 263 264 assertThat(service.queryValidVerificationPackageNames()) 265 .containsExactly(pkg1.getName()) 266 } 267 268 @Test 269 fun addPackageActive() { 270 // language=XML 271 val xml = """ 272 <?xml?> 273 <domain-verifications> 274 <active> 275 <package-state 276 packageName="${pkg1.getName()}" 277 id="${pkg1.domainSetId}" 278 > 279 <state> 280 <domain name="$DOMAIN_1" state="$STATE_SUCCESS"/> 281 </state> 282 <user-states> 283 <user-state userId="$USER_ID" allowLinkHandling="false"> 284 <enabled-hosts> 285 <host name="$DOMAIN_2"/> 286 </enabled-hosts> 287 </user-state> 288 </user-states> 289 </package-state> 290 </active> 291 </domain-verifications> 292 """.trimIndent() 293 294 val service = makeService(pkg1, pkg2) 295 xml.byteInputStream().use { 296 service.readSettings(Xml.resolvePullParser(it)) 297 } 298 299 service.addPackage(pkg1) 300 301 assertAddPackageActivePendingRestoredState(service) 302 } 303 304 @Test 305 fun addPackagePendingStripInvalidDomains() { 306 val xml = addPackagePendingOrRestoredWithInvalidDomains() 307 val service = makeService(pkg1, pkg2) 308 xml.byteInputStream().use { 309 service.readSettings(Xml.resolvePullParser(it)) 310 } 311 312 service.addPackage(pkg1) 313 314 val userState = service.getUserState(pkg1.getName()) 315 assertThat(userState.packageName).isEqualTo(pkg1.getName()) 316 assertThat(userState.identifier).isEqualTo(pkg1.domainSetId) 317 assertThat(userState.isLinkHandlingAllowed).isEqualTo(false) 318 assertThat(userState.user.identifier).isEqualTo(USER_ID) 319 assertThat(userState.hostToStateMap).containsExactlyEntriesIn(mapOf( 320 DOMAIN_1 to DOMAIN_STATE_VERIFIED, 321 DOMAIN_2 to DOMAIN_STATE_SELECTED, 322 )) 323 324 assertAddPackageActivePendingRestoredState(service) 325 } 326 327 @Test 328 fun addPackageRestoredStripInvalidDomains() { 329 val xml = addPackagePendingOrRestoredWithInvalidDomains() 330 val service = makeService(pkg1, pkg2) 331 xml.byteInputStream().use { 332 service.restoreSettings(Xml.resolvePullParser(it)) 333 } 334 335 service.addPackage(pkg1) 336 337 assertAddPackageActivePendingRestoredState(service, expectRestore = true) 338 } 339 340 /** 341 * Shared string that contains invalid [DOMAIN_3] and [DOMAIN_4] which should be stripped from 342 * the final state. 343 */ 344 private fun addPackagePendingOrRestoredWithInvalidDomains(): String = 345 // language=XML 346 """ 347 <?xml?> 348 <domain-verifications> 349 <active> 350 <package-state 351 packageName="${pkg1.getName()}" 352 id="${pkg1.domainSetId}" 353 signature="$DIGEST_ONE" 354 > 355 <state> 356 <domain name="$DOMAIN_1" state="$STATE_SUCCESS"/> 357 <domain name="$DOMAIN_3" state="$STATE_SUCCESS"/> 358 </state> 359 <user-states> 360 <user-state userId="$USER_ID" allowLinkHandling="false"> 361 <enabled-hosts> 362 <host name="$DOMAIN_2"/> 363 <host name="$DOMAIN_4"/> 364 </enabled-hosts> 365 </user-state> 366 <user-state userId="${USER_ID + 10}" allowLinkHandling="true"> 367 <enabled-hosts> 368 <host name="$DOMAIN_4"/> 369 </enabled-hosts> 370 </user-state> 371 </user-states> 372 </package-state> 373 </active> 374 </domain-verifications> 375 """.trimIndent() 376 377 /** 378 * Shared method to assert the same output when testing adding pkg1. 379 */ 380 private fun assertAddPackageActivePendingRestoredState( 381 service: DomainVerificationService, 382 expectRestore: Boolean = false 383 ) { 384 val info = service.getInfo(pkg1.getName()) 385 assertThat(info.packageName).isEqualTo(pkg1.getName()) 386 assertThat(info.identifier).isEqualTo(pkg1.domainSetId) 387 assertThat(info.hostToStateMap).containsExactlyEntriesIn(mapOf( 388 // To share the majority of code, special case restoration to check a different int 389 DOMAIN_1 to if (expectRestore) STATE_MODIFIABLE_VERIFIED else STATE_SUCCESS, 390 DOMAIN_2 to STATE_NO_RESPONSE, 391 )) 392 393 val userState = service.getUserState(pkg1.getName()) 394 assertThat(userState.packageName).isEqualTo(pkg1.getName()) 395 assertThat(userState.identifier).isEqualTo(pkg1.domainSetId) 396 assertThat(userState.isLinkHandlingAllowed).isEqualTo(false) 397 assertThat(userState.user.identifier).isEqualTo(USER_ID) 398 assertThat(userState.hostToStateMap).containsExactlyEntriesIn(mapOf( 399 DOMAIN_1 to DOMAIN_STATE_VERIFIED, 400 DOMAIN_2 to DOMAIN_STATE_SELECTED, 401 )) 402 403 assertThat(service.queryValidVerificationPackageNames()) 404 .containsExactly(pkg1.getName()) 405 406 // Re-enable link handling to check that the 3/4 domains were stripped 407 service.setDomainVerificationLinkHandlingAllowed(pkg1.getName(), true, USER_ID) 408 409 assertThat(service.getOwnersForDomain(DOMAIN_1, USER_ID)) 410 .containsExactly(DomainOwner(PKG_ONE, false)) 411 412 assertThat(service.getOwnersForDomain(DOMAIN_2, USER_ID)) 413 .containsExactly(DomainOwner(PKG_ONE, true)) 414 415 assertThat(service.getOwnersForDomain(DOMAIN_2, USER_ID + 10)).isEmpty() 416 417 listOf(DOMAIN_3, DOMAIN_4).forEach { domain -> 418 listOf(USER_ID, USER_ID + 10).forEach { userId -> 419 assertThat(service.getOwnersForDomain(domain, userId)).isEmpty() 420 } 421 } 422 } 423 424 @Test 425 fun migratePackageDropDomain() { 426 val pkgName = PKG_ONE 427 val pkgBefore = mockPkgSetting(pkgName, UUID_ONE, SIGNATURE_ONE, 428 listOf(DOMAIN_1, DOMAIN_2, DOMAIN_3, DOMAIN_4)) 429 val pkgAfter = mockPkgSetting(pkgName, UUID_TWO, SIGNATURE_TWO, listOf(DOMAIN_1, DOMAIN_2)) 430 431 // Test 4 domains: 432 // 1 will be approved and preserved, 2 will be selected and preserved, 433 // 3 will be denied and dropped, 4 will be selected and dropped 434 435 val map = mutableMapOf<String, PackageSetting>() 436 val service = makeService { map[it] } 437 service.addPackage(pkgBefore) 438 439 // Only insert the package after addPackage call to ensure the service doesn't access 440 // a live package inside the addPackage logic. It should only use the provided input. 441 map[pkgName] = pkgBefore 442 443 // To test the approve/denial states, use the internal methods for this variant 444 service.setDomainVerificationStatusInternal(pkgName, DomainVerificationState.STATE_APPROVED, 445 ArraySet(setOf(DOMAIN_1))) 446 service.setDomainVerificationStatusInternal(pkgName, DomainVerificationState.STATE_DENIED, 447 ArraySet(setOf(DOMAIN_3))) 448 service.setUserSelection( 449 UUID_ONE, setOf(DOMAIN_2, DOMAIN_4), true, USER_ID) 450 451 // Check the verifier cannot change the shell approve/deny states 452 service.setStatus(UUID_ONE, setOf(DOMAIN_1, DOMAIN_3), STATE_SUCCESS) 453 454 assertThat(service.getInfo(pkgName).hostToStateMap).containsExactlyEntriesIn(mapOf( 455 DOMAIN_1 to STATE_UNMODIFIABLE, 456 DOMAIN_2 to STATE_NO_RESPONSE, 457 DOMAIN_3 to STATE_UNMODIFIABLE, 458 DOMAIN_4 to STATE_NO_RESPONSE, 459 )) 460 assertThat(service.getUserState(pkgName).hostToStateMap).containsExactlyEntriesIn(mapOf( 461 DOMAIN_1 to DOMAIN_STATE_VERIFIED, 462 DOMAIN_2 to DOMAIN_STATE_SELECTED, 463 DOMAIN_3 to DOMAIN_STATE_NONE, 464 DOMAIN_4 to DOMAIN_STATE_SELECTED, 465 )) 466 467 // Now remove the package because migrateState shouldn't use it either 468 map.remove(pkgName) 469 470 map[pkgName] = pkgAfter 471 472 service.migrateState(pkgBefore, pkgAfter) 473 474 assertThat(service.getInfo(pkgName).hostToStateMap).containsExactlyEntriesIn(mapOf( 475 DOMAIN_1 to STATE_UNMODIFIABLE, 476 DOMAIN_2 to STATE_NO_RESPONSE, 477 )) 478 assertThat(service.getUserState(pkgName).hostToStateMap).containsExactlyEntriesIn(mapOf( 479 DOMAIN_1 to DOMAIN_STATE_VERIFIED, 480 DOMAIN_2 to DOMAIN_STATE_SELECTED, 481 )) 482 assertThat(service.queryValidVerificationPackageNames()).containsExactly(pkgName) 483 } 484 485 @Test 486 fun migratePackageDropAll() { 487 val pkgName = PKG_ONE 488 val pkgBefore = mockPkgSetting(pkgName, UUID_ONE, SIGNATURE_ONE, listOf(DOMAIN_1, DOMAIN_2)) 489 val pkgAfter = mockPkgSetting(pkgName, UUID_TWO, SIGNATURE_TWO, emptyList()) 490 491 val map = mutableMapOf<String, PackageSetting>() 492 val service = makeService { map[it] } 493 service.addPackage(pkgBefore) 494 495 // Only insert the package after addPackage call to ensure the service doesn't access 496 // a live package inside the addPackage logic. It should only use the provided input. 497 map[pkgName] = pkgBefore 498 499 assertThat(service.getInfo(pkgName).hostToStateMap).containsExactlyEntriesIn(mapOf( 500 DOMAIN_1 to STATE_NO_RESPONSE, 501 DOMAIN_2 to STATE_NO_RESPONSE, 502 )) 503 assertThat(service.getUserState(pkgName).hostToStateMap).containsExactlyEntriesIn(mapOf( 504 DOMAIN_1 to DOMAIN_STATE_NONE, 505 DOMAIN_2 to DOMAIN_STATE_NONE, 506 )) 507 assertThat(service.queryValidVerificationPackageNames()).containsExactly(pkgName) 508 509 // Now remove the package because migrateState shouldn't use it either 510 map.remove(pkgName) 511 512 service.migrateState(pkgBefore, pkgAfter) 513 514 map[pkgName] = pkgAfter 515 516 assertThat(service.setStatus(UUID_ONE, setOf(DOMAIN_1), STATE_SUCCESS)) 517 .isNotEqualTo(DomainVerificationManager.STATUS_OK) 518 519 assertThat(service.setUserSelection(UUID_ONE, setOf(DOMAIN_2), true, USER_ID)) 520 .isNotEqualTo(DomainVerificationManager.STATUS_OK) 521 522 assertThat(service.getDomainVerificationInfo(pkgName)).isNull() 523 assertThat(service.getUserState(pkgName).hostToStateMap).isEmpty() 524 assertThat(service.queryValidVerificationPackageNames()).isEmpty() 525 } 526 527 @Test 528 fun migratePackageAddDomain() { 529 val pkgName = PKG_ONE 530 val pkgBefore = mockPkgSetting(pkgName, UUID_ONE, SIGNATURE_ONE, listOf(DOMAIN_1, DOMAIN_2)) 531 val pkgAfter = mockPkgSetting(pkgName, UUID_TWO, SIGNATURE_TWO, 532 listOf(DOMAIN_1, DOMAIN_2, DOMAIN_3)) 533 534 // Test 3 domains: 535 // 1 will be verified and preserved, 2 will be selected and preserved, 536 // 3 will be new and default 537 538 val map = mutableMapOf<String, PackageSetting>() 539 val service = makeService { map[it] } 540 service.addPackage(pkgBefore) 541 542 // Only insert the package after addPackage call to ensure the service doesn't access 543 // a live package inside the addPackage logic. It should only use the provided input. 544 map[pkgName] = pkgBefore 545 546 service.setStatus(UUID_ONE, setOf(DOMAIN_1), STATE_SUCCESS) 547 service.setUserSelection(UUID_ONE, setOf(DOMAIN_2), true, USER_ID) 548 549 assertThat(service.getInfo(pkgName).hostToStateMap).containsExactlyEntriesIn(mapOf( 550 DOMAIN_1 to STATE_SUCCESS, 551 DOMAIN_2 to STATE_NO_RESPONSE, 552 )) 553 assertThat(service.getUserState(pkgName).hostToStateMap).containsExactlyEntriesIn(mapOf( 554 DOMAIN_1 to DOMAIN_STATE_VERIFIED, 555 DOMAIN_2 to DOMAIN_STATE_SELECTED, 556 )) 557 558 // Now remove the package because migrateState shouldn't use it either 559 map.remove(pkgName) 560 561 service.migrateState(pkgBefore, pkgAfter) 562 563 map[pkgName] = pkgAfter 564 565 assertThat(service.getInfo(pkgName).hostToStateMap).containsExactlyEntriesIn(mapOf( 566 DOMAIN_1 to STATE_SUCCESS, 567 DOMAIN_2 to STATE_NO_RESPONSE, 568 DOMAIN_3 to STATE_NO_RESPONSE, 569 )) 570 assertThat(service.getUserState(pkgName).hostToStateMap).containsExactlyEntriesIn(mapOf( 571 DOMAIN_1 to DOMAIN_STATE_VERIFIED, 572 DOMAIN_2 to DOMAIN_STATE_SELECTED, 573 DOMAIN_3 to DOMAIN_STATE_NONE, 574 )) 575 assertThat(service.queryValidVerificationPackageNames()).containsExactly(pkgName) 576 } 577 578 @Test 579 fun migratePackageAddAll() { 580 val pkgName = PKG_ONE 581 val pkgBefore = mockPkgSetting(pkgName, UUID_ONE, SIGNATURE_ONE, emptyList()) 582 val pkgAfter = mockPkgSetting(pkgName, UUID_TWO, SIGNATURE_TWO, listOf(DOMAIN_1, DOMAIN_2)) 583 584 val map = mutableMapOf<String, PackageSetting>() 585 val service = makeService { map[it] } 586 service.addPackage(pkgBefore) 587 588 // Only insert the package after addPackage call to ensure the service doesn't access 589 // a live package inside the addPackage logic. It should only use the provided input. 590 map[pkgName] = pkgBefore 591 592 assertThat(service.setStatus(UUID_ONE, setOf(DOMAIN_1), STATE_SUCCESS)) 593 .isNotEqualTo(DomainVerificationManager.STATUS_OK) 594 595 assertThat(service.setUserSelection(UUID_ONE, setOf(DOMAIN_2), true, USER_ID)) 596 .isNotEqualTo(DomainVerificationManager.STATUS_OK) 597 598 assertThat(service.getDomainVerificationInfo(pkgName)).isNull() 599 assertThat(service.getUserState(pkgName).hostToStateMap).isEmpty() 600 assertThat(service.queryValidVerificationPackageNames()).isEmpty() 601 602 // Now remove the package because migrateState shouldn't use it either 603 map.remove(pkgName) 604 605 service.migrateState(pkgBefore, pkgAfter) 606 607 map[pkgName] = pkgAfter 608 609 assertThat(service.getInfo(pkgName).hostToStateMap).containsExactlyEntriesIn(mapOf( 610 DOMAIN_1 to STATE_NO_RESPONSE, 611 DOMAIN_2 to STATE_NO_RESPONSE, 612 )) 613 assertThat(service.getUserState(pkgName).hostToStateMap).containsExactlyEntriesIn(mapOf( 614 DOMAIN_1 to DOMAIN_STATE_NONE, 615 DOMAIN_2 to DOMAIN_STATE_NONE, 616 )) 617 assertThat(service.queryValidVerificationPackageNames()).containsExactly(pkgName) 618 } 619 620 @Test 621 fun backupAndRestore() { 622 // This test acts as a proxy for true user restore through PackageManager, 623 // as that's much harder to test for real. 624 625 val pkg1 = mockPkgSetting(PKG_ONE, UUID_ONE, SIGNATURE_ONE, listOf(DOMAIN_1, DOMAIN_2)) 626 val pkg2 = mockPkgSetting(PKG_TWO, UUID_TWO, SIGNATURE_TWO, 627 listOf(DOMAIN_1, DOMAIN_2, DOMAIN_3)) 628 val serviceBefore = makeService(pkg1, pkg2) 629 serviceBefore.addPackage(pkg1) 630 serviceBefore.addPackage(pkg2) 631 632 serviceBefore.setStatus(pkg1.domainSetId, setOf(DOMAIN_1), STATE_SUCCESS) 633 serviceBefore.setDomainVerificationLinkHandlingAllowed(pkg1.getName(), false, 10) 634 serviceBefore.setUserSelection(pkg2.domainSetId, setOf(DOMAIN_2), true, 0) 635 serviceBefore.setUserSelection(pkg2.domainSetId, setOf(DOMAIN_3), true, 10) 636 637 fun assertExpectedState(service: DomainVerificationService) { 638 service.assertState( 639 pkg1, userId = 0, hostToStateMap = mapOf( 640 DOMAIN_1 to DOMAIN_STATE_VERIFIED, 641 DOMAIN_2 to DOMAIN_STATE_NONE, 642 ) 643 ) 644 645 service.assertState( 646 pkg1, userId = 10, linkHandingAllowed = false, hostToStateMap = mapOf( 647 DOMAIN_1 to DOMAIN_STATE_VERIFIED, 648 DOMAIN_2 to DOMAIN_STATE_NONE, 649 ) 650 ) 651 652 service.assertState( 653 pkg2, userId = 0, hostToStateMap = mapOf( 654 DOMAIN_1 to DOMAIN_STATE_NONE, 655 DOMAIN_2 to DOMAIN_STATE_SELECTED, 656 DOMAIN_3 to DOMAIN_STATE_NONE 657 ) 658 ) 659 660 service.assertState( 661 pkg2, userId = 10, hostToStateMap = mapOf( 662 DOMAIN_1 to DOMAIN_STATE_NONE, 663 DOMAIN_2 to DOMAIN_STATE_NONE, 664 DOMAIN_3 to DOMAIN_STATE_SELECTED, 665 ) 666 ) 667 } 668 669 assertExpectedState(serviceBefore) 670 671 val backupUser0 = ByteArrayOutputStream().use { 672 serviceBefore.writeSettings(Xml.resolveSerializer(it), true, 0) 673 it.toByteArray() 674 } 675 676 val backupUser1 = ByteArrayOutputStream().use { 677 serviceBefore.writeSettings(Xml.resolveSerializer(it), true, 10) 678 it.toByteArray() 679 } 680 681 val serviceAfter = makeService(pkg1, pkg2) 682 serviceAfter.addPackage(pkg1) 683 serviceAfter.addPackage(pkg2) 684 685 // Check the state is default before the restoration applies 686 listOf(0, 10).forEach { 687 serviceAfter.assertState( 688 pkg1, userId = it, hostToStateMap = mapOf( 689 DOMAIN_1 to DOMAIN_STATE_NONE, 690 DOMAIN_2 to DOMAIN_STATE_NONE, 691 ) 692 ) 693 } 694 695 listOf(0, 10).forEach { 696 serviceAfter.assertState( 697 pkg2, userId = it, hostToStateMap = mapOf( 698 DOMAIN_1 to DOMAIN_STATE_NONE, 699 DOMAIN_2 to DOMAIN_STATE_NONE, 700 DOMAIN_3 to DOMAIN_STATE_NONE, 701 ) 702 ) 703 } 704 705 ByteArrayInputStream(backupUser1).use { 706 serviceAfter.restoreSettings(Xml.resolvePullParser(it)) 707 } 708 709 // Assert user 1 was restored 710 serviceAfter.assertState( 711 pkg1, userId = 10, linkHandingAllowed = false, hostToStateMap = mapOf( 712 DOMAIN_1 to DOMAIN_STATE_VERIFIED, 713 DOMAIN_2 to DOMAIN_STATE_NONE, 714 ) 715 ) 716 717 serviceAfter.assertState( 718 pkg2, userId = 10, hostToStateMap = mapOf( 719 DOMAIN_1 to DOMAIN_STATE_NONE, 720 DOMAIN_2 to DOMAIN_STATE_NONE, 721 DOMAIN_3 to DOMAIN_STATE_SELECTED, 722 ) 723 ) 724 725 // User 0 has domain verified (since that's not user-specific) 726 serviceAfter.assertState( 727 pkg1, userId = 0, hostToStateMap = mapOf( 728 DOMAIN_1 to DOMAIN_STATE_VERIFIED, 729 DOMAIN_2 to DOMAIN_STATE_NONE, 730 ) 731 ) 732 733 // But user 0 is missing any user selected state 734 serviceAfter.assertState( 735 pkg2, userId = 0, hostToStateMap = mapOf( 736 DOMAIN_1 to DOMAIN_STATE_NONE, 737 DOMAIN_2 to DOMAIN_STATE_NONE, 738 DOMAIN_3 to DOMAIN_STATE_NONE, 739 ) 740 ) 741 742 ByteArrayInputStream(backupUser0).use { 743 serviceAfter.restoreSettings(Xml.resolvePullParser(it)) 744 } 745 746 assertExpectedState(serviceAfter) 747 } 748 749 private fun DomainVerificationService.getInfo(pkgName: String) = 750 getDomainVerificationInfo(pkgName) 751 .also { assertThat(it).isNotNull() }!! 752 753 private fun DomainVerificationService.getUserState(pkgName: String, userId: Int = USER_ID) = 754 getDomainVerificationUserState(pkgName, userId) 755 .also { assertThat(it).isNotNull() }!! 756 757 private fun makeService( 758 systemConfiguredPackageNames: ArraySet<String> = ArraySet(), 759 vararg pkgSettings: PackageSetting 760 ) = makeService(systemConfiguredPackageNames = systemConfiguredPackageNames) { 761 pkgName -> pkgSettings.find { pkgName == it.getName() } 762 } 763 764 private fun makeService(vararg pkgSettings: PackageSetting) = 765 makeService { pkgName -> pkgSettings.find { pkgName == it.getName() } } 766 767 private fun makeService( 768 systemConfiguredPackageNames: ArraySet<String> = ArraySet(), 769 pkgSettingFunction: (String) -> PackageSetting? = { null } 770 ) = DomainVerificationService(mockThrowOnUnmocked { 771 // Assume the test has every permission necessary 772 whenever(enforcePermission(anyString(), anyInt(), anyInt(), anyString())) 773 whenever(checkPermission(anyString(), anyInt(), anyInt())) { 774 PackageManager.PERMISSION_GRANTED 775 } 776 }, mockThrowOnUnmocked { 777 whenever(this.linkedApps) { systemConfiguredPackageNames } 778 }, mockThrowOnUnmocked { 779 whenever(isChangeEnabledInternalNoLogging(anyLong(), any())) { true } 780 }).apply { 781 setConnection(mockThrowOnUnmocked { 782 whenever(filterAppAccess(anyString(), anyInt(), anyInt())) { false } 783 whenever(doesUserExist(0)) { true } 784 whenever(doesUserExist(10)) { true } 785 whenever(scheduleWriteSettings()) 786 787 // Need to provide an internal UID so some permission checks are ignored 788 whenever(callingUid) { Process.ROOT_UID } 789 whenever(callingUserId) { 0 } 790 791 mockPackageSettings { 792 pkgSettingFunction(it) 793 } 794 }) 795 } 796 797 private fun mockPkgSetting( 798 pkgName: String, 799 domainSetId: UUID, 800 signature: String, 801 domains: List<String> = listOf(DOMAIN_1, DOMAIN_2), 802 isSystemApp: Boolean = false 803 ) = mockThrowOnUnmocked<PackageSetting> { 804 val pkg = mockThrowOnUnmocked<AndroidPackage> { 805 whenever(packageName) { pkgName } 806 whenever(targetSdkVersion) { Build.VERSION_CODES.S } 807 whenever(isEnabled) { true } 808 809 val activityList = listOf( 810 ParsedActivity().apply { 811 domains.forEach { 812 addIntent( 813 ParsedIntentInfo().apply { 814 autoVerify = true 815 addAction(Intent.ACTION_VIEW) 816 addCategory(Intent.CATEGORY_BROWSABLE) 817 addCategory(Intent.CATEGORY_DEFAULT) 818 addDataScheme("http") 819 addDataScheme("https") 820 addDataPath("/sub", PatternMatcher.PATTERN_LITERAL) 821 addDataAuthority(it, null) 822 } 823 ) 824 } 825 }, 826 ) 827 828 whenever(activities) { activityList } 829 } 830 831 whenever(getPkg()) { pkg } 832 whenever(getName()) { pkgName } 833 whenever(this.domainSetId) { domainSetId } 834 whenever(getInstantApp(anyInt())) { false } 835 whenever(firstInstallTime) { 0L } 836 whenever(readUserState(0)) { PackageUserState() } 837 whenever(readUserState(10)) { PackageUserState() } 838 whenever(signatures) { arrayOf(Signature(signature)) } 839 whenever(isSystem) { isSystemApp } 840 } 841 842 private fun DomainVerificationService.assertState( 843 pkg: PackageSetting, 844 userId: Int, 845 linkHandingAllowed: Boolean = true, 846 hostToStateMap: Map<String, Int> 847 ) { 848 getUserState(pkg.getName(), userId).apply { 849 assertThat(this.packageName).isEqualTo(pkg.getName()) 850 assertThat(this.identifier).isEqualTo(pkg.domainSetId) 851 assertThat(this.isLinkHandlingAllowed).isEqualTo(linkHandingAllowed) 852 assertThat(this.user.identifier).isEqualTo(userId) 853 assertThat(this.hostToStateMap).containsExactlyEntriesIn(hostToStateMap) 854 } 855 } 856 } 857