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