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.permission.access.permission
18 
19 import android.Manifest
20 import android.content.pm.PackageManager
21 import android.content.pm.PermissionGroupInfo
22 import android.content.pm.PermissionInfo
23 import android.content.pm.SigningDetails
24 import android.os.Build
25 import android.permission.flags.Flags
26 import android.util.Slog
27 import com.android.internal.os.RoSystemProperties
28 import com.android.internal.pm.permission.CompatibilityPermissionInfo
29 import com.android.modules.utils.BinaryXmlPullParser
30 import com.android.modules.utils.BinaryXmlSerializer
31 import com.android.server.permission.access.AccessState
32 import com.android.server.permission.access.GetStateScope
33 import com.android.server.permission.access.MutableAccessState
34 import com.android.server.permission.access.MutateStateScope
35 import com.android.server.permission.access.PermissionUri
36 import com.android.server.permission.access.SchemePolicy
37 import com.android.server.permission.access.UidUri
38 import com.android.server.permission.access.WriteMode
39 import com.android.server.permission.access.collection.* // ktlint-disable no-wildcard-imports
40 import com.android.server.permission.access.immutable.* // ktlint-disable no-wildcard-imports
41 import com.android.server.permission.access.util.andInv
42 import com.android.server.permission.access.util.hasAnyBit
43 import com.android.server.permission.access.util.hasBits
44 import com.android.server.permission.access.util.isInternal
45 import com.android.server.pm.KnownPackages
46 import com.android.server.pm.parsing.PackageInfoUtils
47 import com.android.server.pm.pkg.AndroidPackage
48 import com.android.server.pm.pkg.PackageState
49 import libcore.util.EmptyArray
50 
51 class AppIdPermissionPolicy : SchemePolicy() {
52     private val persistence = AppIdPermissionPersistence()
53 
54     private val migration = AppIdPermissionMigration()
55 
56     private val upgrade = AppIdPermissionUpgrade(this)
57 
58     @Volatile
59     private var onPermissionFlagsChangedListeners:
60         IndexedListSet<OnPermissionFlagsChangedListener> =
61         MutableIndexedListSet()
62     private val onPermissionFlagsChangedListenersLock = Any()
63 
64     private val privilegedPermissionAllowlistViolations = MutableIndexedSet<String>()
65 
66     /** Test-only switch to enforce signature permission allowlist even on debuggable builds. */
67     @Volatile var isSignaturePermissionAllowlistForceEnforced = false
68 
69     override val subjectScheme: String
70         get() = UidUri.SCHEME
71 
72     override val objectScheme: String
73         get() = PermissionUri.SCHEME
74 
75     override fun GetStateScope.onStateMutated() {
76         onPermissionFlagsChangedListeners.forEachIndexed { _, it -> it.onStateMutated() }
77     }
78 
79     override fun MutateStateScope.onUserAdded(userId: Int) {
80         newState.externalState.packageStates.forEach { (_, packageState) ->
81             if (packageState.isApex) {
82                 return@forEach
83             }
84             evaluateAllPermissionStatesForPackageAndUser(packageState, userId, null)
85         }
86         newState.externalState.appIdPackageNames.forEachIndexed { _, appId, _ ->
87             inheritImplicitPermissionStates(appId, userId)
88         }
89     }
90 
91     override fun MutateStateScope.onAppIdRemoved(appId: Int) {
92         newState.userStates.forEachIndexed { userStateIndex, _, userState ->
93             if (appId in userState.appIdPermissionFlags) {
94                 newState.mutateUserStateAt(userStateIndex).mutateAppIdPermissionFlags() -= appId
95                 // Skip notifying the change listeners since the app ID no longer exists.
96             }
97         }
98     }
99 
100     override fun MutateStateScope.onStorageVolumeMounted(
101         volumeUuid: String?,
102         packageNames: List<String>,
103         isSystemUpdated: Boolean
104     ) {
105         val changedPermissionNames = MutableIndexedSet<String>()
106         packageNames.forEachIndexed { _, packageName ->
107             // The package may still be removed even if it was once notified as installed.
108             val packageState =
109                 newState.externalState.packageStates[packageName] ?: return@forEachIndexed
110             adoptPermissions(packageState, changedPermissionNames)
111             addPermissionGroups(packageState)
112             addPermissions(packageState, changedPermissionNames)
113             trimPermissions(packageState.packageName, changedPermissionNames)
114             trimPermissionStates(packageState.appId)
115             revokePermissionsOnPackageUpdate(packageState.appId)
116         }
117         changedPermissionNames.forEachIndexed { _, permissionName ->
118             evaluatePermissionStateForAllPackages(permissionName, null)
119         }
120 
121         packageNames.forEachIndexed { _, packageName ->
122             val packageState =
123                 newState.externalState.packageStates[packageName] ?: return@forEachIndexed
124             val installedPackageState = if (isSystemUpdated) packageState else null
125             evaluateAllPermissionStatesForPackage(packageState, installedPackageState)
126         }
127         packageNames.forEachIndexed { _, packageName ->
128             val packageState =
129                 newState.externalState.packageStates[packageName] ?: return@forEachIndexed
130             newState.externalState.userIds.forEachIndexed { _, userId ->
131                 inheritImplicitPermissionStates(packageState.appId, userId)
132             }
133         }
134     }
135 
136     override fun MutateStateScope.onPackageAdded(packageState: PackageState) {
137         val changedPermissionNames = MutableIndexedSet<String>()
138         adoptPermissions(packageState, changedPermissionNames)
139         addPermissionGroups(packageState)
140         addPermissions(packageState, changedPermissionNames)
141         trimPermissions(packageState.packageName, changedPermissionNames)
142         trimPermissionStates(packageState.appId)
143         revokePermissionsOnPackageUpdate(packageState.appId)
144         changedPermissionNames.forEachIndexed { _, permissionName ->
145             evaluatePermissionStateForAllPackages(permissionName, null)
146         }
147         evaluateAllPermissionStatesForPackage(packageState, packageState)
148         newState.externalState.userIds.forEachIndexed { _, userId ->
149             inheritImplicitPermissionStates(packageState.appId, userId)
150         }
151     }
152 
153     override fun MutateStateScope.onPackageRemoved(packageName: String, appId: Int) {
154         check(packageName !in newState.externalState.disabledSystemPackageStates) {
155             "Package $packageName reported as removed before disabled system package is enabled"
156         }
157 
158         val changedPermissionNames = MutableIndexedSet<String>()
159         trimPermissions(packageName, changedPermissionNames)
160         if (appId in newState.externalState.appIdPackageNames) {
161             trimPermissionStates(appId)
162         }
163         changedPermissionNames.forEachIndexed { _, permissionName ->
164             evaluatePermissionStateForAllPackages(permissionName, null)
165         }
166     }
167 
168     override fun MutateStateScope.onPackageInstalled(packageState: PackageState, userId: Int) {
169         // Clear UPGRADE_EXEMPT for all permissions requested by this package since there's
170         // an installer and the installer has made a decision.
171         clearRestrictedPermissionImplicitExemption(packageState, userId)
172     }
173 
174     private fun MutateStateScope.clearRestrictedPermissionImplicitExemption(
175         packageState: PackageState,
176         userId: Int
177     ) {
178         // System apps can always retain their UPGRADE_EXEMPT.
179         if (packageState.isSystem) {
180             return
181         }
182         val androidPackage = packageState.androidPackage ?: return
183         val appId = packageState.appId
184         androidPackage.requestedPermissions.forEach { permissionName ->
185             val permission = newState.systemState.permissions[permissionName] ?: return@forEach
186             if (!permission.isHardOrSoftRestricted) {
187                 return@forEach
188             }
189             val isRequestedBySystemPackage =
190                 anyPackageInAppId(appId) {
191                     it.isSystem && permissionName in it.androidPackage!!.requestedPermissions
192                 }
193             if (isRequestedBySystemPackage) {
194                 return@forEach
195             }
196             updatePermissionExemptFlags(
197                 appId,
198                 userId,
199                 permission,
200                 PermissionFlags.UPGRADE_EXEMPT,
201                 0
202             )
203         }
204     }
205 
206     fun MutateStateScope.updatePermissionExemptFlags(
207         appId: Int,
208         userId: Int,
209         permission: Permission,
210         exemptFlagMask: Int,
211         exemptFlagValues: Int
212     ) {
213         val permissionName = permission.name
214         val oldFlags = getPermissionFlags(appId, userId, permissionName)
215         var newFlags = (oldFlags andInv exemptFlagMask) or (exemptFlagValues and exemptFlagMask)
216         if (oldFlags == newFlags) {
217             return
218         }
219         val isExempt = newFlags.hasAnyBit(PermissionFlags.MASK_EXEMPT)
220         if (permission.isHardRestricted && !isExempt) {
221             newFlags = newFlags or PermissionFlags.RESTRICTION_REVOKED
222             // If the permission was policy fixed as granted but it is no longer on any of the
223             // allowlists we need to clear the policy fixed flag as allowlisting trumps policy i.e.
224             // policy cannot grant a non grantable permission.
225             if (PermissionFlags.isPermissionGranted(oldFlags)) {
226                 newFlags = newFlags andInv PermissionFlags.POLICY_FIXED
227             }
228         } else {
229             newFlags = newFlags andInv PermissionFlags.RESTRICTION_REVOKED
230         }
231         val isSoftRestricted =
232             if (permission.isSoftRestricted && !isExempt) {
233                 val targetSdkVersion =
234                     reducePackageInAppId(appId, Build.VERSION_CODES.CUR_DEVELOPMENT) {
235                         targetSdkVersion,
236                         packageState ->
237                         if (permissionName in packageState.androidPackage!!.requestedPermissions) {
238                             targetSdkVersion.coerceAtMost(
239                                 packageState.androidPackage!!.targetSdkVersion
240                             )
241                         } else {
242                             targetSdkVersion
243                         }
244                     }
245                 !anyPackageInAppId(appId) {
246                     permissionName in it.androidPackage!!.requestedPermissions &&
247                         isSoftRestrictedPermissionExemptForPackage(
248                             it,
249                             targetSdkVersion,
250                             permissionName
251                         )
252                 }
253             } else {
254                 false
255             }
256         newFlags =
257             if (isSoftRestricted) {
258                 newFlags or PermissionFlags.SOFT_RESTRICTED
259             } else {
260                 newFlags andInv PermissionFlags.SOFT_RESTRICTED
261             }
262         if (oldFlags == newFlags) {
263             return
264         }
265         setPermissionFlags(appId, userId, permissionName, newFlags)
266     }
267 
268     override fun MutateStateScope.onPackageUninstalled(
269         packageName: String,
270         appId: Int,
271         userId: Int
272     ) {
273         resetRuntimePermissions(packageName, userId)
274     }
275 
276     fun MutateStateScope.resetRuntimePermissions(packageName: String, userId: Int) {
277         // It's okay to skip resetting permissions for packages that are removed,
278         // because their states will be trimmed in onPackageRemoved()/onAppIdRemoved()
279         val packageState = newState.externalState.packageStates[packageName] ?: return
280         val androidPackage = packageState.androidPackage ?: return
281         val appId = packageState.appId
282         androidPackage.requestedPermissions.forEach { permissionName ->
283             val permission = newState.systemState.permissions[permissionName] ?: return@forEach
284             if (!permission.isRuntime || permission.isRemoved) {
285                 return@forEach
286             }
287             val isRequestedByOtherPackages =
288                 anyPackageInAppId(appId) {
289                     it.packageName != packageName &&
290                         permissionName in it.androidPackage!!.requestedPermissions
291                 }
292             if (isRequestedByOtherPackages) {
293                 return@forEach
294             }
295             val oldFlags = getPermissionFlags(appId, userId, permissionName)
296             if (oldFlags.hasAnyBit(SYSTEM_OR_POLICY_FIXED_MASK)) {
297                 return@forEach
298             }
299             var newFlags = oldFlags
300             newFlags =
301                 if (
302                     newFlags.hasBits(PermissionFlags.ROLE) ||
303                         newFlags.hasBits(PermissionFlags.PREGRANT)
304                 ) {
305                     newFlags or PermissionFlags.RUNTIME_GRANTED
306                 } else {
307                     newFlags andInv PermissionFlags.RUNTIME_GRANTED
308                 }
309             newFlags = newFlags andInv USER_SETTABLE_MASK
310             if (newFlags.hasBits(PermissionFlags.LEGACY_GRANTED)) {
311                 newFlags = newFlags or PermissionFlags.IMPLICIT
312             }
313             setPermissionFlags(appId, userId, permissionName, newFlags)
314         }
315     }
316 
317     private fun MutateStateScope.adoptPermissions(
318         packageState: PackageState,
319         changedPermissionNames: MutableIndexedSet<String>
320     ) {
321         val `package` = packageState.androidPackage!!
322         `package`.adoptPermissions.forEachIndexed { _, originalPackageName ->
323             val packageName = `package`.packageName
324             if (!canAdoptPermissions(packageName, originalPackageName)) {
325                 return@forEachIndexed
326             }
327             newState.systemState.permissions.forEachIndexed permissions@{
328                 permissionIndex,
329                 permissionName,
330                 oldPermission ->
331                 if (oldPermission.packageName != originalPackageName) {
332                     return@permissions
333                 }
334                 @Suppress("DEPRECATION")
335                 val newPermissionInfo =
336                     PermissionInfo().apply {
337                         name = oldPermission.permissionInfo.name
338                         this.packageName = packageName
339                         protectionLevel = oldPermission.permissionInfo.protectionLevel
340                     }
341                 // Different from the old implementation, which removes the GIDs upon permission
342                 // adoption, but adds them back on the next boot, we now just consistently keep the
343                 // GIDs.
344                 val newPermission =
345                     oldPermission.copy(
346                         permissionInfo = newPermissionInfo,
347                         isReconciled = false,
348                         appId = 0
349                     )
350                 newState
351                     .mutateSystemState()
352                     .mutatePermissions()
353                     .putAt(permissionIndex, newPermission)
354                 changedPermissionNames += permissionName
355             }
356         }
357     }
358 
359     private fun MutateStateScope.canAdoptPermissions(
360         packageName: String,
361         originalPackageName: String
362     ): Boolean {
363         val originalPackageState =
364             newState.externalState.packageStates[originalPackageName] ?: return false
365         if (!originalPackageState.isSystem) {
366             Slog.w(
367                 LOG_TAG,
368                 "Unable to adopt permissions from $originalPackageName to $packageName:" +
369                     " original package not in system partition"
370             )
371             return false
372         }
373         if (originalPackageState.androidPackage != null) {
374             Slog.w(
375                 LOG_TAG,
376                 "Unable to adopt permissions from $originalPackageName to $packageName:" +
377                     " original package still exists"
378             )
379             return false
380         }
381         return true
382     }
383 
384     private fun MutateStateScope.addPermissionGroups(packageState: PackageState) {
385         // Different from the old implementation, which decides whether the app is an instant app by
386         // the install flags, now for consistent behavior we allow adding permission groups if the
387         // app is non-instant in at least one user.
388         val isInstantApp = packageState.userStates.allIndexed { _, _, it -> it.isInstantApp }
389         if (isInstantApp) {
390             Slog.w(
391                 LOG_TAG,
392                 "Ignoring permission groups declared in package" +
393                     " ${packageState.packageName}: instant apps cannot declare permission groups"
394             )
395             return
396         }
397         packageState.androidPackage!!.permissionGroups.forEachIndexed { _, parsedPermissionGroup ->
398             val newPermissionGroup =
399                 PackageInfoUtils.generatePermissionGroupInfo(
400                     parsedPermissionGroup,
401                     PackageManager.GET_META_DATA.toLong()
402                 )!!
403             // TODO: Clear permission state on group take-over?
404             val permissionGroupName = newPermissionGroup.name
405             val oldPermissionGroup = newState.systemState.permissionGroups[permissionGroupName]
406             if (
407                 oldPermissionGroup != null &&
408                     newPermissionGroup.packageName != oldPermissionGroup.packageName
409             ) {
410                 val newPackageName = newPermissionGroup.packageName
411                 val oldPackageName = oldPermissionGroup.packageName
412                 // Different from the old implementation, which defines permission group on
413                 // a first-come-first-serve basis, and relies on system apps being scanned before
414                 // non-system apps, we now allow system apps to override permission groups similar
415                 // to permissions so that we no longer need to rely on the scan order.
416                 if (!packageState.isSystem) {
417                     Slog.w(
418                         LOG_TAG,
419                         "Ignoring permission group $permissionGroupName declared in" +
420                             " package $newPackageName: already declared in another" +
421                             " package $oldPackageName"
422                     )
423                     return@forEachIndexed
424                 }
425                 if (newState.externalState.packageStates[oldPackageName]?.isSystem == true) {
426                     Slog.w(
427                         LOG_TAG,
428                         "Ignoring permission group $permissionGroupName declared in" +
429                             " system package $newPackageName: already declared in another" +
430                             " system package $oldPackageName"
431                     )
432                     return@forEachIndexed
433                 }
434                 Slog.w(
435                     LOG_TAG,
436                     "Overriding permission group $permissionGroupName with" +
437                         " new declaration in system package $newPackageName: originally" +
438                         " declared in another package $oldPackageName"
439                 )
440             }
441             newState.mutateSystemState().mutatePermissionGroups()[permissionGroupName] =
442                 newPermissionGroup
443         }
444     }
445 
446     private fun MutateStateScope.addPermissions(
447         packageState: PackageState,
448         changedPermissionNames: MutableIndexedSet<String>
449     ) {
450         val androidPackage = packageState.androidPackage!!
451         // This may not be the same package as the old permission because the old permission owner
452         // can be different, hence using this somewhat strange name to prevent misuse.
453         val oldNewPackage =
454             oldState.externalState.packageStates[packageState.packageName]?.androidPackage
455         val isPackageSigningChanged =
456             oldNewPackage != null && androidPackage.signingDetails != oldNewPackage.signingDetails
457         androidPackage.permissions.forEachIndexed { _, parsedPermission ->
458             val newPermissionInfo =
459                 PackageInfoUtils.generatePermissionInfo(
460                     parsedPermission,
461                     PackageManager.GET_META_DATA.toLong()
462                 )!!
463             val permissionName = newPermissionInfo.name
464             val oldPermission =
465                 if (parsedPermission.isTree) {
466                     newState.systemState.permissionTrees[permissionName]
467                 } else {
468                     newState.systemState.permissions[permissionName]
469                 }
470 
471             // Different from the old implementation, which may add an (incomplete) signature
472             // permission inside another package's permission tree, we now consistently ignore such
473             // permissions.
474             val permissionTree = findPermissionTree(permissionName)
475             val newPackageName = newPermissionInfo.packageName
476             if (permissionTree != null && newPackageName != permissionTree.packageName) {
477                 Slog.w(
478                     LOG_TAG,
479                     "Ignoring permission $permissionName declared in package" +
480                         " $newPackageName: base permission tree ${permissionTree.name} is" +
481                         " declared in another package ${permissionTree.packageName}"
482                 )
483                 return@forEachIndexed
484             }
485 
486             if (oldPermission != null) {
487                 if (newPackageName != oldPermission.packageName) {
488                     val oldPackageName = oldPermission.packageName
489                     // Only allow system apps to redefine non-system permissions.
490                     if (!packageState.isSystem) {
491                         Slog.w(
492                             LOG_TAG,
493                             "Ignoring permission $permissionName declared in package" +
494                                 " $newPackageName: already declared in another package" +
495                                 " $oldPackageName"
496                         )
497                         return@forEachIndexed
498                     }
499                     if (newState.externalState.packageStates[oldPackageName]?.isSystem == true) {
500                         Slog.w(
501                             LOG_TAG,
502                             "Ignoring permission $permissionName declared in system package" +
503                                 " $newPackageName: already declared in another system package" +
504                                 " $oldPackageName"
505                         )
506                         return@forEachIndexed
507                     }
508                     Slog.w(
509                         LOG_TAG,
510                         "Overriding permission $permissionName with new declaration in" +
511                             " system package $newPackageName: originally declared in another" +
512                             " package $oldPackageName"
513                     )
514                     // Remove permission state on owner change.
515                     newState.externalState.userIds.forEachIndexed { _, userId ->
516                         newState.externalState.appIdPackageNames.forEachIndexed { _, appId, _ ->
517                             setPermissionFlags(appId, userId, permissionName, 0)
518                         }
519                     }
520                 } else if (oldPermission.isReconciled) {
521                     val isPermissionGroupChanged =
522                         newPermissionInfo.isRuntime &&
523                             newPermissionInfo.group != null &&
524                             newPermissionInfo.group != oldPermission.groupName
525                     val isPermissionProtectionChanged =
526                         (newPermissionInfo.isRuntime && !oldPermission.isRuntime) ||
527                             (newPermissionInfo.isInternal && !oldPermission.isInternal)
528                     if (isPermissionGroupChanged || isPermissionProtectionChanged) {
529                         newState.externalState.userIds.forEachIndexed { _, userId ->
530                             newState.externalState.appIdPackageNames.forEachIndexed { _, appId, _ ->
531                                 if (isPermissionGroupChanged) {
532                                     // We might auto-grant permissions if any permission of
533                                     // the group is already granted. Hence if the group of
534                                     // a granted permission changes we need to revoke it to
535                                     // avoid having permissions of the new group auto-granted.
536                                     Slog.w(
537                                         LOG_TAG,
538                                         "Revoking runtime permission $permissionName for" +
539                                             " appId $appId and userId $userId as the permission" +
540                                             " group changed from ${oldPermission.groupName}" +
541                                             " to ${newPermissionInfo.group}"
542                                     )
543                                 }
544                                 if (isPermissionProtectionChanged) {
545                                     Slog.w(
546                                         LOG_TAG,
547                                         "Revoking permission $permissionName for" +
548                                             " appId $appId and userId $userId as the permission" +
549                                             " protection changed."
550                                     )
551                                 }
552                                 setPermissionFlags(appId, userId, permissionName, 0)
553                             }
554                         }
555                     }
556                 }
557             }
558 
559             var gids = EmptyArray.INT
560             var areGidsPerUser = false
561             if (!parsedPermission.isTree && packageState.isSystem) {
562                 newState.externalState.configPermissions[permissionName]?.let {
563                     // PermissionEntry.gids may return null when parsing legacy config trying
564                     // to work around an issue about upgrading from L platfrm. We can just
565                     // ignore such entries now.
566                     if (it.gids != null) {
567                         gids = it.gids
568                         areGidsPerUser = it.perUser
569                     }
570                 }
571             }
572             val newPermission =
573                 Permission(
574                     newPermissionInfo,
575                     true,
576                     Permission.TYPE_MANIFEST,
577                     packageState.appId,
578                     gids,
579                     areGidsPerUser
580                 )
581 
582             if (parsedPermission.isTree) {
583                 newState.mutateSystemState().mutatePermissionTrees()[permissionName] = newPermission
584             } else {
585                 newState.mutateSystemState().mutatePermissions()[permissionName] = newPermission
586                 val isPermissionChanged =
587                     oldPermission == null ||
588                         newPackageName != oldPermission.packageName ||
589                         newPermission.protectionLevel != oldPermission.protectionLevel ||
590                         (oldPermission.isReconciled &&
591                             ((newPermission.isSignature && isPackageSigningChanged) ||
592                                 (newPermission.isKnownSigner &&
593                                     newPermission.knownCerts != oldPermission.knownCerts) ||
594                                 (newPermission.isRuntime &&
595                                     newPermission.groupName != null &&
596                                     newPermission.groupName != oldPermission.groupName)))
597                 if (isPermissionChanged) {
598                     changedPermissionNames += permissionName
599                 }
600             }
601         }
602     }
603 
604     private fun MutateStateScope.trimPermissions(
605         packageName: String,
606         changedPermissionNames: MutableIndexedSet<String>
607     ) {
608         val packageState = newState.externalState.packageStates[packageName]
609         val androidPackage = packageState?.androidPackage
610         if (packageState != null && androidPackage == null) {
611             return
612         }
613         val disabledSystemPackage =
614             newState.externalState.disabledSystemPackageStates[packageName]?.androidPackage
615         // Unlike in the previous implementation, we now also retain permission trees defined by
616         // disabled system packages for consistency with permissions.
617         newState.systemState.permissionTrees.forEachReversedIndexed {
618             permissionTreeIndex,
619             permissionTreeName,
620             permissionTree ->
621             if (
622                 permissionTree.packageName == packageName &&
623                     (packageState == null ||
624                         androidPackage!!.permissions.noneIndexed { _, it ->
625                             it.isTree && it.name == permissionTreeName
626                         }) &&
627                     (disabledSystemPackage?.permissions?.anyIndexed { _, it ->
628                         it.isTree && it.name == permissionTreeName
629                     } != true)
630             ) {
631                 newState.mutateSystemState().mutatePermissionTrees().removeAt(permissionTreeIndex)
632             }
633         }
634 
635         newState.systemState.permissions.forEachReversedIndexed {
636             permissionIndex,
637             permissionName,
638             permission ->
639             val updatedPermission = updatePermissionIfDynamic(permission)
640             newState
641                 .mutateSystemState()
642                 .mutatePermissions()
643                 .putAt(permissionIndex, updatedPermission)
644             if (
645                 updatedPermission.packageName == packageName &&
646                     (packageState == null ||
647                         androidPackage!!.permissions.noneIndexed { _, it ->
648                             !it.isTree && it.name == permissionName
649                         }) &&
650                     (disabledSystemPackage?.permissions?.anyIndexed { _, it ->
651                         !it.isTree && it.name == permissionName
652                     } != true)
653             ) {
654                 // Different from the old implementation where we keep the permission state if the
655                 // permission is declared by a disabled system package (ag/15189282), we now
656                 // shouldn't be notified when the updated system package is removed but the disabled
657                 // system package isn't re-enabled yet, so we don't need to maintain that brittle
658                 // special case either.
659                 newState.externalState.userIds.forEachIndexed { _, userId ->
660                     newState.externalState.appIdPackageNames.forEachIndexed { _, appId, _ ->
661                         setPermissionFlags(appId, userId, permissionName, 0)
662                     }
663                 }
664                 newState.mutateSystemState().mutatePermissions().removeAt(permissionIndex)
665                 changedPermissionNames += permissionName
666             }
667         }
668     }
669 
670     private fun MutateStateScope.updatePermissionIfDynamic(permission: Permission): Permission {
671         if (!permission.isDynamic) {
672             return permission
673         }
674         val permissionTree = findPermissionTree(permission.name) ?: return permission
675         @Suppress("DEPRECATION")
676         return permission.copy(
677             permissionInfo =
678                 PermissionInfo(permission.permissionInfo).apply {
679                     packageName = permissionTree.packageName
680                 },
681             appId = permissionTree.appId,
682             isReconciled = true
683         )
684     }
685 
686     private fun MutateStateScope.trimPermissionStates(appId: Int) {
687         val requestedPermissions = MutableIndexedSet<String>()
688         forEachPackageInAppId(appId) {
689             // Note that we still trim the permission states requested by disabled system packages.
690             // Because in the previous implementation:
691             // despite revokeSharedUserPermissionsForLeavingPackageInternal() retains permissions
692             // requested by disabled system packages, revokeUnusedSharedUserPermissionsLocked(),
693             // which is call upon app update installation, didn't do such preservation.
694             // Hence, permissions only requested by disabled system packages were still trimmed in
695             // the previous implementation.
696             requestedPermissions += it.androidPackage!!.requestedPermissions
697         }
698         newState.userStates.forEachIndexed { _, userId, userState ->
699             userState.appIdPermissionFlags[appId]?.forEachReversedIndexed { _, permissionName, _ ->
700                 if (permissionName !in requestedPermissions) {
701                     setPermissionFlags(appId, userId, permissionName, 0)
702                 }
703             }
704         }
705     }
706 
707     private fun MutateStateScope.revokePermissionsOnPackageUpdate(appId: Int) {
708         val hasOldPackage =
709             appId in oldState.externalState.appIdPackageNames &&
710                 anyPackageInAppId(appId, oldState) { true }
711         if (!hasOldPackage) {
712             // Don't revoke anything if this isn't a package update, i.e. if information about the
713             // old package isn't available. Notably, this also means skipping packages changed via
714             // OTA, but the revocation here is also mostly for normal apps and there's no way to get
715             // information about the package before OTA anyway.
716             return
717         }
718 
719         // If the app is updated, and has scoped storage permissions, then it is possible that the
720         // app updated in an attempt to get unscoped storage. If so, revoke all storage permissions.
721         val oldTargetSdkVersion =
722             reducePackageInAppId(appId, Build.VERSION_CODES.CUR_DEVELOPMENT, oldState) {
723                 targetSdkVersion,
724                 packageState ->
725                 targetSdkVersion.coerceAtMost(packageState.androidPackage!!.targetSdkVersion)
726             }
727         val newTargetSdkVersion =
728             reducePackageInAppId(appId, Build.VERSION_CODES.CUR_DEVELOPMENT, newState) {
729                 targetSdkVersion,
730                 packageState ->
731                 targetSdkVersion.coerceAtMost(packageState.androidPackage!!.targetSdkVersion)
732             }
733         @Suppress("ConvertTwoComparisonsToRangeCheck")
734         val isTargetSdkVersionDowngraded =
735             oldTargetSdkVersion >= Build.VERSION_CODES.Q &&
736                 newTargetSdkVersion < Build.VERSION_CODES.Q
737         @Suppress("ConvertTwoComparisonsToRangeCheck")
738         val isTargetSdkVersionUpgraded =
739             oldTargetSdkVersion < Build.VERSION_CODES.Q &&
740                 newTargetSdkVersion >= Build.VERSION_CODES.Q
741         val oldIsRequestLegacyExternalStorage =
742             anyPackageInAppId(appId, oldState) {
743                 it.androidPackage!!.isRequestLegacyExternalStorage
744             }
745         val newIsRequestLegacyExternalStorage =
746             anyPackageInAppId(appId, newState) {
747                 it.androidPackage!!.isRequestLegacyExternalStorage
748             }
749         val isNewlyRequestingLegacyExternalStorage =
750             !isTargetSdkVersionUpgraded &&
751                 !oldIsRequestLegacyExternalStorage &&
752                 newIsRequestLegacyExternalStorage
753         val shouldRevokeStorageAndMediaPermissions =
754             isNewlyRequestingLegacyExternalStorage || isTargetSdkVersionDowngraded
755         if (shouldRevokeStorageAndMediaPermissions) {
756             newState.userStates.forEachIndexed { _, userId, userState ->
757                 userState.appIdPermissionFlags[appId]?.forEachReversedIndexed {
758                     _,
759                     permissionName,
760                     oldFlags ->
761                     // Do not revoke the permission during an upgrade if it's POLICY_FIXED or
762                     // SYSTEM_FIXED. Otherwise the user cannot grant back the permission.
763                     if (
764                         permissionName in STORAGE_AND_MEDIA_PERMISSIONS &&
765                             oldFlags.hasBits(PermissionFlags.RUNTIME_GRANTED) &&
766                             !oldFlags.hasAnyBit(SYSTEM_OR_POLICY_FIXED_MASK)
767                     ) {
768                         Slog.v(
769                             LOG_TAG,
770                             "Revoking storage permission: $permissionName for appId: " +
771                                 " $appId and user: $userId"
772                         )
773                         val newFlags =
774                             oldFlags andInv (PermissionFlags.RUNTIME_GRANTED or USER_SETTABLE_MASK)
775                         setPermissionFlags(appId, userId, permissionName, newFlags)
776                     }
777                 }
778             }
779         }
780     }
781 
782     private fun MutateStateScope.evaluatePermissionStateForAllPackages(
783         permissionName: String,
784         installedPackageState: PackageState?
785     ) {
786         val externalState = newState.externalState
787         externalState.userIds.forEachIndexed { _, userId ->
788             externalState.appIdPackageNames.forEachIndexed { _, appId, _ ->
789                 val isPermissionRequested =
790                     anyPackageInAppId(appId) {
791                         permissionName in it.androidPackage!!.requestedPermissions
792                     }
793                 if (isPermissionRequested) {
794                     evaluatePermissionState(appId, userId, permissionName, installedPackageState)
795                 }
796             }
797         }
798     }
799 
800     private fun MutateStateScope.evaluateAllPermissionStatesForPackage(
801         packageState: PackageState,
802         installedPackageState: PackageState?
803     ) {
804         newState.externalState.userIds.forEachIndexed { _, userId ->
805             evaluateAllPermissionStatesForPackageAndUser(
806                 packageState,
807                 userId,
808                 installedPackageState
809             )
810         }
811     }
812 
813     private fun MutateStateScope.evaluateAllPermissionStatesForPackageAndUser(
814         packageState: PackageState,
815         userId: Int,
816         installedPackageState: PackageState?
817     ) {
818         packageState.androidPackage?.requestedPermissions?.forEach { permissionName ->
819             evaluatePermissionState(
820                 packageState.appId,
821                 userId,
822                 permissionName,
823                 installedPackageState
824             )
825         }
826     }
827 
828     private fun MutateStateScope.evaluatePermissionState(
829         appId: Int,
830         userId: Int,
831         permissionName: String,
832         installedPackageState: PackageState?
833     ) {
834         val packageNames = newState.externalState.appIdPackageNames[appId]!!
835         // Repeatedly checking whether a permission is requested can actually be costly, so we cache
836         // the result for this method which is frequently called during boot, instead of calling
837         // anyPackageInAppId() and checking requested permissions multiple times.
838         val requestingPackageStates = MutableIndexedList<PackageState>()
839         var hasMissingPackage = false
840         packageNames.forEachIndexed { _, packageName ->
841             val packageState = newState.externalState.packageStates[packageName]!!
842             val androidPackage = packageState.androidPackage
843             if (androidPackage != null) {
844                 if (permissionName in androidPackage.requestedPermissions) {
845                     requestingPackageStates += packageState
846                 }
847             } else {
848                 hasMissingPackage = true
849             }
850         }
851         if (packageNames.size == 1 && hasMissingPackage) {
852             // For non-shared-user packages with missing androidPackage, skip evaluation.
853             return
854         }
855         val permission = newState.systemState.permissions[permissionName]
856         val oldFlags = getPermissionFlags(appId, userId, permissionName)
857         if (permission == null) {
858             if (oldFlags == 0) {
859                 // If the permission definition is missing and we don't have any permission states
860                 // for this permission, add the INSTALL_REVOKED flag to ensure that we don't
861                 // automatically grant the permission when it's defined
862                 setPermissionFlags(appId, userId, permissionName, PermissionFlags.INSTALL_REVOKED)
863             }
864             return
865         }
866         if (permission.isNormal) {
867             val wasGranted = oldFlags.hasBits(PermissionFlags.INSTALL_GRANTED)
868             if (!wasGranted) {
869                 val wasRevoked = oldFlags.hasBits(PermissionFlags.INSTALL_REVOKED)
870                 val isRequestedByInstalledPackage =
871                     installedPackageState != null &&
872                         permissionName in
873                             installedPackageState.androidPackage!!.requestedPermissions
874                 val isRequestedBySystemPackage =
875                     requestingPackageStates.anyIndexed { _, it -> it.isSystem }
876                 val isCompatibilityPermission =
877                     requestingPackageStates.anyIndexed { _, it ->
878                         isCompatibilityPermissionForPackage(it.androidPackage!!, permissionName)
879                     }
880                 // If this is an existing, non-system package,
881                 // then we can't add any new permissions to it.
882                 // Except if this is a permission that was added to the platform
883                 var newFlags =
884                     if (
885                         !wasRevoked ||
886                             isRequestedByInstalledPackage ||
887                             isRequestedBySystemPackage ||
888                             isCompatibilityPermission
889                     ) {
890                         PermissionFlags.INSTALL_GRANTED
891                     } else {
892                         PermissionFlags.INSTALL_REVOKED
893                     }
894                 if (permission.isAppOp) {
895                     newFlags =
896                         newFlags or
897                             (oldFlags and (PermissionFlags.ROLE or PermissionFlags.USER_SET))
898                 }
899                 setPermissionFlags(appId, userId, permissionName, newFlags)
900             }
901         } else if (permission.isSignature || permission.isInternal) {
902             val wasProtectionGranted = oldFlags.hasBits(PermissionFlags.PROTECTION_GRANTED)
903             var newFlags =
904                 if (hasMissingPackage && wasProtectionGranted) {
905                     // Keep the non-runtime permission grants for shared UID with missing
906                     // androidPackage
907                     PermissionFlags.PROTECTION_GRANTED
908                 } else {
909                     val mayGrantByPrivileged =
910                         !permission.isPrivileged ||
911                             requestingPackageStates.anyIndexed { _, it ->
912                                 checkPrivilegedPermissionAllowlist(it, permission)
913                             }
914                     val shouldGrantBySignature =
915                         permission.isSignature &&
916                             requestingPackageStates.anyIndexed { _, it ->
917                                 shouldGrantPermissionBySignature(it, permission)
918                             }
919                     val shouldGrantByProtectionFlags =
920                         requestingPackageStates.anyIndexed { _, it ->
921                             shouldGrantPermissionByProtectionFlags(it, permission)
922                         }
923                     if (
924                         mayGrantByPrivileged &&
925                             (shouldGrantBySignature || shouldGrantByProtectionFlags)
926                     ) {
927                         PermissionFlags.PROTECTION_GRANTED
928                     } else {
929                         0
930                     }
931                 }
932             if (permission.isAppOp) {
933                 newFlags =
934                     newFlags or (oldFlags and (PermissionFlags.ROLE or PermissionFlags.USER_SET))
935             }
936             // Different from the old implementation, which seemingly allows granting an
937             // unallowlisted privileged permission via development or role but revokes it upon next
938             // reconciliation, we now properly allows that because the privileged protection flag
939             // should only affect the other static flags, but not dynamic flags like development or
940             // role. This may be useful in the case of an updated system app.
941             if (permission.isDevelopment) {
942                 newFlags = newFlags or (oldFlags and PermissionFlags.RUNTIME_GRANTED)
943             }
944             if (permission.isRole) {
945                 newFlags =
946                     newFlags or
947                         (oldFlags and (PermissionFlags.ROLE or PermissionFlags.RUNTIME_GRANTED))
948             }
949             setPermissionFlags(appId, userId, permissionName, newFlags)
950         } else if (permission.isRuntime) {
951             var newFlags = oldFlags and PermissionFlags.MASK_RUNTIME
952             val wasRevoked = newFlags != 0 && !PermissionFlags.isPermissionGranted(newFlags)
953             val targetSdkVersion =
954                 requestingPackageStates.reduceIndexed(Build.VERSION_CODES.CUR_DEVELOPMENT) {
955                     targetSdkVersion,
956                     _,
957                     packageState ->
958                     targetSdkVersion.coerceAtMost(packageState.androidPackage!!.targetSdkVersion)
959                 }
960             if (targetSdkVersion < Build.VERSION_CODES.M) {
961                 if (permission.isRuntimeOnly) {
962                     // Different from the old implementation, which simply skips a runtime-only
963                     // permission, we now only allow holding on to the restriction related flags,
964                     // since such flags may only be set one-time in some cases, and disallow all
965                     // other flags thus keeping it revoked.
966                     newFlags = newFlags and PermissionFlags.MASK_EXEMPT
967                 } else {
968                     newFlags = newFlags or PermissionFlags.LEGACY_GRANTED
969                     if (wasRevoked) {
970                         newFlags = newFlags or PermissionFlags.APP_OP_REVOKED
971                     }
972                     // Explicitly check against the old state to determine if this permission is
973                     // new.
974                     val isNewPermission =
975                         getOldStatePermissionFlags(appId, userId, permissionName) == 0
976                     if (isNewPermission) {
977                         newFlags = newFlags or PermissionFlags.IMPLICIT
978                     }
979                 }
980             } else {
981                 val wasGrantedByLegacy = newFlags.hasBits(PermissionFlags.LEGACY_GRANTED)
982                 val hasImplicitFlag = newFlags.hasBits(PermissionFlags.IMPLICIT)
983                 if (wasGrantedByLegacy) {
984                     newFlags = newFlags andInv PermissionFlags.LEGACY_GRANTED
985                     if (!hasImplicitFlag) {
986                         newFlags = newFlags or PermissionFlags.RUNTIME_GRANTED
987                     }
988                 }
989                 val wasGrantedByImplicit = newFlags.hasBits(PermissionFlags.IMPLICIT_GRANTED)
990                 val isLeanbackNotificationsPermission =
991                     newState.externalState.isLeanback && permissionName in NOTIFICATIONS_PERMISSIONS
992                 val isImplicitPermission =
993                     requestingPackageStates.anyIndexed { _, it ->
994                         permissionName in it.androidPackage!!.implicitPermissions
995                     }
996                 val sourcePermissions =
997                     newState.externalState.implicitToSourcePermissions[permissionName]
998                 val isAnySourcePermissionNonRuntime =
999                     sourcePermissions?.anyIndexed { _, sourcePermissionName ->
1000                         val sourcePermission =
1001                             newState.systemState.permissions[sourcePermissionName]
1002                         checkNotNull(sourcePermission) {
1003                             "Unknown source permission $sourcePermissionName in split permissions"
1004                         }
1005                         !sourcePermission.isRuntime
1006                     }
1007                         ?: false
1008                 val shouldGrantByImplicit =
1009                     isLeanbackNotificationsPermission ||
1010                         (isImplicitPermission && isAnySourcePermissionNonRuntime)
1011                 if (shouldGrantByImplicit) {
1012                     newFlags = newFlags or PermissionFlags.IMPLICIT_GRANTED
1013                     if (wasRevoked) {
1014                         newFlags = newFlags or PermissionFlags.APP_OP_REVOKED
1015                     }
1016                 } else {
1017                     newFlags = newFlags andInv PermissionFlags.IMPLICIT_GRANTED
1018                     if (
1019                         (wasGrantedByLegacy || wasGrantedByImplicit) &&
1020                             newFlags.hasBits(PermissionFlags.APP_OP_REVOKED)
1021                     ) {
1022                         // The permission was granted from a compatibility grant or an implicit
1023                         // grant, however this flag might still be set if the user denied this
1024                         // permission in the settings. Hence upon app upgrade and when this
1025                         // permission is no longer LEGACY_GRANTED or IMPLICIT_GRANTED and we revoke
1026                         // the permission, we want to remove this flag so that the app can request
1027                         // the permission again.
1028                         newFlags =
1029                             newFlags andInv
1030                                 (PermissionFlags.RUNTIME_GRANTED or PermissionFlags.APP_OP_REVOKED)
1031                     }
1032                 }
1033                 if (!isImplicitPermission && hasImplicitFlag) {
1034                     newFlags = newFlags andInv PermissionFlags.IMPLICIT
1035                     var shouldRetainAsNearbyDevices = false
1036                     if (permissionName in NEARBY_DEVICES_PERMISSIONS) {
1037                         val accessBackgroundLocationFlags =
1038                             getPermissionFlags(
1039                                 appId,
1040                                 userId,
1041                                 Manifest.permission.ACCESS_BACKGROUND_LOCATION
1042                             )
1043                         shouldRetainAsNearbyDevices =
1044                             PermissionFlags.isAppOpGranted(accessBackgroundLocationFlags) &&
1045                                 !accessBackgroundLocationFlags.hasBits(PermissionFlags.IMPLICIT)
1046                     }
1047                     val shouldRetainByMask = newFlags.hasAnyBit(SYSTEM_OR_POLICY_FIXED_MASK)
1048                     if (shouldRetainAsNearbyDevices || shouldRetainByMask) {
1049                         if (wasGrantedByImplicit) {
1050                             newFlags = newFlags or PermissionFlags.RUNTIME_GRANTED
1051                         }
1052                     } else {
1053                         newFlags =
1054                             newFlags andInv
1055                                 (PermissionFlags.RUNTIME_GRANTED or
1056                                     PermissionFlags.USER_SET or
1057                                     PermissionFlags.USER_FIXED)
1058                     }
1059                 }
1060             }
1061 
1062             val wasExempt = newFlags.hasAnyBit(PermissionFlags.MASK_EXEMPT)
1063             val wasRestricted = newFlags.hasAnyBit(PermissionFlags.MASK_RESTRICTED)
1064             val isExempt =
1065                 if (permission.isHardOrSoftRestricted && !wasExempt && !wasRestricted) {
1066                     // All restricted permissions start as exempt. If there's an installer for the
1067                     // package, we will drop this UPGRADE_EXEMPT flag when we receive the
1068                     // onPackageInstalled() callback and set up the INSTALLER_EXEMPT flags.
1069                     // UPGRADE_EXEMPT is chosen instead of other flags because it is the same flag
1070                     // that
1071                     // was assigned to pre-installed apps in RuntimePermissionsUpgradeController,
1072                     // and to
1073                     // apps with missing permission state.
1074                     // This way we make sure both pre-installed apps, and apps updated/installed
1075                     // after
1076                     // a rollback snapshot is taken, can get the allowlist for permissions that
1077                     // won't be
1078                     // allowlisted otherwise.
1079                     newFlags = newFlags or PermissionFlags.UPGRADE_EXEMPT
1080                     true
1081                 } else {
1082                     wasExempt
1083                 }
1084             newFlags =
1085                 if (permission.isHardRestricted && !isExempt) {
1086                     newFlags or PermissionFlags.RESTRICTION_REVOKED
1087                 } else {
1088                     newFlags andInv PermissionFlags.RESTRICTION_REVOKED
1089                 }
1090             newFlags =
1091                 if (
1092                     permission.isSoftRestricted &&
1093                         !isExempt &&
1094                         !requestingPackageStates.anyIndexed { _, it ->
1095                             isSoftRestrictedPermissionExemptForPackage(
1096                                 it,
1097                                 targetSdkVersion,
1098                                 permissionName
1099                             )
1100                         }
1101                 ) {
1102                     newFlags or PermissionFlags.SOFT_RESTRICTED
1103                 } else {
1104                     newFlags andInv PermissionFlags.SOFT_RESTRICTED
1105                 }
1106             setPermissionFlags(appId, userId, permissionName, newFlags)
1107         } else {
1108             Slog.e(
1109                 LOG_TAG,
1110                 "Unknown protection level ${permission.protectionLevel}" +
1111                     "for permission ${permission.name} while evaluating permission state" +
1112                     "for appId $appId and userId $userId"
1113             )
1114         }
1115     }
1116 
1117     private fun MutateStateScope.inheritImplicitPermissionStates(appId: Int, userId: Int) {
1118         var targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT
1119         val implicitPermissions = MutableIndexedSet<String>()
1120         forEachPackageInAppId(appId) {
1121             targetSdkVersion = targetSdkVersion.coerceAtMost(it.androidPackage!!.targetSdkVersion)
1122             implicitPermissions += it.androidPackage!!.implicitPermissions
1123         }
1124         implicitPermissions.forEachIndexed implicitPermissions@{ _, implicitPermissionName ->
1125             val implicitPermission = newState.systemState.permissions[implicitPermissionName]
1126             checkNotNull(implicitPermission) {
1127                 "Unknown implicit permission $implicitPermissionName in split permissions"
1128             }
1129             if (!implicitPermission.isRuntime) {
1130                 return@implicitPermissions
1131             }
1132             // Explicitly check against the old state to determine if this permission is new.
1133             val isNewPermission =
1134                 getOldStatePermissionFlags(appId, userId, implicitPermissionName) == 0
1135             if (!isNewPermission) {
1136                 return@implicitPermissions
1137             }
1138             val sourcePermissions =
1139                 newState.externalState.implicitToSourcePermissions[implicitPermissionName]
1140                     ?: return@implicitPermissions
1141             var newFlags = getPermissionFlags(appId, userId, implicitPermissionName)
1142             sourcePermissions.forEachIndexed sourcePermissions@{ _, sourcePermissionName ->
1143                 val sourcePermission = newState.systemState.permissions[sourcePermissionName]
1144                 checkNotNull(sourcePermission) {
1145                     "Unknown source permission $sourcePermissionName in split permissions"
1146                 }
1147                 val sourceFlags = getPermissionFlags(appId, userId, sourcePermissionName)
1148                 val isSourceGranted = PermissionFlags.isPermissionGranted(sourceFlags)
1149                 val isNewGranted = PermissionFlags.isPermissionGranted(newFlags)
1150                 val isGrantingNewFromRevoke = isSourceGranted && !isNewGranted
1151                 if (isSourceGranted == isNewGranted || isGrantingNewFromRevoke) {
1152                     if (isGrantingNewFromRevoke) {
1153                         newFlags = 0
1154                     }
1155                     newFlags = newFlags or (sourceFlags and PermissionFlags.MASK_RUNTIME)
1156                 }
1157             }
1158             if (
1159                 targetSdkVersion >= Build.VERSION_CODES.M &&
1160                     implicitPermissionName in NO_IMPLICIT_FLAG_PERMISSIONS
1161             ) {
1162                 newFlags = newFlags andInv PermissionFlags.IMPLICIT
1163             } else {
1164                 newFlags = newFlags or PermissionFlags.IMPLICIT
1165             }
1166             setPermissionFlags(appId, userId, implicitPermissionName, newFlags)
1167         }
1168     }
1169 
1170     private fun isCompatibilityPermissionForPackage(
1171         androidPackage: AndroidPackage,
1172         permissionName: String
1173     ): Boolean {
1174         for (compatibilityPermission in CompatibilityPermissionInfo.COMPAT_PERMS) {
1175             if (
1176                 compatibilityPermission.name == permissionName &&
1177                     androidPackage.targetSdkVersion < compatibilityPermission.sdkVersion
1178             ) {
1179                 Slog.i(
1180                     LOG_TAG,
1181                     "Auto-granting $permissionName to old package" +
1182                         " ${androidPackage.packageName}"
1183                 )
1184                 return true
1185             }
1186         }
1187         return false
1188     }
1189 
1190     private fun MutateStateScope.shouldGrantPermissionBySignature(
1191         packageState: PackageState,
1192         permission: Permission
1193     ): Boolean {
1194         // Check if the package is allowed to use this signature permission.  A package is allowed
1195         // to use a signature permission if:
1196         // - it has the same set of signing certificates as the source package
1197         // - or its signing certificate was rotated from the source package's certificate
1198         // - or its signing certificate is a previous signing certificate of the defining
1199         //     package, and the defining package still trusts the old certificate for permissions
1200         // - or it shares a common signing certificate in its lineage with the defining package,
1201         //     and the defining package still trusts the old certificate for permissions
1202         // - or it shares the above relationships with the system package
1203         val packageSigningDetails = packageState.androidPackage!!.signingDetails
1204         val sourceSigningDetails =
1205             newState.externalState.packageStates[permission.packageName]
1206                 ?.androidPackage
1207                 ?.signingDetails
1208         val platformSigningDetails =
1209             newState.externalState.packageStates[PLATFORM_PACKAGE_NAME]!!
1210                 .androidPackage!!
1211                 .signingDetails
1212         val hasCommonSigner =
1213             sourceSigningDetails?.hasCommonSignerWithCapability(
1214                 packageSigningDetails,
1215                 SigningDetails.CertCapabilities.PERMISSION
1216             ) == true ||
1217                 packageSigningDetails.hasAncestorOrSelf(platformSigningDetails) ||
1218                 platformSigningDetails.checkCapability(
1219                     packageSigningDetails,
1220                     SigningDetails.CertCapabilities.PERMISSION
1221                 )
1222         if (!Flags.signaturePermissionAllowlistEnabled()) {
1223             return hasCommonSigner
1224         }
1225         if (!hasCommonSigner) {
1226             return false
1227         }
1228         // A platform signature permission also needs to be allowlisted on non-debuggable builds.
1229         if (permission.packageName == PLATFORM_PACKAGE_NAME) {
1230             val isRequestedByFactoryApp =
1231                 if (packageState.isSystem) {
1232                     // For updated system applications, a signature permission still needs to be
1233                     // allowlisted if it wasn't requested by the original application.
1234                     if (packageState.isUpdatedSystemApp) {
1235                         val disabledSystemPackage =
1236                             newState.externalState.disabledSystemPackageStates[
1237                                     packageState.packageName]
1238                                 ?.androidPackage
1239                         disabledSystemPackage != null &&
1240                             permission.name in disabledSystemPackage.requestedPermissions
1241                     } else {
1242                         true
1243                     }
1244                 } else {
1245                     false
1246                 }
1247             if (
1248                 !(isRequestedByFactoryApp ||
1249                     getSignaturePermissionAllowlistState(packageState, permission.name) == true)
1250             ) {
1251                 Slog.w(
1252                     LOG_TAG,
1253                     "Signature permission ${permission.name} for package" +
1254                         " ${packageState.packageName} (${packageState.path}) not in" +
1255                         " signature permission allowlist"
1256                 )
1257                 if (!Build.isDebuggable() || isSignaturePermissionAllowlistForceEnforced) {
1258                     return false
1259                 }
1260             }
1261         }
1262         return true
1263     }
1264 
1265     private fun MutateStateScope.getSignaturePermissionAllowlistState(
1266         packageState: PackageState,
1267         permissionName: String
1268     ): Boolean? {
1269         val permissionAllowlist = newState.externalState.permissionAllowlist
1270         val packageName = packageState.packageName
1271         return when {
1272             packageState.isVendor || packageState.isOdm ->
1273                 permissionAllowlist.getVendorSignatureAppAllowlistState(packageName, permissionName)
1274             packageState.isProduct ->
1275                 permissionAllowlist.getProductSignatureAppAllowlistState(
1276                     packageName,
1277                     permissionName
1278                 )
1279             packageState.isSystemExt ->
1280                 permissionAllowlist.getSystemExtSignatureAppAllowlistState(
1281                     packageName,
1282                     permissionName
1283                 )
1284             else ->
1285                 permissionAllowlist.getApexSignatureAppAllowlistState(packageName, permissionName)
1286                     ?: permissionAllowlist.getProductSignatureAppAllowlistState(
1287                         packageName,
1288                         permissionName
1289                     )
1290                     ?: permissionAllowlist.getVendorSignatureAppAllowlistState(
1291                         packageName,
1292                         permissionName
1293                     )
1294                     ?: permissionAllowlist.getSystemExtSignatureAppAllowlistState(
1295                         packageName,
1296                         permissionName
1297                     )
1298                     ?: permissionAllowlist.getSignatureAppAllowlistState(
1299                         packageName,
1300                         permissionName
1301                     )
1302         }
1303     }
1304 
1305     private fun MutateStateScope.checkPrivilegedPermissionAllowlist(
1306         packageState: PackageState,
1307         permission: Permission
1308     ): Boolean {
1309         if (RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS_DISABLE) {
1310             return true
1311         }
1312         if (packageState.packageName == PLATFORM_PACKAGE_NAME) {
1313             return true
1314         }
1315         if (!(packageState.isSystem && packageState.isPrivileged)) {
1316             return true
1317         }
1318         if (
1319             permission.packageName !in newState.externalState.privilegedPermissionAllowlistPackages
1320         ) {
1321             return true
1322         }
1323         val allowlistState = getPrivilegedPermissionAllowlistState(packageState, permission.name)
1324         if (allowlistState != null) {
1325             return allowlistState
1326         }
1327         // Updated system apps do not need to be allowlisted
1328         if (packageState.isUpdatedSystemApp) {
1329             return true
1330         }
1331         // Only enforce the privileged permission allowlist on boot
1332         if (!newState.externalState.isSystemReady) {
1333             // Apps that are in updated apex's do not need to be allowlisted
1334             if (!packageState.isApkInUpdatedApex) {
1335                 Slog.w(
1336                     LOG_TAG,
1337                     "Privileged permission ${permission.name} for package" +
1338                         " ${packageState.packageName} (${packageState.path}) not in" +
1339                         " privileged permission allowlist"
1340                 )
1341                 if (RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS_ENFORCE) {
1342                     privilegedPermissionAllowlistViolations +=
1343                         "${packageState.packageName}" +
1344                             " (${packageState.path}): ${permission.name}"
1345                 }
1346             }
1347         }
1348         return !RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS_ENFORCE
1349     }
1350 
1351     /**
1352      * Get the whether a privileged permission is explicitly allowed or denied for a package in the
1353      * allowlist, or `null` if it's not in the allowlist.
1354      */
1355     private fun MutateStateScope.getPrivilegedPermissionAllowlistState(
1356         packageState: PackageState,
1357         permissionName: String
1358     ): Boolean? {
1359         val permissionAllowlist = newState.externalState.permissionAllowlist
1360         val apexModuleName = packageState.apexModuleName
1361         val packageName = packageState.packageName
1362         return when {
1363             packageState.isVendor || packageState.isOdm ->
1364                 permissionAllowlist.getVendorPrivilegedAppAllowlistState(
1365                     packageName,
1366                     permissionName
1367                 )
1368             packageState.isProduct ->
1369                 permissionAllowlist.getProductPrivilegedAppAllowlistState(
1370                     packageName,
1371                     permissionName
1372                 )
1373             packageState.isSystemExt ->
1374                 permissionAllowlist.getSystemExtPrivilegedAppAllowlistState(
1375                     packageName,
1376                     permissionName
1377                 )
1378             apexModuleName != null -> {
1379                 val nonApexAllowlistState =
1380                     permissionAllowlist.getPrivilegedAppAllowlistState(packageName, permissionName)
1381                 if (nonApexAllowlistState != null) {
1382                     // TODO(andreionea): Remove check as soon as all apk-in-apex
1383                     // permission allowlists are migrated.
1384                     Slog.w(
1385                         LOG_TAG,
1386                         "Package $packageName is an APK in APEX but has permission" +
1387                             " allowlist on the system image, please bundle the allowlist in the" +
1388                             " $apexModuleName APEX instead"
1389                     )
1390                 }
1391                 val apexAllowlistState =
1392                     permissionAllowlist.getApexPrivilegedAppAllowlistState(
1393                         apexModuleName,
1394                         packageName,
1395                         permissionName
1396                     )
1397                 apexAllowlistState ?: nonApexAllowlistState
1398             }
1399             else -> permissionAllowlist.getPrivilegedAppAllowlistState(packageName, permissionName)
1400         }
1401     }
1402 
1403     // See also SoftRestrictedPermissionPolicy.mayGrantPermission()
1404     // Note: we need the appIdTargetSdkVersion parameter here because we are OR-ing the exempt
1405     // status for all packages in a shared UID, but the storage soft restriction logic needs to NOT
1406     // exempt when the target SDK version is low, which is the opposite of what most of our code do,
1407     // and thus can't check the individual package's target SDK version and rely on the OR among
1408     // them.
1409     private fun isSoftRestrictedPermissionExemptForPackage(
1410         packageState: PackageState,
1411         appIdTargetSdkVersion: Int,
1412         permissionName: String
1413     ): Boolean =
1414         when (permissionName) {
1415             Manifest.permission.READ_EXTERNAL_STORAGE,
1416             Manifest.permission.WRITE_EXTERNAL_STORAGE ->
1417                 appIdTargetSdkVersion >= Build.VERSION_CODES.Q
1418             else -> false
1419         }
1420 
1421     private inline fun MutateStateScope.anyPackageInAppId(
1422         appId: Int,
1423         state: AccessState = newState,
1424         predicate: (PackageState) -> Boolean
1425     ): Boolean {
1426         val packageNames = state.externalState.appIdPackageNames[appId]!!
1427         return packageNames.anyIndexed { _, packageName ->
1428             val packageState = state.externalState.packageStates[packageName]!!
1429             packageState.androidPackage != null && predicate(packageState)
1430         }
1431     }
1432 
1433     private inline fun MutateStateScope.forEachPackageInAppId(
1434         appId: Int,
1435         state: AccessState = newState,
1436         action: (PackageState) -> Unit
1437     ) {
1438         val packageNames = state.externalState.appIdPackageNames[appId]!!
1439         packageNames.forEachIndexed { _, packageName ->
1440             val packageState = state.externalState.packageStates[packageName]!!
1441             if (packageState.androidPackage != null) {
1442                 action(packageState)
1443             }
1444         }
1445     }
1446 
1447     // Using Int instead of <T> to avoid autoboxing, since we only have the use case for Int.
1448     private inline fun MutateStateScope.reducePackageInAppId(
1449         appId: Int,
1450         initialValue: Int,
1451         state: AccessState = newState,
1452         accumulator: (Int, PackageState) -> Int
1453     ): Int {
1454         val packageNames = state.externalState.appIdPackageNames[appId]!!
1455         return packageNames.reduceIndexed(initialValue) { value, _, packageName ->
1456             val packageState = state.externalState.packageStates[packageName]!!
1457             if (packageState.androidPackage != null) {
1458                 accumulator(value, packageState)
1459             } else {
1460                 value
1461             }
1462         }
1463     }
1464 
1465     private fun MutateStateScope.shouldGrantPermissionByProtectionFlags(
1466         packageState: PackageState,
1467         permission: Permission
1468     ): Boolean {
1469         val androidPackage = packageState.androidPackage!!
1470         val knownPackages = newState.externalState.knownPackages
1471         val packageName = packageState.packageName
1472         if ((permission.isPrivileged || permission.isOem) && packageState.isSystem) {
1473             val shouldGrant =
1474                 if (packageState.isUpdatedSystemApp) {
1475                     // For updated system applications, a privileged/oem permission
1476                     // is granted only if it had been defined by the original application.
1477                     val disabledSystemPackageState =
1478                         newState.externalState.disabledSystemPackageStates[packageState.packageName]
1479                     val disabledSystemPackage = disabledSystemPackageState?.androidPackage
1480                     disabledSystemPackage != null &&
1481                         permission.name in disabledSystemPackage.requestedPermissions &&
1482                         shouldGrantPrivilegedOrOemPermission(disabledSystemPackageState, permission)
1483                 } else {
1484                     shouldGrantPrivilegedOrOemPermission(packageState, permission)
1485                 }
1486             if (shouldGrant) {
1487                 return true
1488             }
1489         }
1490         if (permission.isPre23 && androidPackage.targetSdkVersion < Build.VERSION_CODES.M) {
1491             // If this was a previously normal/dangerous permission that got moved
1492             // to a system permission as part of the runtime permission redesign, then
1493             // we still want to blindly grant it to old apps.
1494             return true
1495         }
1496         if (
1497             permission.isInstaller &&
1498                 (packageName in knownPackages[KnownPackages.PACKAGE_INSTALLER]!! ||
1499                     packageName in knownPackages[KnownPackages.PACKAGE_PERMISSION_CONTROLLER]!!)
1500         ) {
1501             // If this permission is to be granted to the system installer and
1502             // this app is an installer or permission controller, then it gets the permission.
1503             return true
1504         }
1505         if (
1506             permission.isVerifier && packageName in knownPackages[KnownPackages.PACKAGE_VERIFIER]!!
1507         ) {
1508             // If this permission is to be granted to the system verifier and
1509             // this app is a verifier, then it gets the permission.
1510             return true
1511         }
1512         if (permission.isPreInstalled && packageState.isSystem) {
1513             // Any pre-installed system app is allowed to get this permission.
1514             return true
1515         }
1516         if (
1517             permission.isKnownSigner &&
1518                 androidPackage.signingDetails.hasAncestorOrSelfWithDigest(permission.knownCerts)
1519         ) {
1520             // If the permission is to be granted to a known signer then check if any of this
1521             // app's signing certificates are in the trusted certificate digest Set.
1522             return true
1523         }
1524         if (
1525             permission.isSetup && packageName in knownPackages[KnownPackages.PACKAGE_SETUP_WIZARD]!!
1526         ) {
1527             // If this permission is to be granted to the system setup wizard and
1528             // this app is a setup wizard, then it gets the permission.
1529             return true
1530         }
1531         if (
1532             permission.isSystemTextClassifier &&
1533                 packageName in knownPackages[KnownPackages.PACKAGE_SYSTEM_TEXT_CLASSIFIER]!!
1534         ) {
1535             // Special permissions for the system default text classifier.
1536             return true
1537         }
1538         if (
1539             permission.isConfigurator &&
1540                 packageName in knownPackages[KnownPackages.PACKAGE_CONFIGURATOR]!!
1541         ) {
1542             // Special permissions for the device configurator.
1543             return true
1544         }
1545         if (
1546             permission.isIncidentReportApprover &&
1547                 packageName in knownPackages[KnownPackages.PACKAGE_INCIDENT_REPORT_APPROVER]!!
1548         ) {
1549             // If this permission is to be granted to the incident report approver and
1550             // this app is the incident report approver, then it gets the permission.
1551             return true
1552         }
1553         if (
1554             permission.isAppPredictor &&
1555                 packageName in knownPackages[KnownPackages.PACKAGE_APP_PREDICTOR]!!
1556         ) {
1557             // Special permissions for the system app predictor.
1558             return true
1559         }
1560         if (
1561             permission.isCompanion &&
1562                 packageName in knownPackages[KnownPackages.PACKAGE_COMPANION]!!
1563         ) {
1564             // Special permissions for the system companion device manager.
1565             return true
1566         }
1567         if (permission.isRecents && packageName in knownPackages[KnownPackages.PACKAGE_RECENTS]!!) {
1568             // Special permission for the recents app.
1569             return true
1570         }
1571         if (permission.isModule && packageState.apexModuleName != null) {
1572             // Special permission granted for APKs inside APEX modules.
1573             return true
1574         }
1575         return false
1576     }
1577 
1578     private fun MutateStateScope.shouldGrantPrivilegedOrOemPermission(
1579         packageState: PackageState,
1580         permission: Permission
1581     ): Boolean {
1582         val permissionName = permission.name
1583         val packageName = packageState.packageName
1584         when {
1585             permission.isPrivileged -> {
1586                 if (packageState.isPrivileged) {
1587                     // In any case, don't grant a privileged permission to privileged vendor apps,
1588                     // if the permission's protectionLevel does not have the extra vendorPrivileged
1589                     // flag.
1590                     if (
1591                         (packageState.isVendor || packageState.isOdm) &&
1592                             !permission.isVendorPrivileged
1593                     ) {
1594                         Slog.w(
1595                             LOG_TAG,
1596                             "Permission $permissionName cannot be granted to privileged" +
1597                                 " vendor (or odm) app $packageName because it isn't a" +
1598                                 " vendorPrivileged permission"
1599                         )
1600                         return false
1601                     }
1602                     return true
1603                 }
1604             }
1605             permission.isOem -> {
1606                 if (packageState.isOem) {
1607                     val allowlistState =
1608                         newState.externalState.permissionAllowlist.getOemAppAllowlistState(
1609                             packageName,
1610                             permissionName
1611                         )
1612                     checkNotNull(allowlistState) {
1613                         "OEM permission $permissionName requested by package" +
1614                             " $packageName must be explicitly declared granted or not"
1615                     }
1616                     return allowlistState
1617                 }
1618             }
1619         }
1620         return false
1621     }
1622 
1623     override fun MutateStateScope.onSystemReady() {
1624         if (!privilegedPermissionAllowlistViolations.isEmpty()) {
1625             throw IllegalStateException(
1626                 "Signature|privileged permissions not in privileged" +
1627                     " permission allowlist: $privilegedPermissionAllowlistViolations"
1628             )
1629         }
1630     }
1631 
1632     override fun BinaryXmlPullParser.parseSystemState(state: MutableAccessState) {
1633         with(persistence) { this@parseSystemState.parseSystemState(state) }
1634     }
1635 
1636     override fun BinaryXmlSerializer.serializeSystemState(state: AccessState) {
1637         with(persistence) { this@serializeSystemState.serializeSystemState(state) }
1638     }
1639 
1640     override fun BinaryXmlPullParser.parseUserState(state: MutableAccessState, userId: Int) {
1641         with(persistence) { this@parseUserState.parseUserState(state, userId) }
1642     }
1643 
1644     override fun BinaryXmlSerializer.serializeUserState(state: AccessState, userId: Int) {
1645         with(persistence) { this@serializeUserState.serializeUserState(state, userId) }
1646     }
1647 
1648     fun GetStateScope.getPermissionTrees(): IndexedMap<String, Permission> =
1649         state.systemState.permissionTrees
1650 
1651     fun GetStateScope.findPermissionTree(permissionName: String): Permission? =
1652         state.systemState.permissionTrees.firstNotNullOfOrNullIndexed {
1653             _,
1654             permissionTreeName,
1655             permissionTree ->
1656             if (
1657                 permissionName.startsWith(permissionTreeName) &&
1658                     permissionName.length > permissionTreeName.length &&
1659                     permissionName[permissionTreeName.length] == '.'
1660             ) {
1661                 permissionTree
1662             } else {
1663                 null
1664             }
1665         }
1666 
1667     fun MutateStateScope.addPermissionTree(permission: Permission) {
1668         newState.mutateSystemState().mutatePermissionTrees()[permission.name] = permission
1669     }
1670 
1671     /** returns all permission group definitions available in the system */
1672     fun GetStateScope.getPermissionGroups(): IndexedMap<String, PermissionGroupInfo> =
1673         state.systemState.permissionGroups
1674 
1675     /** returns all permission definitions available in the system */
1676     fun GetStateScope.getPermissions(): IndexedMap<String, Permission> =
1677         state.systemState.permissions
1678 
1679     fun MutateStateScope.addPermission(
1680         permission: Permission,
1681         isSynchronousWrite: Boolean = false
1682     ) {
1683         val writeMode = if (isSynchronousWrite) WriteMode.SYNCHRONOUS else WriteMode.ASYNCHRONOUS
1684         newState.mutateSystemState(writeMode).mutatePermissions()[permission.name] = permission
1685     }
1686 
1687     fun MutateStateScope.removePermission(permission: Permission) {
1688         newState.mutateSystemState().mutatePermissions() -= permission.name
1689     }
1690 
1691     fun GetStateScope.getUidPermissionFlags(appId: Int, userId: Int): IndexedMap<String, Int>? =
1692         state.userStates[userId]?.appIdPermissionFlags?.get(appId)
1693 
1694     fun GetStateScope.getPermissionFlags(appId: Int, userId: Int, permissionName: String): Int =
1695         getPermissionFlags(state, appId, userId, permissionName)
1696 
1697     private fun MutateStateScope.getOldStatePermissionFlags(
1698         appId: Int,
1699         userId: Int,
1700         permissionName: String
1701     ): Int = getPermissionFlags(oldState, appId, userId, permissionName)
1702 
1703     private fun getPermissionFlags(
1704         state: AccessState,
1705         appId: Int,
1706         userId: Int,
1707         permissionName: String
1708     ): Int =
1709         state.userStates[userId]?.appIdPermissionFlags?.get(appId).getWithDefault(permissionName, 0)
1710 
1711     fun GetStateScope.getAllPermissionFlags(appId: Int, userId: Int): IndexedMap<String, Int>? =
1712         state.userStates[userId]?.appIdPermissionFlags?.get(appId)
1713 
1714     fun MutateStateScope.setPermissionFlags(
1715         appId: Int,
1716         userId: Int,
1717         permissionName: String,
1718         flags: Int
1719     ): Boolean =
1720         updatePermissionFlags(appId, userId, permissionName, PermissionFlags.MASK_ALL, flags)
1721 
1722     fun MutateStateScope.updatePermissionFlags(
1723         appId: Int,
1724         userId: Int,
1725         permissionName: String,
1726         flagMask: Int,
1727         flagValues: Int
1728     ): Boolean {
1729         if (userId !in newState.userStates) {
1730             // Despite that we check UserManagerInternal.exists() in PermissionService, we may still
1731             // sometimes get race conditions between that check and the actual mutateState() call.
1732             // This should rarely happen but at least we should not crash.
1733             Slog.e(LOG_TAG, "Unable to update permission flags for missing user $userId")
1734             return false
1735         }
1736         val oldFlags =
1737             newState.userStates[userId]!!
1738                 .appIdPermissionFlags[appId]
1739                 .getWithDefault(permissionName, 0)
1740         val newFlags = (oldFlags andInv flagMask) or (flagValues and flagMask)
1741         if (oldFlags == newFlags) {
1742             return false
1743         }
1744         val appIdPermissionFlags = newState.mutateUserState(userId)!!.mutateAppIdPermissionFlags()
1745         val permissionFlags = appIdPermissionFlags.mutateOrPut(appId) { MutableIndexedMap() }
1746         permissionFlags.putWithDefault(permissionName, newFlags, 0)
1747         if (permissionFlags.isEmpty()) {
1748             appIdPermissionFlags -= appId
1749         }
1750         onPermissionFlagsChangedListeners.forEachIndexed { _, it ->
1751             it.onPermissionFlagsChanged(appId, userId, permissionName, oldFlags, newFlags)
1752         }
1753         return true
1754     }
1755 
1756     fun addOnPermissionFlagsChangedListener(listener: OnPermissionFlagsChangedListener) {
1757         synchronized(onPermissionFlagsChangedListenersLock) {
1758             onPermissionFlagsChangedListeners = onPermissionFlagsChangedListeners + listener
1759         }
1760     }
1761 
1762     fun removeOnPermissionFlagsChangedListener(listener: OnPermissionFlagsChangedListener) {
1763         synchronized(onPermissionFlagsChangedListenersLock) {
1764             onPermissionFlagsChangedListeners = onPermissionFlagsChangedListeners - listener
1765         }
1766     }
1767 
1768     override fun migrateSystemState(state: MutableAccessState) {
1769         migration.migrateSystemState(state)
1770     }
1771 
1772     override fun migrateUserState(state: MutableAccessState, userId: Int) {
1773         migration.migrateUserState(state, userId)
1774     }
1775 
1776     override fun MutateStateScope.upgradePackageState(
1777         packageState: PackageState,
1778         userId: Int,
1779         version: Int
1780     ) {
1781         with(upgrade) { upgradePackageState(packageState, userId, version) }
1782     }
1783 
1784     companion object {
1785         private val LOG_TAG = AppIdPermissionPolicy::class.java.simpleName
1786 
1787         private const val PLATFORM_PACKAGE_NAME = "android"
1788 
1789         // A set of permissions that we don't want to revoke when they are no longer implicit.
1790         private val NO_IMPLICIT_FLAG_PERMISSIONS =
1791             indexedSetOf(
1792                 Manifest.permission.ACCESS_MEDIA_LOCATION,
1793                 Manifest.permission.ACTIVITY_RECOGNITION,
1794                 Manifest.permission.READ_MEDIA_AUDIO,
1795                 Manifest.permission.READ_MEDIA_IMAGES,
1796                 Manifest.permission.READ_MEDIA_VIDEO,
1797                 Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED,
1798             )
1799 
1800         private val NEARBY_DEVICES_PERMISSIONS =
1801             indexedSetOf(
1802                 Manifest.permission.BLUETOOTH_ADVERTISE,
1803                 Manifest.permission.BLUETOOTH_CONNECT,
1804                 Manifest.permission.BLUETOOTH_SCAN,
1805                 Manifest.permission.NEARBY_WIFI_DEVICES
1806             )
1807 
1808         private val NOTIFICATIONS_PERMISSIONS = indexedSetOf(Manifest.permission.POST_NOTIFICATIONS)
1809 
1810         private val STORAGE_AND_MEDIA_PERMISSIONS =
1811             indexedSetOf(
1812                 Manifest.permission.READ_EXTERNAL_STORAGE,
1813                 Manifest.permission.WRITE_EXTERNAL_STORAGE,
1814                 Manifest.permission.READ_MEDIA_AUDIO,
1815                 Manifest.permission.READ_MEDIA_VIDEO,
1816                 Manifest.permission.READ_MEDIA_IMAGES,
1817                 Manifest.permission.ACCESS_MEDIA_LOCATION,
1818                 Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED
1819             )
1820 
1821         /** Mask for all permission flags that can be set by the user */
1822         private const val USER_SETTABLE_MASK =
1823             PermissionFlags.USER_SET or
1824                 PermissionFlags.USER_FIXED or
1825                 PermissionFlags.APP_OP_REVOKED or
1826                 PermissionFlags.ONE_TIME or
1827                 PermissionFlags.HIBERNATION or
1828                 PermissionFlags.USER_SELECTED
1829 
1830         /**
1831          * Mask for all permission flags that imply we shouldn't automatically modify the permission
1832          * grant state.
1833          */
1834         private const val SYSTEM_OR_POLICY_FIXED_MASK =
1835             PermissionFlags.SYSTEM_FIXED or PermissionFlags.POLICY_FIXED
1836     }
1837 
1838     /** Listener for permission flags changes. */
1839     interface OnPermissionFlagsChangedListener {
1840         /**
1841          * Called when a permission flags change has been made to the upcoming new state.
1842          *
1843          * Implementations should keep this method fast to avoid stalling the locked state mutation,
1844          * and only call external code after [onStateMutated] when the new state has actually become
1845          * the current state visible to external code.
1846          */
1847         fun onPermissionFlagsChanged(
1848             appId: Int,
1849             userId: Int,
1850             permissionName: String,
1851             oldFlags: Int,
1852             newFlags: Int
1853         )
1854 
1855         /**
1856          * Called when the upcoming new state has become the current state.
1857          *
1858          * Implementations should keep this method fast to avoid stalling the locked state mutation.
1859          */
1860         fun onStateMutated()
1861     }
1862 }
1863