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.Signature 22 import android.content.pm.SigningDetails 23 import android.content.pm.verify.domain.DomainOwner 24 import android.content.pm.verify.domain.DomainVerificationInfo.STATE_MODIFIABLE_VERIFIED 25 import android.content.pm.verify.domain.DomainVerificationInfo.STATE_NO_RESPONSE 26 import android.content.pm.verify.domain.DomainVerificationInfo.STATE_SUCCESS 27 import android.content.pm.verify.domain.DomainVerificationInfo.STATE_UNMODIFIABLE 28 import android.content.pm.verify.domain.DomainVerificationManager 29 import android.content.pm.verify.domain.DomainVerificationState 30 import android.content.pm.verify.domain.DomainVerificationUserState.DOMAIN_STATE_NONE 31 import android.content.pm.verify.domain.DomainVerificationUserState.DOMAIN_STATE_SELECTED 32 import android.content.pm.verify.domain.DomainVerificationUserState.DOMAIN_STATE_VERIFIED 33 import android.os.Build 34 import android.os.PatternMatcher 35 import android.os.Process 36 import android.util.ArraySet 37 import android.util.SparseArray 38 import android.util.Xml 39 import com.android.server.pm.Computer 40 import com.android.server.pm.parsing.pkg.AndroidPackage 41 import com.android.server.pm.pkg.PackageStateInternal 42 import com.android.server.pm.pkg.PackageUserStateInternal 43 import com.android.server.pm.pkg.component.ParsedActivityImpl 44 import com.android.server.pm.pkg.component.ParsedIntentInfoImpl 45 import com.android.server.pm.verify.domain.DomainVerificationService 46 import com.android.server.testutils.mock 47 import com.android.server.testutils.mockThrowOnUnmocked 48 import com.android.server.testutils.spy 49 import com.android.server.testutils.whenever 50 import com.google.common.truth.Truth.assertThat 51 import org.junit.Test 52 import org.mockito.ArgumentMatchers.any 53 import org.mockito.ArgumentMatchers.anyInt 54 import org.mockito.ArgumentMatchers.anyLong 55 import org.mockito.ArgumentMatchers.anyString 56 import org.mockito.Mockito.doReturn 57 import java.io.ByteArrayInputStream 58 import java.io.ByteArrayOutputStream 59 import java.security.PublicKey 60 import java.util.UUID 61 62 class DomainVerificationPackageTest { 63 64 companion object { 65 private const val PKG_ONE = "com.test.one" 66 private const val PKG_TWO = "com.test.two" 67 private val UUID_ONE = UUID.fromString("1b041c96-8d37-4932-a858-561bfac5947c") 68 private val UUID_TWO = UUID.fromString("a3389c16-7f9f-4e86-85e3-500d1249c74c") 69 private const val SIGNATURE_ONE = "AA" 70 private const val DIGEST_ONE = 71 "BCEEF655B5A034911F1C3718CE056531B45EF03B4C7B1F15629E867294011A7D" 72 private const val SIGNATURE_TWO = "BB" 73 74 private val DOMAIN_BASE = DomainVerificationPackageTest::class.java.packageName 75 private val DOMAIN_1 = "one.$DOMAIN_BASE" 76 private val DOMAIN_2 = "two.$DOMAIN_BASE" 77 private val DOMAIN_3 = "three.$DOMAIN_BASE" 78 private val DOMAIN_4 = "four.$DOMAIN_BASE" 79 80 private const val USER_ID = 0 81 private const val USER_ID_SECONDARY = 10 82 private val USER_IDS = listOf(USER_ID, USER_ID_SECONDARY) 83 } 84 85 private val pkg1 = mockPkgState(PKG_ONE, UUID_ONE, SIGNATURE_ONE) 86 private val pkg2 = mockPkgState(PKG_TWO, UUID_TWO, SIGNATURE_TWO) 87 88 @Test 89 fun addPackageFirstTime() { 90 val service = makeService(pkg1, pkg2) 91 service.addPackage(pkg1) 92 val info = service.getInfo(pkg1.packageName) 93 assertThat(info.packageName).isEqualTo(pkg1.packageName) 94 assertThat(info.identifier).isEqualTo(pkg1.domainSetId) 95 assertThat(info.hostToStateMap).containsExactlyEntriesIn(mapOf( 96 DOMAIN_1 to STATE_NO_RESPONSE, 97 DOMAIN_2 to STATE_NO_RESPONSE, 98 )) 99 100 val userState = service.getUserState(pkg1.packageName) 101 assertThat(userState.packageName).isEqualTo(pkg1.packageName) 102 assertThat(userState.identifier).isEqualTo(pkg1.domainSetId) 103 assertThat(userState.isLinkHandlingAllowed).isEqualTo(true) 104 assertThat(userState.user.identifier).isEqualTo(USER_ID) 105 assertThat(userState.hostToStateMap).containsExactlyEntriesIn(mapOf( 106 DOMAIN_1 to DOMAIN_STATE_NONE, 107 DOMAIN_2 to DOMAIN_STATE_NONE, 108 )) 109 110 assertThat(service.queryValidVerificationPackageNames()) 111 .containsExactly(pkg1.packageName) 112 } 113 114 @Test 115 fun addPackageSystemConfigured() { 116 val pkg1 = mockPkgState(PKG_ONE, UUID_ONE, SIGNATURE_ONE, isSystemApp = false) 117 val pkg2 = mockPkgState(PKG_TWO, UUID_TWO, SIGNATURE_TWO, isSystemApp = true) 118 119 val service = makeService( 120 systemConfiguredPackageNames = ArraySet(setOf(pkg1.packageName, pkg2.packageName)), 121 pkg1, pkg2 122 ) 123 service.addPackage(pkg1) 124 service.addPackage(pkg2) 125 126 service.getInfo(pkg1.packageName).apply { 127 assertThat(packageName).isEqualTo(pkg1.packageName) 128 assertThat(identifier).isEqualTo(pkg1.domainSetId) 129 assertThat(hostToStateMap).containsExactlyEntriesIn( 130 mapOf( 131 DOMAIN_1 to STATE_NO_RESPONSE, 132 DOMAIN_2 to STATE_NO_RESPONSE, 133 ) 134 ) 135 } 136 137 service.getUserState(pkg1.packageName).apply { 138 assertThat(packageName).isEqualTo(pkg1.packageName) 139 assertThat(identifier).isEqualTo(pkg1.domainSetId) 140 assertThat(isLinkHandlingAllowed).isEqualTo(true) 141 assertThat(user.identifier).isEqualTo(USER_ID) 142 assertThat(hostToStateMap).containsExactlyEntriesIn( 143 mapOf( 144 DOMAIN_1 to DOMAIN_STATE_NONE, 145 DOMAIN_2 to DOMAIN_STATE_NONE, 146 ) 147 ) 148 } 149 150 service.getInfo(pkg2.packageName).apply { 151 assertThat(packageName).isEqualTo(pkg2.packageName) 152 assertThat(identifier).isEqualTo(pkg2.domainSetId) 153 assertThat(hostToStateMap).containsExactlyEntriesIn( 154 mapOf( 155 DOMAIN_1 to STATE_UNMODIFIABLE, 156 DOMAIN_2 to STATE_UNMODIFIABLE, 157 ) 158 ) 159 } 160 161 service.getUserState(pkg2.packageName).apply { 162 assertThat(packageName).isEqualTo(pkg2.packageName) 163 assertThat(identifier).isEqualTo(pkg2.domainSetId) 164 assertThat(isLinkHandlingAllowed).isEqualTo(true) 165 assertThat(user.identifier).isEqualTo(USER_ID) 166 assertThat(hostToStateMap).containsExactlyEntriesIn( 167 mapOf( 168 DOMAIN_1 to DOMAIN_STATE_VERIFIED, 169 DOMAIN_2 to DOMAIN_STATE_VERIFIED, 170 ) 171 ) 172 } 173 174 assertThat(service.queryValidVerificationPackageNames()) 175 .containsExactly(pkg1.packageName, pkg2.packageName) 176 } 177 178 @Test 179 fun addPackageRestoredMatchingSignature() { 180 // language=XML 181 val xml = """ 182 <?xml?> 183 <domain-verifications> 184 <active> 185 <package-state 186 packageName="${pkg1.packageName}" 187 id="${pkg1.domainSetId}" 188 signature="$DIGEST_ONE" 189 > 190 <state> 191 <domain name="$DOMAIN_1" state="1"/> 192 </state> 193 </package-state> 194 </active> 195 </domain-verifications> 196 """ 197 198 val service = makeService(pkg1, pkg2) 199 val computer = mockComputer(pkg1, pkg2) 200 service.restoreSettings(computer, Xml.resolvePullParser(xml.byteInputStream())) 201 service.addPackage(pkg1) 202 val info = service.getInfo(pkg1.packageName) 203 assertThat(info.packageName).isEqualTo(pkg1.packageName) 204 assertThat(info.identifier).isEqualTo(pkg1.domainSetId) 205 assertThat(info.hostToStateMap).containsExactlyEntriesIn( 206 mapOf( 207 DOMAIN_1 to STATE_MODIFIABLE_VERIFIED, 208 DOMAIN_2 to STATE_NO_RESPONSE, 209 ) 210 ) 211 212 val userState = service.getUserState(pkg1.packageName) 213 assertThat(userState.packageName).isEqualTo(pkg1.packageName) 214 assertThat(userState.identifier).isEqualTo(pkg1.domainSetId) 215 assertThat(userState.isLinkHandlingAllowed).isEqualTo(true) 216 assertThat(userState.user.identifier).isEqualTo(USER_ID) 217 assertThat(userState.hostToStateMap).containsExactlyEntriesIn( 218 mapOf( 219 DOMAIN_1 to DOMAIN_STATE_VERIFIED, 220 DOMAIN_2 to DOMAIN_STATE_NONE, 221 ) 222 ) 223 224 assertThat(service.queryValidVerificationPackageNames()) 225 .containsExactly(pkg1.packageName) 226 } 227 228 @Test 229 fun addPackageRestoredMismatchSignature() { 230 // language=XML 231 val xml = """ 232 <?xml?> 233 <domain-verifications> 234 <active> 235 <package-state 236 packageName="${pkg1.packageName}" 237 id="${pkg1.domainSetId}" 238 signature="INVALID_SIGNATURE" 239 > 240 <state> 241 <domain name="$DOMAIN_1" state="1"/> 242 </state> 243 </package-state> 244 </active> 245 </domain-verifications> 246 """ 247 248 val service = makeService(pkg1, pkg2) 249 val computer = mockComputer(pkg1, pkg2) 250 service.restoreSettings(computer, Xml.resolvePullParser(xml.byteInputStream())) 251 service.addPackage(pkg1) 252 val info = service.getInfo(pkg1.packageName) 253 assertThat(info.packageName).isEqualTo(pkg1.packageName) 254 assertThat(info.identifier).isEqualTo(pkg1.domainSetId) 255 assertThat(info.hostToStateMap).containsExactlyEntriesIn( 256 mapOf( 257 DOMAIN_1 to STATE_NO_RESPONSE, 258 DOMAIN_2 to STATE_NO_RESPONSE, 259 ) 260 ) 261 262 val userState = service.getUserState(pkg1.packageName) 263 assertThat(userState.packageName).isEqualTo(pkg1.packageName) 264 assertThat(userState.identifier).isEqualTo(pkg1.domainSetId) 265 assertThat(userState.isLinkHandlingAllowed).isEqualTo(true) 266 assertThat(userState.user.identifier).isEqualTo(USER_ID) 267 assertThat(userState.hostToStateMap).containsExactlyEntriesIn( 268 mapOf( 269 DOMAIN_1 to DOMAIN_STATE_NONE, 270 DOMAIN_2 to DOMAIN_STATE_NONE, 271 ) 272 ) 273 274 assertThat(service.queryValidVerificationPackageNames()) 275 .containsExactly(pkg1.packageName) 276 } 277 278 @Test 279 fun addPackageActive() { 280 // language=XML 281 val xml = """ 282 <?xml?> 283 <domain-verifications> 284 <active> 285 <package-state 286 packageName="${pkg1.packageName}" 287 id="${pkg1.domainSetId}" 288 > 289 <state> 290 <domain name="$DOMAIN_1" state="$STATE_SUCCESS"/> 291 </state> 292 <user-states> 293 <user-state userId="$USER_ID" allowLinkHandling="false"> 294 <enabled-hosts> 295 <host name="$DOMAIN_2"/> 296 </enabled-hosts> 297 </user-state> 298 </user-states> 299 </package-state> 300 </active> 301 </domain-verifications> 302 """.trimIndent() 303 304 val service = makeService(pkg1, pkg2) 305 val computer = mockComputer(pkg1, pkg2) 306 xml.byteInputStream().use { 307 service.readSettings(computer, Xml.resolvePullParser(it)) 308 } 309 310 service.addPackage(pkg1) 311 312 assertAddPackageActivePendingRestoredState(service) 313 } 314 315 @Test 316 fun addPackagePendingStripInvalidDomains() { 317 val xml = addPackagePendingOrRestoredWithInvalidDomains() 318 val service = makeService(pkg1, pkg2) 319 val computer = mockComputer(pkg1, pkg2) 320 xml.byteInputStream().use { 321 service.readSettings(computer, Xml.resolvePullParser(it)) 322 } 323 324 service.addPackage(pkg1) 325 326 val userState = service.getUserState(pkg1.packageName) 327 assertThat(userState.packageName).isEqualTo(pkg1.packageName) 328 assertThat(userState.identifier).isEqualTo(pkg1.domainSetId) 329 assertThat(userState.isLinkHandlingAllowed).isEqualTo(false) 330 assertThat(userState.user.identifier).isEqualTo(USER_ID) 331 assertThat(userState.hostToStateMap).containsExactlyEntriesIn(mapOf( 332 DOMAIN_1 to DOMAIN_STATE_VERIFIED, 333 DOMAIN_2 to DOMAIN_STATE_SELECTED, 334 )) 335 336 assertAddPackageActivePendingRestoredState(service) 337 } 338 339 @Test 340 fun addPackageRestoredStripInvalidDomains() { 341 val xml = addPackagePendingOrRestoredWithInvalidDomains() 342 val service = makeService(pkg1, pkg2) 343 val computer = mockComputer(pkg1, pkg2) 344 xml.byteInputStream().use { 345 service.restoreSettings(computer, Xml.resolvePullParser(it)) 346 } 347 348 service.addPackage(pkg1) 349 350 assertAddPackageActivePendingRestoredState(service, expectRestore = true) 351 } 352 353 /** 354 * Shared string that contains invalid [DOMAIN_3] and [DOMAIN_4] which should be stripped from 355 * the final state. 356 */ 357 private fun addPackagePendingOrRestoredWithInvalidDomains(): String = 358 // language=XML 359 """ 360 <?xml?> 361 <domain-verifications> 362 <active> 363 <package-state 364 packageName="${pkg1.packageName}" 365 id="${pkg1.domainSetId}" 366 signature="$DIGEST_ONE" 367 > 368 <state> 369 <domain name="$DOMAIN_1" state="$STATE_SUCCESS"/> 370 <domain name="$DOMAIN_3" state="$STATE_SUCCESS"/> 371 </state> 372 <user-states> 373 <user-state userId="$USER_ID" allowLinkHandling="false"> 374 <enabled-hosts> 375 <host name="$DOMAIN_2"/> 376 <host name="$DOMAIN_4"/> 377 </enabled-hosts> 378 </user-state> 379 <user-state userId="${USER_ID + 10}" allowLinkHandling="true"> 380 <enabled-hosts> 381 <host name="$DOMAIN_4"/> 382 </enabled-hosts> 383 </user-state> 384 </user-states> 385 </package-state> 386 </active> 387 </domain-verifications> 388 """.trimIndent() 389 390 /** 391 * Shared method to assert the same output when testing adding pkg1. 392 */ 393 private fun assertAddPackageActivePendingRestoredState( 394 service: DomainVerificationService, 395 expectRestore: Boolean = false 396 ) { 397 val info = service.getInfo(pkg1.packageName) 398 assertThat(info.packageName).isEqualTo(pkg1.packageName) 399 assertThat(info.identifier).isEqualTo(pkg1.domainSetId) 400 assertThat(info.hostToStateMap).containsExactlyEntriesIn(mapOf( 401 // To share the majority of code, special case restoration to check a different int 402 DOMAIN_1 to if (expectRestore) STATE_MODIFIABLE_VERIFIED else STATE_SUCCESS, 403 DOMAIN_2 to STATE_NO_RESPONSE, 404 )) 405 406 val userState = service.getUserState(pkg1.packageName) 407 assertThat(userState.packageName).isEqualTo(pkg1.packageName) 408 assertThat(userState.identifier).isEqualTo(pkg1.domainSetId) 409 assertThat(userState.isLinkHandlingAllowed).isEqualTo(false) 410 assertThat(userState.user.identifier).isEqualTo(USER_ID) 411 assertThat(userState.hostToStateMap).containsExactlyEntriesIn(mapOf( 412 DOMAIN_1 to DOMAIN_STATE_VERIFIED, 413 DOMAIN_2 to DOMAIN_STATE_SELECTED, 414 )) 415 416 assertThat(service.queryValidVerificationPackageNames()) 417 .containsExactly(pkg1.packageName) 418 419 // Re-enable link handling to check that the 3/4 domains were stripped 420 service.setDomainVerificationLinkHandlingAllowed(pkg1.packageName, true, USER_ID) 421 422 assertThat(service.getOwnersForDomain(DOMAIN_1, USER_ID)) 423 .containsExactly(DomainOwner(PKG_ONE, false)) 424 425 assertThat(service.getOwnersForDomain(DOMAIN_2, USER_ID)) 426 .containsExactly(DomainOwner(PKG_ONE, true)) 427 428 assertThat(service.getOwnersForDomain(DOMAIN_2, USER_ID + 10)).isEmpty() 429 430 listOf(DOMAIN_3, DOMAIN_4).forEach { domain -> 431 listOf(USER_ID, USER_ID + 10).forEach { userId -> 432 assertThat(service.getOwnersForDomain(domain, userId)).isEmpty() 433 } 434 } 435 } 436 437 @Test 438 fun migratePackageDropDomain() { 439 val pkgName = PKG_ONE 440 val pkgBefore = mockPkgState(pkgName, UUID_ONE, SIGNATURE_ONE, 441 listOf(DOMAIN_1, DOMAIN_2, DOMAIN_3, DOMAIN_4)) 442 val pkgAfter = mockPkgState(pkgName, UUID_TWO, SIGNATURE_TWO, listOf(DOMAIN_1, DOMAIN_2)) 443 444 // Test 4 domains: 445 // 1 will be approved and preserved, 2 will be selected and preserved, 446 // 3 will be denied and dropped, 4 will be selected and dropped 447 448 val map = mutableMapOf<String, PackageStateInternal>() 449 val service = makeService { map[it] } 450 service.addPackage(pkgBefore) 451 452 // Only insert the package after addPackage call to ensure the service doesn't access 453 // a live package inside the addPackage logic. It should only use the provided input. 454 map[pkgName] = pkgBefore 455 456 // To test the approve/denial states, use the internal methods for this variant 457 service.setDomainVerificationStatusInternal(pkgName, DomainVerificationState.STATE_APPROVED, 458 ArraySet(setOf(DOMAIN_1))) 459 service.setDomainVerificationStatusInternal(pkgName, DomainVerificationState.STATE_DENIED, 460 ArraySet(setOf(DOMAIN_3))) 461 service.setUserSelection( 462 UUID_ONE, setOf(DOMAIN_2, DOMAIN_4), true, USER_ID) 463 464 // Check the verifier cannot change the shell approve/deny states 465 service.setStatus(UUID_ONE, setOf(DOMAIN_1, DOMAIN_3), STATE_SUCCESS) 466 467 assertThat(service.getInfo(pkgName).hostToStateMap).containsExactlyEntriesIn(mapOf( 468 DOMAIN_1 to STATE_UNMODIFIABLE, 469 DOMAIN_2 to STATE_NO_RESPONSE, 470 DOMAIN_3 to STATE_UNMODIFIABLE, 471 DOMAIN_4 to STATE_NO_RESPONSE, 472 )) 473 assertThat(service.getUserState(pkgName).hostToStateMap).containsExactlyEntriesIn(mapOf( 474 DOMAIN_1 to DOMAIN_STATE_VERIFIED, 475 DOMAIN_2 to DOMAIN_STATE_SELECTED, 476 DOMAIN_3 to DOMAIN_STATE_NONE, 477 DOMAIN_4 to DOMAIN_STATE_SELECTED, 478 )) 479 480 // Now remove the package because migrateState shouldn't use it either 481 map.remove(pkgName) 482 483 map[pkgName] = pkgAfter 484 485 service.migrateState(pkgBefore, pkgAfter) 486 487 assertThat(service.getInfo(pkgName).hostToStateMap).containsExactlyEntriesIn(mapOf( 488 DOMAIN_1 to STATE_UNMODIFIABLE, 489 DOMAIN_2 to STATE_NO_RESPONSE, 490 )) 491 assertThat(service.getUserState(pkgName).hostToStateMap).containsExactlyEntriesIn(mapOf( 492 DOMAIN_1 to DOMAIN_STATE_VERIFIED, 493 DOMAIN_2 to DOMAIN_STATE_SELECTED, 494 )) 495 assertThat(service.queryValidVerificationPackageNames()).containsExactly(pkgName) 496 } 497 498 @Test 499 fun migratePackageDropAll() { 500 val pkgName = PKG_ONE 501 val pkgBefore = mockPkgState(pkgName, UUID_ONE, SIGNATURE_ONE, listOf(DOMAIN_1, DOMAIN_2)) 502 val pkgAfter = mockPkgState(pkgName, UUID_TWO, SIGNATURE_TWO, emptyList()) 503 504 val map = mutableMapOf<String, PackageStateInternal>() 505 val service = makeService { map[it] } 506 service.addPackage(pkgBefore) 507 508 // Only insert the package after addPackage call to ensure the service doesn't access 509 // a live package inside the addPackage logic. It should only use the provided input. 510 map[pkgName] = pkgBefore 511 512 assertThat(service.getInfo(pkgName).hostToStateMap).containsExactlyEntriesIn(mapOf( 513 DOMAIN_1 to STATE_NO_RESPONSE, 514 DOMAIN_2 to STATE_NO_RESPONSE, 515 )) 516 assertThat(service.getUserState(pkgName).hostToStateMap).containsExactlyEntriesIn(mapOf( 517 DOMAIN_1 to DOMAIN_STATE_NONE, 518 DOMAIN_2 to DOMAIN_STATE_NONE, 519 )) 520 assertThat(service.queryValidVerificationPackageNames()).containsExactly(pkgName) 521 522 // Now remove the package because migrateState shouldn't use it either 523 map.remove(pkgName) 524 525 service.migrateState(pkgBefore, pkgAfter) 526 527 map[pkgName] = pkgAfter 528 529 assertThat(service.setStatus(UUID_ONE, setOf(DOMAIN_1), STATE_SUCCESS)) 530 .isNotEqualTo(DomainVerificationManager.STATUS_OK) 531 532 assertThat(service.setUserSelection(UUID_ONE, setOf(DOMAIN_2), true, USER_ID)) 533 .isNotEqualTo(DomainVerificationManager.STATUS_OK) 534 535 assertThat(service.getDomainVerificationInfo(pkgName)).isNull() 536 assertThat(service.getUserState(pkgName).hostToStateMap).isEmpty() 537 assertThat(service.queryValidVerificationPackageNames()).isEmpty() 538 } 539 540 @Test 541 fun migratePackageAddDomain() { 542 val pkgName = PKG_ONE 543 val pkgBefore = mockPkgState(pkgName, UUID_ONE, SIGNATURE_ONE, listOf(DOMAIN_1, DOMAIN_2)) 544 val pkgAfter = mockPkgState(pkgName, UUID_TWO, SIGNATURE_TWO, 545 listOf(DOMAIN_1, DOMAIN_2, DOMAIN_3)) 546 547 // Test 3 domains: 548 // 1 will be verified and preserved, 2 will be selected and preserved, 549 // 3 will be new and default 550 551 val map = mutableMapOf<String, PackageStateInternal>() 552 val service = makeService { map[it] } 553 service.addPackage(pkgBefore) 554 555 // Only insert the package after addPackage call to ensure the service doesn't access 556 // a live package inside the addPackage logic. It should only use the provided input. 557 map[pkgName] = pkgBefore 558 559 service.setStatus(UUID_ONE, setOf(DOMAIN_1), STATE_SUCCESS) 560 service.setUserSelection(UUID_ONE, setOf(DOMAIN_2), true, USER_ID) 561 562 assertThat(service.getInfo(pkgName).hostToStateMap).containsExactlyEntriesIn(mapOf( 563 DOMAIN_1 to STATE_SUCCESS, 564 DOMAIN_2 to STATE_NO_RESPONSE, 565 )) 566 assertThat(service.getUserState(pkgName).hostToStateMap).containsExactlyEntriesIn(mapOf( 567 DOMAIN_1 to DOMAIN_STATE_VERIFIED, 568 DOMAIN_2 to DOMAIN_STATE_SELECTED, 569 )) 570 571 // Now remove the package because migrateState shouldn't use it either 572 map.remove(pkgName) 573 574 service.migrateState(pkgBefore, pkgAfter) 575 576 map[pkgName] = pkgAfter 577 578 assertThat(service.getInfo(pkgName).hostToStateMap).containsExactlyEntriesIn(mapOf( 579 DOMAIN_1 to STATE_SUCCESS, 580 DOMAIN_2 to STATE_NO_RESPONSE, 581 DOMAIN_3 to STATE_NO_RESPONSE, 582 )) 583 assertThat(service.getUserState(pkgName).hostToStateMap).containsExactlyEntriesIn(mapOf( 584 DOMAIN_1 to DOMAIN_STATE_VERIFIED, 585 DOMAIN_2 to DOMAIN_STATE_SELECTED, 586 DOMAIN_3 to DOMAIN_STATE_NONE, 587 )) 588 assertThat(service.queryValidVerificationPackageNames()).containsExactly(pkgName) 589 } 590 591 @Test 592 fun migratePackageAddAll() { 593 val pkgName = PKG_ONE 594 val pkgBefore = mockPkgState(pkgName, UUID_ONE, SIGNATURE_ONE, emptyList()) 595 val pkgAfter = mockPkgState(pkgName, UUID_TWO, SIGNATURE_TWO, listOf(DOMAIN_1, DOMAIN_2)) 596 597 val map = mutableMapOf<String, PackageStateInternal>() 598 val service = makeService { map[it] } 599 service.addPackage(pkgBefore) 600 601 // Only insert the package after addPackage call to ensure the service doesn't access 602 // a live package inside the addPackage logic. It should only use the provided input. 603 map[pkgName] = pkgBefore 604 605 assertThat(service.setStatus(UUID_ONE, setOf(DOMAIN_1), STATE_SUCCESS)) 606 .isNotEqualTo(DomainVerificationManager.STATUS_OK) 607 608 assertThat(service.setUserSelection(UUID_ONE, setOf(DOMAIN_2), true, USER_ID)) 609 .isNotEqualTo(DomainVerificationManager.STATUS_OK) 610 611 assertThat(service.getDomainVerificationInfo(pkgName)).isNull() 612 assertThat(service.getUserState(pkgName).hostToStateMap).isEmpty() 613 assertThat(service.queryValidVerificationPackageNames()).isEmpty() 614 615 // Now remove the package because migrateState shouldn't use it either 616 map.remove(pkgName) 617 618 service.migrateState(pkgBefore, pkgAfter) 619 620 map[pkgName] = pkgAfter 621 622 assertThat(service.getInfo(pkgName).hostToStateMap).containsExactlyEntriesIn(mapOf( 623 DOMAIN_1 to STATE_NO_RESPONSE, 624 DOMAIN_2 to STATE_NO_RESPONSE, 625 )) 626 assertThat(service.getUserState(pkgName).hostToStateMap).containsExactlyEntriesIn(mapOf( 627 DOMAIN_1 to DOMAIN_STATE_NONE, 628 DOMAIN_2 to DOMAIN_STATE_NONE, 629 )) 630 assertThat(service.queryValidVerificationPackageNames()).containsExactly(pkgName) 631 } 632 633 @Test 634 fun migratePackageSelected() { 635 val pkgName = PKG_ONE 636 val pkgBefore = mockPkgState(pkgName, UUID_ONE, SIGNATURE_ONE, 637 listOf(DOMAIN_1), listOf(DOMAIN_2)) 638 val pkgAfter = mockPkgState(pkgName, UUID_TWO, SIGNATURE_TWO, 639 listOf(DOMAIN_1), listOf(DOMAIN_2)) 640 641 val map = mutableMapOf<String, PackageStateInternal>() 642 val service = makeService { map[it] } 643 service.addPackage(pkgBefore) 644 645 // Only insert the package after addPackage call to ensure the service doesn't access 646 // a live package inside the addPackage logic. It should only use the provided input. 647 map[pkgName] = pkgBefore 648 649 assertThat(service.setStatus(UUID_ONE, setOf(DOMAIN_1), STATE_SUCCESS)) 650 .isEqualTo(DomainVerificationManager.STATUS_OK) 651 652 assertThat(service.setUserSelection(UUID_ONE, setOf(DOMAIN_2), true, USER_ID)) 653 .isEqualTo(DomainVerificationManager.STATUS_OK) 654 655 service.getInfo(pkgName).run { 656 assertThat(identifier).isEqualTo(UUID_ONE) 657 assertThat(hostToStateMap).containsExactlyEntriesIn(mapOf( 658 DOMAIN_1 to STATE_SUCCESS, 659 )) 660 } 661 assertThat(service.getUserState(pkgName).hostToStateMap).containsExactlyEntriesIn(mapOf( 662 DOMAIN_1 to DOMAIN_STATE_VERIFIED, 663 DOMAIN_2 to DOMAIN_STATE_SELECTED, 664 )) 665 assertThat(service.queryValidVerificationPackageNames()).containsExactly(pkgName) 666 667 // Now remove the package because migrateState shouldn't use it either 668 map.remove(pkgName) 669 670 service.migrateState(pkgBefore, pkgAfter) 671 672 map[pkgName] = pkgAfter 673 674 service.getInfo(pkgName).run { 675 assertThat(identifier).isEqualTo(UUID_TWO) 676 assertThat(hostToStateMap).containsExactlyEntriesIn(mapOf( 677 DOMAIN_1 to STATE_SUCCESS, 678 )) 679 } 680 assertThat(service.getUserState(pkgName).hostToStateMap).containsExactlyEntriesIn(mapOf( 681 DOMAIN_1 to DOMAIN_STATE_VERIFIED, 682 DOMAIN_2 to DOMAIN_STATE_SELECTED, 683 )) 684 assertThat(service.queryValidVerificationPackageNames()).containsExactly(pkgName) 685 } 686 687 @Test 688 fun backupAndRestore() { 689 // This test acts as a proxy for true user restore through PackageManager, 690 // as that's much harder to test for real. 691 692 val pkg1 = mockPkgState(PKG_ONE, UUID_ONE, SIGNATURE_ONE, listOf(DOMAIN_1, DOMAIN_2)) 693 val pkg2 = mockPkgState(PKG_TWO, UUID_TWO, SIGNATURE_TWO, 694 listOf(DOMAIN_1, DOMAIN_2, DOMAIN_3)) 695 val serviceBefore = makeService(pkg1, pkg2) 696 val computerBefore = mockComputer(pkg1, pkg2) 697 serviceBefore.addPackage(pkg1) 698 serviceBefore.addPackage(pkg2) 699 700 serviceBefore.setStatus(pkg1.domainSetId, setOf(DOMAIN_1), STATE_SUCCESS) 701 serviceBefore.setDomainVerificationLinkHandlingAllowed(pkg1.packageName, false, 10) 702 serviceBefore.setUserSelection(pkg2.domainSetId, setOf(DOMAIN_2), true, 0) 703 serviceBefore.setUserSelection(pkg2.domainSetId, setOf(DOMAIN_3), true, 10) 704 705 fun assertExpectedState(service: DomainVerificationService) { 706 service.assertState( 707 pkg1, userId = 0, hostToStateMap = mapOf( 708 DOMAIN_1 to DOMAIN_STATE_VERIFIED, 709 DOMAIN_2 to DOMAIN_STATE_NONE, 710 ) 711 ) 712 713 service.assertState( 714 pkg1, userId = 10, linkHandingAllowed = false, hostToStateMap = mapOf( 715 DOMAIN_1 to DOMAIN_STATE_VERIFIED, 716 DOMAIN_2 to DOMAIN_STATE_NONE, 717 ) 718 ) 719 720 service.assertState( 721 pkg2, userId = 0, hostToStateMap = mapOf( 722 DOMAIN_1 to DOMAIN_STATE_NONE, 723 DOMAIN_2 to DOMAIN_STATE_SELECTED, 724 DOMAIN_3 to DOMAIN_STATE_NONE 725 ) 726 ) 727 728 service.assertState( 729 pkg2, userId = 10, hostToStateMap = mapOf( 730 DOMAIN_1 to DOMAIN_STATE_NONE, 731 DOMAIN_2 to DOMAIN_STATE_NONE, 732 DOMAIN_3 to DOMAIN_STATE_SELECTED, 733 ) 734 ) 735 } 736 737 assertExpectedState(serviceBefore) 738 739 val backupUser0 = ByteArrayOutputStream().use { 740 serviceBefore.writeSettings(computerBefore, Xml.resolveSerializer(it), true, 0) 741 it.toByteArray() 742 } 743 744 val backupUser1 = ByteArrayOutputStream().use { 745 serviceBefore.writeSettings(computerBefore, Xml.resolveSerializer(it), true, 10) 746 it.toByteArray() 747 } 748 749 val serviceAfter = makeService(pkg1, pkg2) 750 val computerAfter = mockComputer(pkg1, pkg2) 751 serviceAfter.addPackage(pkg1) 752 serviceAfter.addPackage(pkg2) 753 754 // Check the state is default before the restoration applies 755 listOf(0, 10).forEach { 756 serviceAfter.assertState( 757 pkg1, userId = it, hostToStateMap = mapOf( 758 DOMAIN_1 to DOMAIN_STATE_NONE, 759 DOMAIN_2 to DOMAIN_STATE_NONE, 760 ) 761 ) 762 } 763 764 listOf(0, 10).forEach { 765 serviceAfter.assertState( 766 pkg2, userId = it, hostToStateMap = mapOf( 767 DOMAIN_1 to DOMAIN_STATE_NONE, 768 DOMAIN_2 to DOMAIN_STATE_NONE, 769 DOMAIN_3 to DOMAIN_STATE_NONE, 770 ) 771 ) 772 } 773 774 ByteArrayInputStream(backupUser1).use { 775 serviceAfter.restoreSettings(computerAfter, Xml.resolvePullParser(it)) 776 } 777 778 // Assert user 1 was restored 779 serviceAfter.assertState( 780 pkg1, userId = 10, linkHandingAllowed = false, hostToStateMap = mapOf( 781 DOMAIN_1 to DOMAIN_STATE_VERIFIED, 782 DOMAIN_2 to DOMAIN_STATE_NONE, 783 ) 784 ) 785 786 serviceAfter.assertState( 787 pkg2, userId = 10, hostToStateMap = mapOf( 788 DOMAIN_1 to DOMAIN_STATE_NONE, 789 DOMAIN_2 to DOMAIN_STATE_NONE, 790 DOMAIN_3 to DOMAIN_STATE_SELECTED, 791 ) 792 ) 793 794 // User 0 has domain verified (since that's not user-specific) 795 serviceAfter.assertState( 796 pkg1, userId = 0, hostToStateMap = mapOf( 797 DOMAIN_1 to DOMAIN_STATE_VERIFIED, 798 DOMAIN_2 to DOMAIN_STATE_NONE, 799 ) 800 ) 801 802 // But user 0 is missing any user selected state 803 serviceAfter.assertState( 804 pkg2, userId = 0, hostToStateMap = mapOf( 805 DOMAIN_1 to DOMAIN_STATE_NONE, 806 DOMAIN_2 to DOMAIN_STATE_NONE, 807 DOMAIN_3 to DOMAIN_STATE_NONE, 808 ) 809 ) 810 811 ByteArrayInputStream(backupUser0).use { 812 serviceAfter.restoreSettings(computerAfter, Xml.resolvePullParser(it)) 813 } 814 815 assertExpectedState(serviceAfter) 816 } 817 818 @Test 819 fun verifiedUnapproved_unverifiedSelected_approvalCausesUnselect_systemApi() { 820 verifiedUnapproved_unverifiedSelected_approvalCausesUnselect { 821 setDomainVerificationStatus(it.domainSetId, setOf(DOMAIN_1, DOMAIN_2), STATE_SUCCESS) 822 } 823 } 824 825 @Test 826 fun verifiedUnapproved_unverifiedSelected_approvalCausesUnselect_internalApi() { 827 verifiedUnapproved_unverifiedSelected_approvalCausesUnselect { 828 setDomainVerificationStatusInternal(it.packageName, STATE_SUCCESS, 829 ArraySet(setOf(DOMAIN_1, DOMAIN_2))) 830 } 831 } 832 833 private fun verifiedUnapproved_unverifiedSelected_approvalCausesUnselect( 834 setStatusBlock: DomainVerificationService.(PackageStateInternal) -> Unit 835 ) { 836 /* 837 Domains tested: 838 1: Becomes verified in package 1, but package 1 disabled in secondary user, only 839 disables selection for package 2 in main user 840 2: Becomes verified in package 1, unselected by package 2, remains unselected 841 3: Is autoVerify, but unverified, selected by package 2, remains selected 842 4: Non-autoVerify, selected by package 2, remains selected 843 */ 844 845 val pkg1 = mockPkgState( 846 PKG_ONE, 847 UUID_ONE, 848 SIGNATURE_ONE, 849 autoVerifyDomains = listOf(DOMAIN_1, DOMAIN_2, DOMAIN_3), 850 otherDomains = listOf(DOMAIN_4) 851 ) 852 val pkg2 = mockPkgState( 853 PKG_TWO, 854 UUID_TWO, 855 SIGNATURE_TWO, 856 autoVerifyDomains = emptyList(), 857 otherDomains = listOf(DOMAIN_1, DOMAIN_2, DOMAIN_3, DOMAIN_4) 858 ) 859 860 val service = makeService(pkg1, pkg2) 861 service.addPackage(pkg1) 862 service.addPackage(pkg2) 863 864 // Approve domain 1, 3, and 4 for package 2 for both users 865 USER_IDS.forEach { 866 assertThat( 867 service.setDomainVerificationUserSelection( 868 UUID_TWO, 869 setOf(DOMAIN_1, DOMAIN_3, DOMAIN_4), 870 true, 871 it 872 ) 873 ).isEqualTo(DomainVerificationManager.STATUS_OK) 874 } 875 876 // But disable the owner package link handling in the secondary user 877 service.setDomainVerificationLinkHandlingAllowed(pkg1.packageName, false, 878 USER_ID_SECONDARY 879 ) 880 881 service.assertState( 882 pkg1, 883 verifyState = listOf( 884 DOMAIN_1 to STATE_NO_RESPONSE, 885 DOMAIN_2 to STATE_NO_RESPONSE, 886 DOMAIN_3 to STATE_NO_RESPONSE, 887 ), 888 userState2LinkHandlingAllowed = false 889 ) 890 891 service.assertState( 892 pkg2, 893 verifyState = null, 894 userState1DomainState1 = DOMAIN_STATE_SELECTED, 895 userState1DomainState3 = DOMAIN_STATE_SELECTED, 896 userState1DomainState4 = DOMAIN_STATE_SELECTED, 897 userState2DomainState1 = DOMAIN_STATE_SELECTED, 898 userState2DomainState3 = DOMAIN_STATE_SELECTED, 899 userState2DomainState4 = DOMAIN_STATE_SELECTED, 900 ) 901 902 // Verify the owner package 903 service.setStatusBlock(pkg1) 904 905 // Assert that package 1 is now verified, but link handling disabled in secondary user 906 service.assertState( 907 pkg1, 908 verifyState = listOf( 909 DOMAIN_1 to STATE_SUCCESS, 910 DOMAIN_2 to STATE_SUCCESS, 911 DOMAIN_3 to STATE_NO_RESPONSE, 912 ), 913 userState1DomainState1 = DOMAIN_STATE_VERIFIED, 914 userState1DomainState2 = DOMAIN_STATE_VERIFIED, 915 userState1DomainState3 = DOMAIN_STATE_NONE, 916 userState1DomainState4 = DOMAIN_STATE_NONE, 917 userState2LinkHandlingAllowed = false, 918 userState2DomainState1 = DOMAIN_STATE_VERIFIED, 919 userState2DomainState2 = DOMAIN_STATE_VERIFIED, 920 userState2DomainState3 = DOMAIN_STATE_NONE, 921 userState2DomainState4 = DOMAIN_STATE_NONE, 922 ) 923 924 // Assert package 2 maintains selected in user where package 1 had link handling disabled 925 service.assertState( 926 pkg2, 927 verifyState = null, 928 userState1DomainState1 = DOMAIN_STATE_NONE, 929 userState1DomainState3 = DOMAIN_STATE_SELECTED, 930 userState1DomainState4 = DOMAIN_STATE_SELECTED, 931 userState2DomainState1 = DOMAIN_STATE_SELECTED, 932 userState2DomainState3 = DOMAIN_STATE_SELECTED, 933 userState2DomainState4 = DOMAIN_STATE_SELECTED, 934 ) 935 } 936 937 fun DomainVerificationService.assertState( 938 pkg: PackageStateInternal, 939 verifyState: List<Pair<String, Int>>?, 940 userState1LinkHandlingAllowed: Boolean = true, 941 userState1DomainState1: Int = DOMAIN_STATE_NONE, 942 userState1DomainState2: Int = DOMAIN_STATE_NONE, 943 userState1DomainState3: Int = DOMAIN_STATE_NONE, 944 userState1DomainState4: Int = DOMAIN_STATE_NONE, 945 userState2LinkHandlingAllowed: Boolean = true, 946 userState2DomainState1: Int = DOMAIN_STATE_NONE, 947 userState2DomainState2: Int = DOMAIN_STATE_NONE, 948 userState2DomainState3: Int = DOMAIN_STATE_NONE, 949 userState2DomainState4: Int = DOMAIN_STATE_NONE, 950 ) { 951 if (verifyState == null) { 952 // If no auto verify domains, the info itself will be null 953 assertThat(getDomainVerificationInfo(pkg.packageName)).isNull() 954 } else { 955 getInfo(pkg.packageName).run { 956 assertThat(hostToStateMap).containsExactlyEntriesIn(verifyState.associate { it }) 957 } 958 } 959 960 getUserState(pkg.packageName, USER_ID).run { 961 assertThat(isLinkHandlingAllowed).isEqualTo(userState1LinkHandlingAllowed) 962 assertThat(hostToStateMap).containsExactlyEntriesIn( 963 mapOf( 964 DOMAIN_1 to userState1DomainState1, 965 DOMAIN_2 to userState1DomainState2, 966 DOMAIN_3 to userState1DomainState3, 967 DOMAIN_4 to userState1DomainState4, 968 ) 969 ) 970 } 971 972 getUserState(pkg.packageName, USER_ID_SECONDARY).run { 973 assertThat(isLinkHandlingAllowed).isEqualTo(userState2LinkHandlingAllowed) 974 assertThat(hostToStateMap).containsExactlyEntriesIn( 975 mapOf( 976 DOMAIN_1 to userState2DomainState1, 977 DOMAIN_2 to userState2DomainState2, 978 DOMAIN_3 to userState2DomainState3, 979 DOMAIN_4 to userState2DomainState4, 980 ) 981 ) 982 } 983 } 984 985 private fun DomainVerificationService.getInfo(pkgName: String) = 986 getDomainVerificationInfo(pkgName) 987 .also { assertThat(it).isNotNull() }!! 988 989 private fun DomainVerificationService.getUserState(pkgName: String, userId: Int = USER_ID) = 990 getDomainVerificationUserState(pkgName, userId) 991 .also { assertThat(it).isNotNull() }!! 992 993 private fun makeService( 994 systemConfiguredPackageNames: ArraySet<String> = ArraySet(), 995 vararg pkgStates: PackageStateInternal 996 ) = makeService(systemConfiguredPackageNames = systemConfiguredPackageNames) { 997 pkgName -> pkgStates.find { pkgName == it.packageName } 998 } 999 1000 private fun makeService(vararg pkgStates: PackageStateInternal) = 1001 makeService { pkgName -> pkgStates.find { pkgName == it.packageName } } 1002 1003 private fun makeService( 1004 systemConfiguredPackageNames: ArraySet<String> = ArraySet(), 1005 pkgStateFunction: (String) -> PackageStateInternal? = { null } 1006 ) = DomainVerificationService(mockThrowOnUnmocked { 1007 // Assume the test has every permission necessary 1008 whenever(enforcePermission(anyString(), anyInt(), anyInt(), anyString())) 1009 whenever(checkPermission(anyString(), anyInt(), anyInt())) { 1010 PackageManager.PERMISSION_GRANTED 1011 } 1012 }, mockThrowOnUnmocked { 1013 whenever(this.linkedApps) { systemConfiguredPackageNames } 1014 }, mockThrowOnUnmocked { 1015 whenever(isChangeEnabledInternalNoLogging(anyLong(), any())) { true } 1016 }).apply { 1017 setConnection(mockThrowOnUnmocked { 1018 whenever(filterAppAccess(anyString(), anyInt(), anyInt())) { false } 1019 whenever(doesUserExist(0)) { true } 1020 whenever(doesUserExist(10)) { true } 1021 whenever(scheduleWriteSettings()) 1022 1023 // Need to provide an internal UID so some permission checks are ignored 1024 whenever(callingUid) { Process.ROOT_UID } 1025 whenever(callingUserId) { 0 } 1026 1027 whenever(snapshot()) { mockComputer(pkgStateFunction) } 1028 }) 1029 } 1030 1031 private fun mockComputer(vararg pkgStates: PackageStateInternal) = 1032 mockComputer { pkgName -> pkgStates.find { pkgName == it.packageName } } 1033 1034 private fun mockComputer(pkgStateFunction: (String) -> PackageStateInternal? = { null }) = 1035 mockThrowOnUnmocked<Computer> { 1036 whenever(getPackageStateInternal(anyString())) { 1037 pkgStateFunction(getArgument(0)) 1038 } 1039 } 1040 1041 private fun mockPkgState( 1042 pkgName: String, 1043 domainSetId: UUID, 1044 signature: String, 1045 autoVerifyDomains: List<String> = listOf(DOMAIN_1, DOMAIN_2), 1046 otherDomains: List<String> = listOf(), 1047 isSystemApp: Boolean = false 1048 ) = mockThrowOnUnmocked<PackageStateInternal> { 1049 val pkg = mockThrowOnUnmocked<AndroidPackage> { 1050 whenever(packageName) { pkgName } 1051 whenever(targetSdkVersion) { Build.VERSION_CODES.S } 1052 whenever(isEnabled) { true } 1053 1054 fun baseIntent(domain: String) = ParsedIntentInfoImpl() 1055 .apply { 1056 intentFilter.apply { 1057 addAction(Intent.ACTION_VIEW) 1058 addCategory(Intent.CATEGORY_BROWSABLE) 1059 addCategory(Intent.CATEGORY_DEFAULT) 1060 addDataScheme("http") 1061 addDataScheme("https") 1062 addDataPath("/sub", PatternMatcher.PATTERN_LITERAL) 1063 addDataAuthority(domain, null) 1064 } 1065 } 1066 1067 val activityList = listOf( 1068 ParsedActivityImpl().apply { 1069 autoVerifyDomains.forEach { 1070 addIntent(baseIntent(it).apply { intentFilter.autoVerify = true }) 1071 } 1072 otherDomains.forEach { 1073 addIntent(baseIntent(it).apply { intentFilter.autoVerify = false }) 1074 } 1075 }, 1076 ) 1077 1078 whenever(activities) { activityList } 1079 } 1080 1081 whenever(this.pkg) { pkg } 1082 whenever(packageName) { pkgName } 1083 whenever(this.domainSetId) { domainSetId } 1084 whenever(getUserStateOrDefault(0)) { PackageUserStateInternal.DEFAULT } 1085 whenever(getUserStateOrDefault(10)) { PackageUserStateInternal.DEFAULT } 1086 whenever(userStates) { 1087 SparseArray<PackageUserStateInternal>().apply { 1088 this[0] = PackageUserStateInternal.DEFAULT 1089 this[1] = PackageUserStateInternal.DEFAULT 1090 } 1091 } 1092 whenever(isSystem) { isSystemApp } 1093 1094 val mockSigningDetails = SigningDetails(arrayOf(spy(Signature(signature)) { 1095 doReturn(mock<PublicKey>()).whenever(this).publicKey 1096 }), SigningDetails.SignatureSchemeVersion.UNKNOWN) 1097 whenever(signingDetails).thenReturn(mockSigningDetails) 1098 } 1099 1100 private fun DomainVerificationService.assertState( 1101 pkg: PackageStateInternal, 1102 userId: Int, 1103 linkHandingAllowed: Boolean = true, 1104 hostToStateMap: Map<String, Int> 1105 ) { 1106 getUserState(pkg.packageName, userId).apply { 1107 assertThat(this.packageName).isEqualTo(pkg.packageName) 1108 assertThat(this.identifier).isEqualTo(pkg.domainSetId) 1109 assertThat(this.isLinkHandlingAllowed).isEqualTo(linkHandingAllowed) 1110 assertThat(this.user.identifier).isEqualTo(userId) 1111 assertThat(this.hostToStateMap).containsExactlyEntriesIn(hostToStateMap) 1112 } 1113 } 1114 } 1115