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