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