• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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