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