1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.permission.access.permission
18 
19 import android.Manifest
20 import android.content.pm.PackageManager
21 import android.content.pm.PermissionGroupInfo
22 import android.content.pm.PermissionInfo
23 import android.content.pm.SigningDetails
24 import android.os.Build
25 import android.os.UserHandle
26 import android.util.Log
27 import com.android.internal.os.RoSystemProperties
28 import com.android.modules.utils.BinaryXmlPullParser
29 import com.android.modules.utils.BinaryXmlSerializer
30 import com.android.server.permission.access.AccessState
31 import com.android.server.permission.access.AccessUri
32 import com.android.server.permission.access.GetStateScope
33 import com.android.server.permission.access.MutateStateScope
34 import com.android.server.permission.access.PermissionUri
35 import com.android.server.permission.access.SchemePolicy
36 import com.android.server.permission.access.UidUri
37 import com.android.server.permission.access.collection.* // ktlint-disable no-wildcard-imports
38 import com.android.server.permission.access.util.andInv
39 import com.android.server.permission.access.util.hasAnyBit
40 import com.android.server.permission.access.util.hasBits
41 import com.android.server.permission.access.util.isInternal
42 import com.android.server.pm.KnownPackages
43 import com.android.server.pm.parsing.PackageInfoUtils
44 import com.android.server.pm.permission.CompatibilityPermissionInfo
45 import com.android.server.pm.pkg.AndroidPackage
46 import com.android.server.pm.pkg.PackageState
47 
48 class UidPermissionPolicy : SchemePolicy() {
49     private val persistence = UidPermissionPersistence()
50 
51     @Volatile
52     private var onPermissionFlagsChangedListeners =
53         IndexedListSet<OnPermissionFlagsChangedListener>()
54     private val onPermissionFlagsChangedListenersLock = Any()
55 
56     private val privilegedPermissionAllowlistViolations = IndexedSet<String>()
57 
58     override val subjectScheme: String
59         get() = UidUri.SCHEME
60 
61     override val objectScheme: String
62         get() = PermissionUri.SCHEME
63 
64     override fun GetStateScope.getDecision(subject: AccessUri, `object`: AccessUri): Int {
65         subject as UidUri
66         `object` as PermissionUri
67         return getPermissionFlags(subject.appId, subject.userId, `object`.permissionName)
68     }
69 
70     override fun MutateStateScope.setDecision(
71         subject: AccessUri,
72         `object`: AccessUri,
73         decision: Int
74     ) {
75         subject as UidUri
76         `object` as PermissionUri
77         setPermissionFlags(subject.appId, subject.userId, `object`.permissionName, decision)
78     }
79 
80     override fun GetStateScope.onStateMutated() {
81         onPermissionFlagsChangedListeners.forEachIndexed { _, it -> it.onStateMutated() }
82     }
83 
84     override fun MutateStateScope.onInitialized() {
85         newState.systemState.configPermissions.forEach { (permissionName, permissionEntry) ->
86             val permissions = newState.systemState.permissions
87             val oldPermission = permissions[permissionName]
88             val newPermission = if (oldPermission != null) {
89                 if (permissionEntry.gids != null) {
90                     oldPermission.copy(
91                         gids = permissionEntry.gids, areGidsPerUser = permissionEntry.perUser
92                     )
93                 } else {
94                     return@forEach
95                 }
96             } else {
97                 @Suppress("DEPRECATION")
98                 val permissionInfo = PermissionInfo().apply {
99                     name = permissionName
100                     packageName = PLATFORM_PACKAGE_NAME
101                     protectionLevel = PermissionInfo.PROTECTION_SIGNATURE
102                 }
103                 if (permissionEntry.gids != null) {
104                     Permission(
105                         permissionInfo, false, Permission.TYPE_CONFIG, 0, permissionEntry.gids,
106                         permissionEntry.perUser
107                     )
108                 } else {
109                     Permission(permissionInfo, false, Permission.TYPE_CONFIG, 0)
110                 }
111             }
112             permissions[permissionName] = newPermission
113         }
114     }
115 
116     override fun MutateStateScope.onUserAdded(userId: Int) {
117         newState.systemState.packageStates.forEach { (_, packageState) ->
118             evaluateAllPermissionStatesForPackageAndUser(packageState, userId, null)
119         }
120         newState.systemState.appIds.forEachKeyIndexed { _, appId ->
121             inheritImplicitPermissionStates(appId, userId)
122         }
123     }
124 
125     override fun MutateStateScope.onAppIdRemoved(appId: Int) {
126         newState.userStates.forEachValueIndexed { _, userState ->
127             userState.uidPermissionFlags -= appId
128             userState.requestWrite()
129             // Skip notifying the change listeners since the app ID no longer exists.
130         }
131     }
132 
133     override fun MutateStateScope.onStorageVolumeMounted(
134         volumeUuid: String?,
135         isSystemUpdated: Boolean
136     ) {
137         val changedPermissionNames = IndexedSet<String>()
138         newState.systemState.packageStates.forEach { (_, packageState) ->
139             val androidPackage = packageState.androidPackage
140             if (androidPackage == null || androidPackage.volumeUuid != volumeUuid) {
141                 return@forEach
142             }
143             adoptPermissions(packageState, changedPermissionNames)
144             addPermissionGroups(packageState)
145             addPermissions(packageState, changedPermissionNames)
146             trimPermissions(packageState.packageName, changedPermissionNames)
147             trimPermissionStates(packageState.appId)
148             revokePermissionsOnPackageUpdate(packageState.appId)
149         }
150         changedPermissionNames.forEachIndexed { _, permissionName ->
151             evaluatePermissionStateForAllPackages(permissionName, null)
152         }
153 
154         newState.systemState.packageStates.forEach { (_, packageState) ->
155             val androidPackage = packageState.androidPackage
156             if (androidPackage == null || androidPackage.volumeUuid != volumeUuid) {
157                 return@forEach
158             }
159             val installedPackageState = if (isSystemUpdated) packageState else null
160             evaluateAllPermissionStatesForPackage(packageState, installedPackageState)
161         }
162         newState.systemState.packageStates.forEach { (_, packageState) ->
163             val androidPackage = packageState.androidPackage
164             if (androidPackage == null || androidPackage.volumeUuid != volumeUuid) {
165                 return@forEach
166             }
167             newState.systemState.userIds.forEachIndexed { _, userId ->
168                 inheritImplicitPermissionStates(packageState.appId, userId)
169             }
170         }
171     }
172 
173     override fun MutateStateScope.onPackageAdded(packageState: PackageState) {
174         val changedPermissionNames = IndexedSet<String>()
175         adoptPermissions(packageState, changedPermissionNames)
176         addPermissionGroups(packageState)
177         addPermissions(packageState, changedPermissionNames)
178         // TODO: revokeSystemAlertWindowIfUpgradedPast23()
179         trimPermissions(packageState.packageName, changedPermissionNames)
180         trimPermissionStates(packageState.appId)
181         revokePermissionsOnPackageUpdate(packageState.appId)
182         changedPermissionNames.forEachIndexed { _, permissionName ->
183             evaluatePermissionStateForAllPackages(permissionName, null)
184         }
185         evaluateAllPermissionStatesForPackage(packageState, packageState)
186         newState.systemState.userIds.forEachIndexed { _, userId ->
187             inheritImplicitPermissionStates(packageState.appId, userId)
188         }
189     }
190 
191     override fun MutateStateScope.onPackageRemoved(packageName: String, appId: Int) {
192         // TODO: STOPSHIP: Remove this check or at least turn into logging.
193         check(packageName !in newState.systemState.disabledSystemPackageStates) {
194             "Package $packageName reported as removed before disabled system package is enabled"
195         }
196 
197         val changedPermissionNames = IndexedSet<String>()
198         trimPermissions(packageName, changedPermissionNames)
199         if (appId in newState.systemState.appIds) {
200             trimPermissionStates(appId)
201         }
202         changedPermissionNames.forEachIndexed { _, permissionName ->
203             evaluatePermissionStateForAllPackages(permissionName, null)
204         }
205     }
206 
207     override fun MutateStateScope.onPackageUninstalled(
208         packageName: String,
209         appId: Int,
210         userId: Int
211     ) {
212         resetRuntimePermissions(packageName, appId, userId)
213     }
214 
215     fun MutateStateScope.resetRuntimePermissions(
216         packageName: String,
217         appId: Int,
218         userId: Int
219     ) {
220         val androidPackage = newState.systemState.packageStates[packageName]?.androidPackage
221             ?: return
222         androidPackage.requestedPermissions.forEachIndexed { _, permissionName ->
223             val permission = newState.systemState.permissions[permissionName]
224                 ?: return@forEachIndexed
225             if (permission.isRemoved) {
226                 return@forEachIndexed
227             }
228             val isRequestedByOtherPackages = anyRequestingPackageInAppId(appId, permissionName) {
229                 it.packageName != packageName
230             }
231             if (isRequestedByOtherPackages) {
232                 return@forEachIndexed
233             }
234             val oldFlags = getPermissionFlags(appId, userId, permissionName)
235             if (oldFlags.hasAnyBit(SYSTEM_OR_POLICY_FIXED_MASK)) {
236                 return@forEachIndexed
237             }
238             var newFlags = oldFlags
239             newFlags = if (
240                 newFlags.hasBits(PermissionFlags.ROLE) || newFlags.hasBits(PermissionFlags.PREGRANT)
241             ) {
242                 newFlags or PermissionFlags.RUNTIME_GRANTED
243             } else {
244                 newFlags andInv PermissionFlags.RUNTIME_GRANTED
245             }
246             newFlags = newFlags andInv USER_SETTABLE_MASK
247             if (newFlags.hasBits(PermissionFlags.LEGACY_GRANTED)) {
248                 newFlags = newFlags or PermissionFlags.IMPLICIT
249             }
250             setPermissionFlags(appId, userId, permissionName, newFlags)
251         }
252     }
253 
254     private fun MutateStateScope.adoptPermissions(
255         packageState: PackageState,
256         changedPermissionNames: IndexedSet<String>
257     ) {
258         val `package` = packageState.androidPackage!!
259         `package`.adoptPermissions.forEachIndexed { _, originalPackageName ->
260             val packageName = `package`.packageName
261             if (!canAdoptPermissions(packageName, originalPackageName)) {
262                 return@forEachIndexed
263             }
264             val systemState = newState.systemState
265             val permissions = systemState.permissions
266             permissions.forEachIndexed permissions@ {
267                 permissionIndex, permissionName, oldPermission ->
268                 if (oldPermission.packageName != originalPackageName) {
269                     return@permissions
270                 }
271                 @Suppress("DEPRECATION")
272                 val newPermissionInfo = PermissionInfo().apply {
273                     name = oldPermission.permissionInfo.name
274                     this.packageName = packageName
275                     protectionLevel = oldPermission.permissionInfo.protectionLevel
276                 }
277                 // Different from the old implementation, which removes the GIDs upon permission
278                 // adoption, but adds them back on the next boot, we now just consistently keep the
279                 // GIDs.
280                 val newPermission = oldPermission.copy(
281                     permissionInfo = newPermissionInfo, isReconciled = false, appId = 0
282                 )
283                 permissions.setValueAt(permissionIndex, newPermission)
284                 systemState.requestWrite()
285                 changedPermissionNames += permissionName
286             }
287         }
288     }
289 
290     private fun MutateStateScope.canAdoptPermissions(
291         packageName: String,
292         originalPackageName: String
293     ): Boolean {
294         val originalPackageState = newState.systemState.packageStates[originalPackageName]
295             ?: return false
296         if (!originalPackageState.isSystem) {
297             Log.w(
298                 LOG_TAG, "Unable to adopt permissions from $originalPackageName to $packageName:" +
299                     " original package not in system partition"
300             )
301             return false
302         }
303         if (originalPackageState.androidPackage != null) {
304             Log.w(
305                 LOG_TAG, "Unable to adopt permissions from $originalPackageName to $packageName:" +
306                     " original package still exists"
307             )
308             return false
309         }
310         return true
311     }
312 
313     private fun MutateStateScope.addPermissionGroups(packageState: PackageState) {
314         // Different from the old implementation, which decides whether the app is an instant app by
315         // the install flags, now for consistent behavior we allow adding permission groups if the
316         // app is non-instant in at least one user.
317         val isInstantApp = packageState.userStates.allIndexed { _, _, it -> it.isInstantApp }
318         if (isInstantApp) {
319             Log.w(
320                 LOG_TAG, "Ignoring permission groups declared in package" +
321                     " ${packageState.packageName}: instant apps cannot declare permission groups"
322             )
323             return
324         }
325         packageState.androidPackage!!.permissionGroups.forEachIndexed { _, parsedPermissionGroup ->
326             val newPermissionGroup = PackageInfoUtils.generatePermissionGroupInfo(
327                 parsedPermissionGroup, PackageManager.GET_META_DATA.toLong()
328             )!!
329             // TODO: Clear permission state on group take-over?
330             val permissionGroupName = newPermissionGroup.name
331             val oldPermissionGroup = newState.systemState.permissionGroups[permissionGroupName]
332             if (oldPermissionGroup != null &&
333                 newPermissionGroup.packageName != oldPermissionGroup.packageName) {
334                 val newPackageName = newPermissionGroup.packageName
335                 val oldPackageName = oldPermissionGroup.packageName
336                 // Different from the old implementation, which defines permission group on
337                 // a first-come-first-serve basis, and relies on system apps being scanned before
338                 // non-system apps, we now allow system apps to override permission groups similar
339                 // to permissions so that we no longer need to rely on the scan order.
340                 if (!packageState.isSystem) {
341                     Log.w(
342                         LOG_TAG, "Ignoring permission group $permissionGroupName declared in" +
343                             " package $newPackageName: already declared in another" +
344                             " package $oldPackageName"
345                     )
346                     return@forEachIndexed
347                 }
348                 if (newState.systemState.packageStates[oldPackageName]?.isSystem == true) {
349                     Log.w(
350                         LOG_TAG, "Ignoring permission group $permissionGroupName declared in" +
351                             " system package $newPackageName: already declared in another" +
352                             " system package $oldPackageName"
353                     )
354                     return@forEachIndexed
355                 }
356                 Log.w(
357                     LOG_TAG, "Overriding permission group $permissionGroupName with" +
358                         " new declaration in system package $newPackageName: originally" +
359                         " declared in another package $oldPackageName"
360                 )
361             }
362             newState.systemState.permissionGroups[permissionGroupName] = newPermissionGroup
363         }
364     }
365 
366     private fun MutateStateScope.addPermissions(
367         packageState: PackageState,
368         changedPermissionNames: IndexedSet<String>
369     ) {
370         packageState.androidPackage!!.permissions.forEachIndexed { _, parsedPermission ->
371             // TODO:
372             // parsedPermission.flags = parsedPermission.flags andInv PermissionInfo.FLAG_INSTALLED
373             // TODO: This seems actually unused.
374             // if (packageState.androidPackage.targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1) {
375             //    parsedPermission.setParsedPermissionGroup(
376             //        newState.systemState.permissionGroup[parsedPermission.group]
377             //    )
378             // }
379             val newPermissionInfo = PackageInfoUtils.generatePermissionInfo(
380                 parsedPermission, PackageManager.GET_META_DATA.toLong()
381             )!!
382             // TODO: newPermissionInfo.flags |= PermissionInfo.FLAG_INSTALLED
383             val systemState = newState.systemState
384             val permissionName = newPermissionInfo.name
385             val oldPermission = if (parsedPermission.isTree) {
386                 systemState.permissionTrees[permissionName]
387             } else {
388                 systemState.permissions[permissionName]
389             }
390             // Different from the old implementation, which may add an (incomplete) signature
391             // permission inside another package's permission tree, we now consistently ignore such
392             // permissions.
393             val permissionTree = findPermissionTree(permissionName)
394             val newPackageName = newPermissionInfo.packageName
395             if (permissionTree != null && newPackageName != permissionTree.packageName) {
396                 Log.w(
397                     LOG_TAG, "Ignoring permission $permissionName declared in package" +
398                         " $newPackageName: base permission tree ${permissionTree.name} is" +
399                         " declared in another package ${permissionTree.packageName}"
400                 )
401                 return@forEachIndexed
402             }
403             val newPermission = if (oldPermission != null &&
404                 newPackageName != oldPermission.packageName) {
405                 val oldPackageName = oldPermission.packageName
406                 // Only allow system apps to redefine non-system permissions.
407                 if (!packageState.isSystem) {
408                     Log.w(
409                         LOG_TAG, "Ignoring permission $permissionName declared in package" +
410                             " $newPackageName: already declared in another package" +
411                             " $oldPackageName"
412                     )
413                     return@forEachIndexed
414                 }
415                 if (oldPermission.type == Permission.TYPE_CONFIG && !oldPermission.isReconciled) {
416                     // It's a config permission and has no owner, take ownership now.
417                     oldPermission.copy(
418                         permissionInfo = newPermissionInfo, isReconciled = true,
419                         appId = packageState.appId
420                     )
421                 } else if (systemState.packageStates[oldPackageName]?.isSystem != true) {
422                     Log.w(
423                         LOG_TAG, "Overriding permission $permissionName with new declaration in" +
424                             " system package $newPackageName: originally declared in another" +
425                             " package $oldPackageName"
426                     )
427                     // Remove permission state on owner change.
428                     systemState.userIds.forEachIndexed { _, userId ->
429                         systemState.appIds.forEachKeyIndexed { _, appId ->
430                             setPermissionFlags(appId, userId, permissionName, 0)
431                         }
432                     }
433                     // Different from the old implementation, which removes the GIDs upon permission
434                     // override, but adds them back on the next boot, we now just consistently keep
435                     // the GIDs.
436                     Permission(
437                         newPermissionInfo, true, Permission.TYPE_MANIFEST, packageState.appId,
438                         oldPermission.gids, oldPermission.areGidsPerUser
439                     )
440                 } else {
441                     Log.w(
442                         LOG_TAG, "Ignoring permission $permissionName declared in system package" +
443                             " $newPackageName: already declared in another system package" +
444                             " $oldPackageName"
445                     )
446                     return@forEachIndexed
447                 }
448             } else {
449                 if (oldPermission != null) {
450                     val isPermissionGroupChanged = newPermissionInfo.isRuntime &&
451                         newPermissionInfo.group != null &&
452                         newPermissionInfo.group != oldPermission.groupName
453                     val isPermissionTypeChanged = oldPermission.type != Permission.TYPE_CONFIG && (
454                         (newPermissionInfo.isRuntime && !oldPermission.isRuntime) ||
455                             (newPermissionInfo.isInternal && !oldPermission.isInternal)
456                     )
457                     if (isPermissionGroupChanged || isPermissionTypeChanged) {
458                         systemState.userIds.forEachIndexed { _, userId ->
459                             systemState.appIds.forEachKeyIndexed { _, appId ->
460                                 if (isPermissionGroupChanged) {
461                                     // We might auto-grant permissions if any permission of
462                                     // the group is already granted. Hence if the group of
463                                     // a granted permission changes we need to revoke it to
464                                     // avoid having permissions of the new group auto-granted.
465                                     Log.w(
466                                         LOG_TAG, "Revoking runtime permission $permissionName for" +
467                                             " appId $appId and userId $userId as the permission" +
468                                             " group changed from ${oldPermission.groupName}" +
469                                             " to ${newPermissionInfo.group}"
470                                     )
471                                 }
472                                 if (isPermissionTypeChanged) {
473                                     Log.w(
474                                         LOG_TAG, "Revoking permission $permissionName for" +
475                                             " appId $appId and userId $userId as the permission" +
476                                             " type changed."
477                                     )
478                                 }
479                                 setPermissionFlags(appId, userId, permissionName, 0)
480                             }
481                         }
482                     }
483                 }
484 
485                 // Different from the old implementation, which doesn't update the permission
486                 // definition upon app update, but does update it on the next boot, we now
487                 // consistently update the permission definition upon app update.
488                 @Suppress("IfThenToElvis")
489                 if (oldPermission != null) {
490                     oldPermission.copy(
491                         permissionInfo = newPermissionInfo, isReconciled = true,
492                         appId = packageState.appId
493                     )
494                 } else {
495                     Permission(
496                         newPermissionInfo, true, Permission.TYPE_MANIFEST, packageState.appId
497                     )
498                 }
499             }
500 
501             if (parsedPermission.isTree) {
502                 systemState.permissionTrees[permissionName] = newPermission
503             } else {
504                 systemState.permissions[permissionName] = newPermission
505             }
506             systemState.requestWrite()
507             changedPermissionNames += permissionName
508         }
509     }
510 
511     private fun MutateStateScope.trimPermissions(
512         packageName: String,
513         changedPermissionNames: IndexedSet<String>
514     ) {
515         val systemState = newState.systemState
516         val packageState = systemState.packageStates[packageName]
517         val androidPackage = packageState?.androidPackage
518         if (packageState != null && androidPackage == null) {
519             return
520         }
521         val disabledSystemPackage = systemState.disabledSystemPackageStates[packageName]
522             ?.androidPackage
523         // Unlike in the previous implementation, we now also retain permission trees defined by
524         // disabled system packages for consistency with permissions.
525         val isPermissionTreeRemoved = systemState.permissionTrees.removeAllIndexed {
526             _, permissionTreeName, permissionTree ->
527             permissionTree.packageName == packageName && (
528                 packageState == null || androidPackage!!.permissions.noneIndexed { _, it ->
529                     it.isTree && it.name == permissionTreeName
530                 }
531             ) && (
532                 disabledSystemPackage?.permissions?.anyIndexed { _, it ->
533                     it.isTree && it.name == permissionTreeName
534                 } != true
535             )
536         }
537         if (isPermissionTreeRemoved) {
538             systemState.requestWrite()
539         }
540 
541         systemState.permissions.removeAllIndexed { permissionIndex, permissionName, permission ->
542             val updatedPermission = updatePermissionIfDynamic(permission)
543             newState.systemState.permissions.setValueAt(permissionIndex, updatedPermission)
544             if (updatedPermission.packageName == packageName && (
545                 packageState == null || androidPackage!!.permissions.noneIndexed { _, it ->
546                     !it.isTree && it.name == permissionName
547                 }
548             ) && (
549                 disabledSystemPackage?.permissions?.anyIndexed { _, it ->
550                     !it.isTree && it.name == permissionName
551                 } != true
552             )) {
553                 // Different from the old implementation where we keep the permission state if the
554                 // permission is declared by a disabled system package (ag/15189282), we now
555                 // shouldn't be notified when the updated system package is removed but the disabled
556                 // system package isn't re-enabled yet, so we don't need to maintain that brittle
557                 // special case either.
558                 systemState.userIds.forEachIndexed { _, userId ->
559                     systemState.appIds.forEachKeyIndexed { _, appId ->
560                         setPermissionFlags(appId, userId, permissionName, 0)
561                     }
562                 }
563                 changedPermissionNames += permissionName
564                 systemState.requestWrite()
565                 true
566             } else {
567                 false
568             }
569         }
570     }
571 
572     private fun MutateStateScope.updatePermissionIfDynamic(permission: Permission): Permission {
573         if (!permission.isDynamic) {
574             return permission
575         }
576         val permissionTree = findPermissionTree(permission.name) ?: return permission
577         @Suppress("DEPRECATION")
578         return permission.copy(
579             permissionInfo = PermissionInfo(permission.permissionInfo).apply {
580                 packageName = permissionTree.packageName
581             }, appId = permissionTree.appId, isReconciled = true
582         )
583     }
584 
585     private fun MutateStateScope.trimPermissionStates(appId: Int) {
586         val requestedPermissions = IndexedSet<String>()
587         forEachPackageInAppId(appId) {
588             // Note that we still trim the permission states requested by disabled system packages.
589             // Because in the previous implementation:
590             // despite revokeSharedUserPermissionsForLeavingPackageInternal() retains permissions
591             // requested by disabled system packages, revokeUnusedSharedUserPermissionsLocked(),
592             // which is call upon app update installation, didn't do such preservation.
593             // Hence, permissions only requested by disabled system packages were still trimmed in
594             // the previous implementation.
595             requestedPermissions += it.androidPackage!!.requestedPermissions
596         }
597         newState.userStates.forEachIndexed { _, userId, userState ->
598             userState.uidPermissionFlags[appId]?.forEachReversedIndexed { _, permissionName, _ ->
599                 if (permissionName !in requestedPermissions) {
600                     setPermissionFlags(appId, userId, permissionName, 0)
601                 }
602             }
603         }
604     }
605 
606     private fun MutateStateScope.revokePermissionsOnPackageUpdate(appId: Int) {
607         // If the app is updated, and has scoped storage permissions, then it is possible that the
608         // app updated in an attempt to get unscoped storage. If so, revoke all storage permissions.
609         newState.userStates.forEachIndexed { _, userId, userState ->
610             userState.uidPermissionFlags[appId]?.forEachReversedIndexed {
611                 _, permissionName, oldFlags ->
612                 if (permissionName !in STORAGE_AND_MEDIA_PERMISSIONS || oldFlags == 0) {
613                     return@forEachReversedIndexed
614                 }
615                 val oldTargetSdkVersion = getAppIdTargetSdkVersion(appId, permissionName, oldState)
616                 val newTargetSdkVersion = getAppIdTargetSdkVersion(appId, permissionName, newState)
617                 val isTargetSdkVersionDowngraded = oldTargetSdkVersion >= Build.VERSION_CODES.Q &&
618                     newTargetSdkVersion < Build.VERSION_CODES.Q
619                 val isTargetSdkVersionUpgraded = oldTargetSdkVersion < Build.VERSION_CODES.Q &&
620                     newTargetSdkVersion >= Build.VERSION_CODES.Q
621                 val oldIsRequestLegacyExternalStorage = anyRequestingPackageInAppId(
622                     appId, permissionName, oldState
623                 ) { it.androidPackage!!.isRequestLegacyExternalStorage }
624                 val newIsRequestLegacyExternalStorage = anyRequestingPackageInAppId(
625                     appId, permissionName, newState
626                 ) { it.androidPackage!!.isRequestLegacyExternalStorage }
627                 val isNewlyRequestingLegacyExternalStorage = !isTargetSdkVersionUpgraded &&
628                     !oldIsRequestLegacyExternalStorage && newIsRequestLegacyExternalStorage
629                 if ((isNewlyRequestingLegacyExternalStorage || isTargetSdkVersionDowngraded) &&
630                     oldFlags.hasBits(PermissionFlags.RUNTIME_GRANTED)) {
631                     val newFlags = oldFlags andInv (
632                         PermissionFlags.RUNTIME_GRANTED or USER_SETTABLE_MASK
633                     )
634                     setPermissionFlags(appId, userId, permissionName, newFlags)
635                 }
636             }
637         }
638     }
639 
640     private fun MutateStateScope.evaluatePermissionStateForAllPackages(
641         permissionName: String,
642         installedPackageState: PackageState?
643     ) {
644         val systemState = newState.systemState
645         systemState.userIds.forEachIndexed { _, userId ->
646             systemState.appIds.forEachKeyIndexed { _, appId ->
647                 val isPermissionRequested =
648                     anyRequestingPackageInAppId(appId, permissionName) { true }
649                 if (isPermissionRequested) {
650                     evaluatePermissionState(appId, userId, permissionName, installedPackageState)
651                 }
652             }
653         }
654     }
655 
656     private fun MutateStateScope.evaluateAllPermissionStatesForPackage(
657         packageState: PackageState,
658         installedPackageState: PackageState?
659     ) {
660         newState.systemState.userIds.forEachIndexed { _, userId ->
661             evaluateAllPermissionStatesForPackageAndUser(
662                 packageState, userId, installedPackageState
663             )
664         }
665     }
666 
667     private fun MutateStateScope.evaluateAllPermissionStatesForPackageAndUser(
668         packageState: PackageState,
669         userId: Int,
670         installedPackageState: PackageState?
671     ) {
672         packageState.androidPackage?.requestedPermissions?.forEachIndexed { _, permissionName ->
673             evaluatePermissionState(
674                 packageState.appId, userId, permissionName, installedPackageState
675             )
676         }
677     }
678 
679     private fun MutateStateScope.evaluatePermissionState(
680         appId: Int,
681         userId: Int,
682         permissionName: String,
683         installedPackageState: PackageState?
684     ) {
685         val packageNames = newState.systemState.appIds[appId]
686         val hasMissingPackage = packageNames.anyIndexed { _, packageName ->
687             newState.systemState.packageStates[packageName]!!.androidPackage == null
688         }
689         if (packageNames.size == 1 && hasMissingPackage) {
690             // For non-shared-user packages with missing androidPackage, skip evaluation.
691             return
692         }
693         val permission = newState.systemState.permissions[permissionName]
694         val oldFlags = getPermissionFlags(appId, userId, permissionName)
695         if (permission == null) {
696             if (oldFlags == 0) {
697                 // If the permission definition is missing and we don't have any permission states
698                 // for this permission, add the INSTALL_REVOKED flag to ensure that we don't
699                 // automatically grant the permission when it's defined
700                 setPermissionFlags(appId, userId, permissionName, PermissionFlags.INSTALL_REVOKED)
701             }
702             return
703         }
704         if (permission.isNormal) {
705             val wasGranted = oldFlags.hasBits(PermissionFlags.INSTALL_GRANTED)
706             if (!wasGranted) {
707                 val wasRevoked = oldFlags.hasBits(PermissionFlags.INSTALL_REVOKED)
708                 val isRequestedByInstalledPackage = installedPackageState != null &&
709                     permissionName in installedPackageState.androidPackage!!.requestedPermissions
710                 val isRequestedBySystemPackage =
711                     anyRequestingPackageInAppId(appId, permissionName) { it.isSystem }
712                 val isCompatibilityPermission = anyRequestingPackageInAppId(appId, permissionName) {
713                     isCompatibilityPermissionForPackage(it.androidPackage!!, permissionName)
714                 }
715                 // If this is an existing, non-system package,
716                 // then we can't add any new permissions to it.
717                 // Except if this is a permission that was added to the platform
718                 val newFlags = if (!wasRevoked || isRequestedByInstalledPackage ||
719                     isRequestedBySystemPackage || isCompatibilityPermission) {
720                     PermissionFlags.INSTALL_GRANTED
721                 } else {
722                     PermissionFlags.INSTALL_REVOKED
723                 }
724                 setPermissionFlags(appId, userId, permissionName, newFlags)
725             }
726         } else if (permission.isSignature || permission.isInternal) {
727             val wasProtectionGranted = oldFlags.hasBits(PermissionFlags.PROTECTION_GRANTED)
728             var newFlags = if (hasMissingPackage && wasProtectionGranted) {
729                 // Keep the non-runtime permission grants for shared UID with missing androidPackage
730                 PermissionFlags.PROTECTION_GRANTED
731             } else {
732                 val mayGrantByPrivileged = !permission.isPrivileged || (
733                     anyRequestingPackageInAppId(appId, permissionName) {
734                         checkPrivilegedPermissionAllowlist(it, permission)
735                     }
736                 )
737                 val shouldGrantBySignature = permission.isSignature && (
738                     anyRequestingPackageInAppId(appId, permissionName) {
739                         shouldGrantPermissionBySignature(it, permission)
740                     }
741                 )
742                 val shouldGrantByProtectionFlags =
743                     anyRequestingPackageInAppId(appId, permissionName) {
744                         shouldGrantPermissionByProtectionFlags(it, permission)
745                     }
746                 if (mayGrantByPrivileged &&
747                     (shouldGrantBySignature || shouldGrantByProtectionFlags)) {
748                     PermissionFlags.PROTECTION_GRANTED
749                 } else {
750                     0
751                 }
752             }
753             // Different from the old implementation, which seemingly allows granting an
754             // unallowlisted privileged permission via development or role but revokes it upon next
755             // reconciliation, we now properly allows that because the privileged protection flag
756             // should only affect the other static flags, but not dynamic flags like development or
757             // role. This may be useful in the case of an updated system app.
758             if (permission.isDevelopment) {
759                 newFlags = newFlags or (oldFlags and PermissionFlags.RUNTIME_GRANTED)
760             }
761             if (permission.isRole) {
762                 newFlags = newFlags or (
763                     oldFlags and (PermissionFlags.ROLE or PermissionFlags.RUNTIME_GRANTED)
764                 )
765             }
766             setPermissionFlags(appId, userId, permissionName, newFlags)
767         } else if (permission.isRuntime) {
768             var newFlags = oldFlags and PermissionFlags.MASK_RUNTIME
769             if (getAppIdTargetSdkVersion(appId, permissionName) < Build.VERSION_CODES.M) {
770                 if (permission.isRuntimeOnly) {
771                     // Different from the old implementation, which simply skips a runtime-only
772                     // permission, we now only allow holding on to the restriction related flags,
773                     // since such flags may only be set one-time in some cases, and disallow all
774                     // other flags thus keeping it revoked.
775                     newFlags = newFlags and PermissionFlags.MASK_EXEMPT
776                 } else {
777                     newFlags = newFlags or PermissionFlags.LEGACY_GRANTED
778                     // Explicitly check against the old state to determine if this permission is
779                     // new.
780                     val isNewPermission =
781                         getOldStatePermissionFlags(appId, userId, permissionName) == 0
782                     if (isNewPermission) {
783                         newFlags = newFlags or PermissionFlags.IMPLICIT
784                     }
785                 }
786             } else {
787                 val wasGrantedByLegacy = newFlags.hasBits(PermissionFlags.LEGACY_GRANTED)
788                 newFlags = newFlags andInv PermissionFlags.LEGACY_GRANTED
789                 val wasGrantedByImplicit = newFlags.hasBits(PermissionFlags.IMPLICIT_GRANTED)
790                 val isLeanbackNotificationsPermission = newState.systemState.isLeanback &&
791                     permissionName in NOTIFICATIONS_PERMISSIONS
792                 val isImplicitPermission = anyRequestingPackageInAppId(appId, permissionName) {
793                     permissionName in it.androidPackage!!.implicitPermissions
794                 }
795                 val sourcePermissions = newState.systemState
796                     .implicitToSourcePermissions[permissionName]
797                 val isAnySourcePermissionNonRuntime = sourcePermissions?.any {
798                     val sourcePermission = newState.systemState.permissions[it]
799                     checkNotNull(sourcePermission) {
800                         "Unknown source permission $it in split permissions"
801                     }
802                     !sourcePermission.isRuntime
803                 } ?: false
804                 val shouldGrantByImplicit = isLeanbackNotificationsPermission ||
805                     (isImplicitPermission && isAnySourcePermissionNonRuntime)
806                 if (shouldGrantByImplicit) {
807                     newFlags = newFlags or PermissionFlags.IMPLICIT_GRANTED
808                 } else {
809                     newFlags = newFlags andInv PermissionFlags.IMPLICIT_GRANTED
810                 }
811                 if ((wasGrantedByLegacy || wasGrantedByImplicit) && !shouldGrantByImplicit) {
812                     // The permission was granted from a compatibility grant or an implicit grant,
813                     // however this flag might still be set if the user denied this permission in
814                     // the settings. Hence upon app upgrade and when this permission is no longer
815                     // LEGACY_GRANTED or IMPLICIT_GRANTED and we revoke the permission, we want to
816                     // remove this flag so that the app can request the permission again.
817                     newFlags = newFlags andInv PermissionFlags.APP_OP_REVOKED
818                 }
819                 val hasImplicitFlag = newFlags.hasBits(PermissionFlags.IMPLICIT)
820                 if (!isImplicitPermission && hasImplicitFlag) {
821                     newFlags = newFlags andInv PermissionFlags.IMPLICIT
822                     var shouldRetainAsNearbyDevices = false
823                     if (permissionName in NEARBY_DEVICES_PERMISSIONS) {
824                         val accessBackgroundLocationFlags = getPermissionFlags(
825                             appId, userId, Manifest.permission.ACCESS_BACKGROUND_LOCATION
826                         )
827                         shouldRetainAsNearbyDevices =
828                             PermissionFlags.isAppOpGranted(accessBackgroundLocationFlags) &&
829                                 !accessBackgroundLocationFlags.hasBits(PermissionFlags.IMPLICIT)
830                     }
831                     val shouldRetainByMask = newFlags.hasAnyBit(SYSTEM_OR_POLICY_FIXED_MASK)
832                     if (shouldRetainAsNearbyDevices || shouldRetainByMask) {
833                         if (wasGrantedByImplicit) {
834                             newFlags = newFlags or PermissionFlags.RUNTIME_GRANTED
835                         }
836                     } else {
837                         newFlags = newFlags andInv (
838                             PermissionFlags.RUNTIME_GRANTED or PermissionFlags.USER_SET or
839                                 PermissionFlags.USER_FIXED
840                         )
841                     }
842                 }
843             }
844 
845             val isExempt = newFlags.hasAnyBit(PermissionFlags.MASK_EXEMPT)
846             val isHardRestricted = permission.isHardRestricted && !isExempt
847             newFlags = if (isHardRestricted) {
848                 newFlags or PermissionFlags.RESTRICTION_REVOKED
849             } else {
850                 newFlags andInv PermissionFlags.RESTRICTION_REVOKED
851             }
852             val isSoftRestricted = permission.isSoftRestricted && !isExempt
853             newFlags = if (isSoftRestricted) {
854                 newFlags or PermissionFlags.SOFT_RESTRICTED
855             } else {
856                 newFlags andInv PermissionFlags.SOFT_RESTRICTED
857             }
858             setPermissionFlags(appId, userId, permissionName, newFlags)
859         } else {
860             Log.e(LOG_TAG, "Unknown protection level ${permission.protectionLevel}" +
861                 "for permission ${permission.name} while evaluating permission state" +
862                 "for appId $appId and userId $userId")
863         }
864     }
865 
866     private fun MutateStateScope.inheritImplicitPermissionStates(appId: Int, userId: Int) {
867         val implicitPermissions = IndexedSet<String>()
868         forEachPackageInAppId(appId) {
869             implicitPermissions += it.androidPackage!!.implicitPermissions
870         }
871         implicitPermissions.forEachIndexed implicitPermissions@ { _, implicitPermissionName ->
872             val implicitPermission = newState.systemState.permissions[implicitPermissionName]
873             checkNotNull(implicitPermission) {
874                 "Unknown implicit permission $implicitPermissionName in split permissions"
875             }
876             if (!implicitPermission.isRuntime) {
877                 return@implicitPermissions
878             }
879             // Explicitly check against the old state to determine if this permission is new.
880             val isNewPermission =
881                 getOldStatePermissionFlags(appId, userId, implicitPermissionName) == 0
882             if (!isNewPermission) {
883                 return@implicitPermissions
884             }
885             val sourcePermissions = newState.systemState
886                 .implicitToSourcePermissions[implicitPermissionName] ?: return@implicitPermissions
887             var newFlags = getPermissionFlags(appId, userId, implicitPermissionName)
888             sourcePermissions.forEachIndexed sourcePermissions@ { _, sourcePermissionName ->
889                 val sourcePermission = newState.systemState.permissions[sourcePermissionName]
890                 checkNotNull(sourcePermission) {
891                     "Unknown source permission $sourcePermissionName in split permissions"
892                 }
893                 val sourceFlags = getPermissionFlags(appId, userId, sourcePermissionName)
894                 val isSourceGranted = PermissionFlags.isPermissionGranted(sourceFlags)
895                 val isNewGranted = PermissionFlags.isPermissionGranted(newFlags)
896                 val isGrantingNewFromRevoke = isSourceGranted && !isNewGranted
897                 if (isSourceGranted == isNewGranted || isGrantingNewFromRevoke) {
898                     if (isGrantingNewFromRevoke) {
899                         newFlags = 0
900                     }
901                     newFlags = newFlags or (sourceFlags and PermissionFlags.MASK_RUNTIME)
902                 }
903             }
904             if (implicitPermissionName in RETAIN_IMPLICIT_FLAGS_PERMISSIONS) {
905                 newFlags = newFlags andInv PermissionFlags.IMPLICIT
906             } else {
907                 newFlags = newFlags or PermissionFlags.IMPLICIT
908             }
909             setPermissionFlags(appId, userId, implicitPermissionName, newFlags)
910         }
911     }
912 
913     private fun isCompatibilityPermissionForPackage(
914         androidPackage: AndroidPackage,
915         permissionName: String
916     ): Boolean {
917         for (compatibilityPermission in CompatibilityPermissionInfo.COMPAT_PERMS) {
918             if (compatibilityPermission.name == permissionName &&
919                 androidPackage.targetSdkVersion < compatibilityPermission.sdkVersion) {
920                 Log.i(
921                     LOG_TAG, "Auto-granting $permissionName to old package" +
922                     " ${androidPackage.packageName}"
923                 )
924                 return true
925             }
926         }
927         return false
928     }
929 
930     private fun MutateStateScope.shouldGrantPermissionBySignature(
931         packageState: PackageState,
932         permission: Permission
933     ): Boolean {
934         // Check if the package is allowed to use this signature permission.  A package is allowed
935         // to use a signature permission if:
936         // - it has the same set of signing certificates as the source package
937         // - or its signing certificate was rotated from the source package's certificate
938         // - or its signing certificate is a previous signing certificate of the defining
939         //     package, and the defining package still trusts the old certificate for permissions
940         // - or it shares a common signing certificate in its lineage with the defining package,
941         //     and the defining package still trusts the old certificate for permissions
942         // - or it shares the above relationships with the system package
943         val packageSigningDetails = packageState.androidPackage!!.signingDetails
944         val sourceSigningDetails = newState.systemState
945             .packageStates[permission.packageName]?.androidPackage?.signingDetails
946         val platformSigningDetails = newState.systemState
947             .packageStates[PLATFORM_PACKAGE_NAME]!!.androidPackage!!.signingDetails
948         return sourceSigningDetails?.hasCommonSignerWithCapability(packageSigningDetails,
949             SigningDetails.CertCapabilities.PERMISSION) == true ||
950             packageSigningDetails.hasAncestorOrSelf(platformSigningDetails) ||
951             platformSigningDetails.checkCapability(packageSigningDetails,
952                     SigningDetails.CertCapabilities.PERMISSION)
953     }
954 
955     private fun MutateStateScope.checkPrivilegedPermissionAllowlist(
956         packageState: PackageState,
957         permission: Permission
958     ): Boolean {
959         if (RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS_DISABLE) {
960             return true
961         }
962         if (packageState.packageName == PLATFORM_PACKAGE_NAME) {
963             return true
964         }
965         if (!(packageState.isSystem && packageState.isPrivileged)) {
966             return true
967         }
968         if (permission.packageName !in newState.systemState.privilegedPermissionAllowlistPackages) {
969             return true
970         }
971         val allowlistState = getPrivilegedPermissionAllowlistState(packageState, permission.name)
972         if (allowlistState != null) {
973             return allowlistState
974         }
975         // Updated system apps do not need to be allowlisted
976         if (packageState.isUpdatedSystemApp) {
977             return true
978         }
979         // Only enforce the privileged permission allowlist on boot
980         if (!newState.systemState.isSystemReady) {
981             // Apps that are in updated apex's do not need to be allowlisted
982             if (!packageState.isApkInUpdatedApex) {
983                 Log.w(
984                     LOG_TAG, "Privileged permission ${permission.name} for package" +
985                     " ${packageState.packageName} (${packageState.path}) not in" +
986                     " privileged permission allowlist"
987                 )
988                 if (RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS_ENFORCE) {
989                     privilegedPermissionAllowlistViolations += "${packageState.packageName}" +
990                         " (${packageState.path}): ${permission.name}"
991                 }
992             }
993         }
994         return !RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS_ENFORCE
995     }
996 
997     /**
998      * Get the whether a privileged permission is explicitly allowed or denied for a package in the
999      * allowlist, or `null` if it's not in the allowlist.
1000      */
1001     private fun MutateStateScope.getPrivilegedPermissionAllowlistState(
1002         packageState: PackageState,
1003         permissionName: String
1004     ): Boolean? {
1005         val permissionAllowlist = newState.systemState.permissionAllowlist
1006         val apexModuleName = packageState.apexModuleName
1007         val packageName = packageState.packageName
1008         return when {
1009             packageState.isVendor -> permissionAllowlist.getVendorPrivilegedAppAllowlistState(
1010                 packageName, permissionName
1011             )
1012             packageState.isProduct -> permissionAllowlist.getProductPrivilegedAppAllowlistState(
1013                 packageName, permissionName
1014             )
1015             packageState.isSystemExt ->
1016                 permissionAllowlist.getSystemExtPrivilegedAppAllowlistState(
1017                     packageName, permissionName
1018                 )
1019             apexModuleName != null -> {
1020                 val nonApexAllowlistState = permissionAllowlist.getPrivilegedAppAllowlistState(
1021                     packageName, permissionName
1022                 )
1023                 if (nonApexAllowlistState != null) {
1024                     // TODO(andreionea): Remove check as soon as all apk-in-apex
1025                     // permission allowlists are migrated.
1026                     Log.w(
1027                         LOG_TAG, "Package $packageName is an APK in APEX but has permission" +
1028                             " allowlist on the system image, please bundle the allowlist in the" +
1029                             " $apexModuleName APEX instead"
1030                     )
1031                 }
1032                 val apexAllowlistState = permissionAllowlist.getApexPrivilegedAppAllowlistState(
1033                     apexModuleName, packageName, permissionName
1034                 )
1035                 apexAllowlistState ?: nonApexAllowlistState
1036             }
1037             else -> permissionAllowlist.getPrivilegedAppAllowlistState(packageName, permissionName)
1038         }
1039     }
1040 
1041     private fun MutateStateScope.getAppIdTargetSdkVersion(
1042         appId: Int,
1043         permissionName: String,
1044         state: AccessState = newState
1045     ): Int {
1046         var targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT
1047         forEachRequestingPackageInAppId(appId, permissionName, state) {
1048             targetSdkVersion = targetSdkVersion.coerceAtMost(it.androidPackage!!.targetSdkVersion)
1049         }
1050         return targetSdkVersion
1051     }
1052 
1053     private inline fun MutateStateScope.anyRequestingPackageInAppId(
1054         appId: Int,
1055         permissionName: String,
1056         state: AccessState = newState,
1057         predicate: (PackageState) -> Boolean
1058     ): Boolean {
1059         val packageNames = state.systemState.appIds[appId]
1060         return packageNames.anyIndexed { _, packageName ->
1061             val packageState = state.systemState.packageStates[packageName]!!
1062             val androidPackage = packageState.androidPackage
1063             androidPackage != null && permissionName in androidPackage.requestedPermissions &&
1064                 predicate(packageState)
1065         }
1066     }
1067 
1068     private inline fun MutateStateScope.forEachPackageInAppId(
1069         appId: Int,
1070         state: AccessState = newState,
1071         action: (PackageState) -> Unit
1072     ) {
1073         val packageNames = state.systemState.appIds[appId]!!
1074         packageNames.forEachIndexed { _, packageName ->
1075             val packageState = state.systemState.packageStates[packageName]!!
1076             if (packageState.androidPackage != null) {
1077                 action(packageState)
1078             }
1079         }
1080     }
1081 
1082     private inline fun MutateStateScope.forEachRequestingPackageInAppId(
1083         appId: Int,
1084         permissionName: String,
1085         state: AccessState = newState,
1086         action: (PackageState) -> Unit
1087     ) {
1088         val packageNames = state.systemState.appIds[appId]
1089         packageNames.forEachIndexed { _, packageName ->
1090             val packageState = state.systemState.packageStates[packageName]!!
1091             val androidPackage = packageState.androidPackage
1092             if (androidPackage != null && permissionName in androidPackage.requestedPermissions) {
1093                 action(packageState)
1094             }
1095         }
1096     }
1097 
1098     private fun MutateStateScope.shouldGrantPermissionByProtectionFlags(
1099         packageState: PackageState,
1100         permission: Permission
1101     ): Boolean {
1102         val androidPackage = packageState.androidPackage!!
1103         val knownPackages = newState.systemState.knownPackages
1104         val packageName = packageState.packageName
1105         if ((permission.isPrivileged || permission.isOem) && packageState.isSystem) {
1106             val shouldGrant = if (packageState.isUpdatedSystemApp) {
1107                 // For updated system applications, a privileged/oem permission
1108                 // is granted only if it had been defined by the original application.
1109                 val disabledSystemPackageState = newState.systemState
1110                     .disabledSystemPackageStates[packageState.packageName]
1111                 val disabledSystemPackage = disabledSystemPackageState?.androidPackage
1112                 disabledSystemPackage != null &&
1113                     permission.name in disabledSystemPackage.requestedPermissions &&
1114                     shouldGrantPrivilegedOrOemPermission(disabledSystemPackageState, permission)
1115             } else {
1116                 shouldGrantPrivilegedOrOemPermission(packageState, permission)
1117             }
1118             if (shouldGrant) {
1119                 return true
1120             }
1121         }
1122         if (permission.isPre23 && androidPackage.targetSdkVersion < Build.VERSION_CODES.M) {
1123             // If this was a previously normal/dangerous permission that got moved
1124             // to a system permission as part of the runtime permission redesign, then
1125             // we still want to blindly grant it to old apps.
1126             return true
1127         }
1128         if (permission.isInstaller && (
1129             packageName in knownPackages[KnownPackages.PACKAGE_INSTALLER] ||
1130                 packageName in knownPackages[KnownPackages.PACKAGE_PERMISSION_CONTROLLER]
1131         )) {
1132             // If this permission is to be granted to the system installer and
1133             // this app is an installer or permission controller, then it gets the permission.
1134             return true
1135         }
1136         if (permission.isVerifier &&
1137             packageName in knownPackages[KnownPackages.PACKAGE_VERIFIER]) {
1138             // If this permission is to be granted to the system verifier and
1139             // this app is a verifier, then it gets the permission.
1140             return true
1141         }
1142         if (permission.isPreInstalled && packageState.isSystem) {
1143             // Any pre-installed system app is allowed to get this permission.
1144             return true
1145         }
1146         if (permission.isKnownSigner &&
1147             androidPackage.signingDetails.hasAncestorOrSelfWithDigest(permission.knownCerts)) {
1148             // If the permission is to be granted to a known signer then check if any of this
1149             // app's signing certificates are in the trusted certificate digest Set.
1150             return true
1151         }
1152         if (permission.isSetup &&
1153             packageName in knownPackages[KnownPackages.PACKAGE_SETUP_WIZARD]) {
1154             // If this permission is to be granted to the system setup wizard and
1155             // this app is a setup wizard, then it gets the permission.
1156             return true
1157         }
1158         if (permission.isSystemTextClassifier &&
1159             packageName in knownPackages[KnownPackages.PACKAGE_SYSTEM_TEXT_CLASSIFIER]) {
1160             // Special permissions for the system default text classifier.
1161             return true
1162         }
1163         if (permission.isConfigurator &&
1164             packageName in knownPackages[KnownPackages.PACKAGE_CONFIGURATOR]) {
1165             // Special permissions for the device configurator.
1166             return true
1167         }
1168         if (permission.isIncidentReportApprover &&
1169             packageName in knownPackages[KnownPackages.PACKAGE_INCIDENT_REPORT_APPROVER]) {
1170             // If this permission is to be granted to the incident report approver and
1171             // this app is the incident report approver, then it gets the permission.
1172             return true
1173         }
1174         if (permission.isAppPredictor &&
1175             packageName in knownPackages[KnownPackages.PACKAGE_APP_PREDICTOR]) {
1176             // Special permissions for the system app predictor.
1177             return true
1178         }
1179         if (permission.isCompanion &&
1180             packageName in knownPackages[KnownPackages.PACKAGE_COMPANION]) {
1181             // Special permissions for the system companion device manager.
1182             return true
1183         }
1184         if (permission.isRetailDemo &&
1185             packageName in knownPackages[KnownPackages.PACKAGE_RETAIL_DEMO] &&
1186             isDeviceOrProfileOwnerUid(packageState.appId)) {
1187             // Special permission granted only to the OEM specified retail demo app.
1188             // Note that the original code was passing app ID as UID, so this behavior is kept
1189             // unchanged.
1190             return true
1191         }
1192         if (permission.isRecents &&
1193             packageName in knownPackages[KnownPackages.PACKAGE_RECENTS]) {
1194             // Special permission for the recents app.
1195             return true
1196         }
1197         if (permission.isModule && packageState.apexModuleName != null) {
1198             // Special permission granted for APKs inside APEX modules.
1199             return true
1200         }
1201         return false
1202     }
1203 
1204     private fun MutateStateScope.shouldGrantPrivilegedOrOemPermission(
1205         packageState: PackageState,
1206         permission: Permission
1207     ): Boolean {
1208         val permissionName = permission.name
1209         val packageName = packageState.packageName
1210         when {
1211             permission.isPrivileged -> {
1212                 if (packageState.isPrivileged) {
1213                     // In any case, don't grant a privileged permission to privileged vendor apps,
1214                     // if the permission's protectionLevel does not have the extra vendorPrivileged
1215                     // flag.
1216                     if (packageState.isVendor && !permission.isVendorPrivileged) {
1217                         Log.w(
1218                             LOG_TAG, "Permission $permissionName cannot be granted to privileged" +
1219                             " vendor app $packageName because it isn't a vendorPrivileged" +
1220                             " permission"
1221                         )
1222                         return false
1223                     }
1224                     return true
1225                 }
1226             }
1227             permission.isOem -> {
1228                 if (packageState.isOem) {
1229                     val allowlistState = newState.systemState.permissionAllowlist
1230                         .getOemAppAllowlistState(packageName, permissionName)
1231                     checkNotNull(allowlistState) {
1232                         "OEM permission $permissionName requested by package" +
1233                             " $packageName must be explicitly declared granted or not"
1234                     }
1235                     return allowlistState
1236                 }
1237             }
1238         }
1239         return false
1240     }
1241 
1242     private fun MutateStateScope.isDeviceOrProfileOwnerUid(uid: Int): Boolean {
1243         val userId = UserHandle.getUserId(uid)
1244         val ownerPackageName = newState.systemState.deviceAndProfileOwners[userId] ?: return false
1245         val ownerPackageState = newState.systemState.packageStates[ownerPackageName] ?: return false
1246         val ownerUid = UserHandle.getUid(userId, ownerPackageState.appId)
1247         return uid == ownerUid
1248     }
1249 
1250     override fun MutateStateScope.onSystemReady() {
1251         if (!privilegedPermissionAllowlistViolations.isEmpty()) {
1252             throw IllegalStateException("Signature|privileged permissions not in privileged" +
1253                 " permission allowlist: $privilegedPermissionAllowlistViolations")
1254         }
1255     }
1256 
1257     override fun BinaryXmlPullParser.parseSystemState(state: AccessState) {
1258         with(persistence) { this@parseSystemState.parseSystemState(state) }
1259     }
1260 
1261     override fun BinaryXmlSerializer.serializeSystemState(state: AccessState) {
1262         with(persistence) { this@serializeSystemState.serializeSystemState(state) }
1263     }
1264 
1265     override fun BinaryXmlPullParser.parseUserState(state: AccessState, userId: Int) {
1266         with(persistence) { this@parseUserState.parseUserState(state, userId) }
1267     }
1268 
1269     override fun BinaryXmlSerializer.serializeUserState(state: AccessState, userId: Int) {
1270         with(persistence) { this@serializeUserState.serializeUserState(state, userId) }
1271     }
1272 
1273     fun GetStateScope.getPermissionTrees(): IndexedMap<String, Permission> =
1274         state.systemState.permissionTrees
1275 
1276     fun GetStateScope.findPermissionTree(permissionName: String): Permission? =
1277         state.systemState.permissionTrees.firstNotNullOfOrNullIndexed {
1278                 _, permissionTreeName, permissionTree ->
1279             if (permissionName.startsWith(permissionTreeName) &&
1280                 permissionName.length > permissionTreeName.length &&
1281                 permissionName[permissionTreeName.length] == '.') {
1282                 permissionTree
1283             } else {
1284                 null
1285             }
1286         }
1287 
1288     fun MutateStateScope.addPermissionTree(permission: Permission) {
1289         newState.systemState.permissionTrees[permission.name] = permission
1290         newState.systemState.requestWrite()
1291     }
1292 
1293     /**
1294      * returns all permission group definitions available in the system
1295      */
1296     fun GetStateScope.getPermissionGroups(): IndexedMap<String, PermissionGroupInfo> =
1297         state.systemState.permissionGroups
1298 
1299     /**
1300      * returns all permission definitions available in the system
1301      */
1302     fun GetStateScope.getPermissions(): IndexedMap<String, Permission> =
1303         state.systemState.permissions
1304 
1305     fun MutateStateScope.addPermission(permission: Permission, sync: Boolean = false) {
1306         newState.systemState.permissions[permission.name] = permission
1307         newState.systemState.requestWrite(sync)
1308     }
1309 
1310     fun MutateStateScope.removePermission(permission: Permission) {
1311         newState.systemState.permissions -= permission.name
1312         newState.systemState.requestWrite()
1313     }
1314 
1315     fun GetStateScope.getUidPermissionFlags(appId: Int, userId: Int): IndexedMap<String, Int>? =
1316         state.userStates[userId]?.uidPermissionFlags?.get(appId)
1317 
1318     fun GetStateScope.getPermissionFlags(
1319         appId: Int,
1320         userId: Int,
1321         permissionName: String
1322     ): Int = getPermissionFlags(state, appId, userId, permissionName)
1323 
1324     private fun MutateStateScope.getOldStatePermissionFlags(
1325         appId: Int,
1326         userId: Int,
1327         permissionName: String
1328     ): Int = getPermissionFlags(oldState, appId, userId, permissionName)
1329 
1330     private fun getPermissionFlags(
1331         state: AccessState,
1332         appId: Int,
1333         userId: Int,
1334         permissionName: String
1335     ): Int =
1336         state.userStates[userId]?.uidPermissionFlags?.get(appId).getWithDefault(permissionName, 0)
1337 
1338     fun MutateStateScope.setPermissionFlags(
1339         appId: Int,
1340         userId: Int,
1341         permissionName: String,
1342         flags: Int
1343     ): Boolean =
1344         updatePermissionFlags(appId, userId, permissionName, PermissionFlags.MASK_ALL, flags)
1345 
1346     fun MutateStateScope.updatePermissionFlags(
1347         appId: Int,
1348         userId: Int,
1349         permissionName: String,
1350         flagMask: Int,
1351         flagValues: Int
1352     ): Boolean {
1353         val userState = newState.userStates[userId]
1354         val uidPermissionFlags = userState.uidPermissionFlags
1355         var permissionFlags = uidPermissionFlags[appId]
1356         val oldFlags = permissionFlags.getWithDefault(permissionName, 0)
1357         val newFlags = (oldFlags andInv flagMask) or (flagValues and flagMask)
1358         if (oldFlags == newFlags) {
1359             return false
1360         }
1361         if (permissionFlags == null) {
1362             permissionFlags = IndexedMap()
1363             uidPermissionFlags[appId] = permissionFlags
1364         }
1365         permissionFlags.putWithDefault(permissionName, newFlags, 0)
1366         if (permissionFlags.isEmpty()) {
1367             uidPermissionFlags -= appId
1368         }
1369         userState.requestWrite()
1370         onPermissionFlagsChangedListeners.forEachIndexed { _, it ->
1371             it.onPermissionFlagsChanged(appId, userId, permissionName, oldFlags, newFlags)
1372         }
1373         return true
1374     }
1375 
1376     fun addOnPermissionFlagsChangedListener(listener: OnPermissionFlagsChangedListener) {
1377         synchronized(onPermissionFlagsChangedListenersLock) {
1378             onPermissionFlagsChangedListeners = onPermissionFlagsChangedListeners + listener
1379         }
1380     }
1381 
1382     fun removeOnPermissionFlagsChangedListener(listener: OnPermissionFlagsChangedListener) {
1383         synchronized(onPermissionFlagsChangedListenersLock) {
1384             onPermissionFlagsChangedListeners = onPermissionFlagsChangedListeners - listener
1385         }
1386     }
1387 
1388     companion object {
1389         private val LOG_TAG = UidPermissionPolicy::class.java.simpleName
1390 
1391         private const val PLATFORM_PACKAGE_NAME = "android"
1392 
1393         // A set of permissions that we don't want to revoke when they are no longer implicit.
1394         private val RETAIN_IMPLICIT_FLAGS_PERMISSIONS = indexedSetOf(
1395             Manifest.permission.ACCESS_MEDIA_LOCATION,
1396             Manifest.permission.ACTIVITY_RECOGNITION,
1397             Manifest.permission.READ_MEDIA_AUDIO,
1398             Manifest.permission.READ_MEDIA_IMAGES,
1399             Manifest.permission.READ_MEDIA_VIDEO,
1400         )
1401 
1402         private val NEARBY_DEVICES_PERMISSIONS = indexedSetOf(
1403             Manifest.permission.BLUETOOTH_ADVERTISE,
1404             Manifest.permission.BLUETOOTH_CONNECT,
1405             Manifest.permission.BLUETOOTH_SCAN,
1406             Manifest.permission.NEARBY_WIFI_DEVICES
1407         )
1408 
1409         private val NOTIFICATIONS_PERMISSIONS = indexedSetOf(
1410             Manifest.permission.POST_NOTIFICATIONS
1411         )
1412 
1413         private val STORAGE_AND_MEDIA_PERMISSIONS = indexedSetOf(
1414             Manifest.permission.READ_EXTERNAL_STORAGE,
1415             Manifest.permission.WRITE_EXTERNAL_STORAGE,
1416             Manifest.permission.READ_MEDIA_AUDIO,
1417             Manifest.permission.READ_MEDIA_VIDEO,
1418             Manifest.permission.READ_MEDIA_IMAGES,
1419             Manifest.permission.ACCESS_MEDIA_LOCATION,
1420             Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED
1421         )
1422 
1423         /**
1424          * Mask for all permission flags that can be set by the user
1425          */
1426         private const val USER_SETTABLE_MASK =
1427             PermissionFlags.USER_SET or
1428                 PermissionFlags.USER_FIXED or
1429                 PermissionFlags.APP_OP_REVOKED or
1430                 PermissionFlags.ONE_TIME or
1431                 PermissionFlags.HIBERNATION or
1432                 PermissionFlags.USER_SELECTED
1433 
1434         /**
1435          * Mask for all permission flags that imply we shouldn't automatically modify the
1436          * permission grant state.
1437          */
1438         private const val SYSTEM_OR_POLICY_FIXED_MASK =
1439             PermissionFlags.SYSTEM_FIXED or PermissionFlags.POLICY_FIXED
1440     }
1441 
1442     /**
1443      * Listener for permission flags changes.
1444      */
1445     abstract class OnPermissionFlagsChangedListener {
1446         /**
1447          * Called when a permission flags change has been made to the upcoming new state.
1448          *
1449          * Implementations should keep this method fast to avoid stalling the locked state mutation,
1450          * and only call external code after [onStateMutated] when the new state has actually become
1451          * the current state visible to external code.
1452          */
1453         abstract fun onPermissionFlagsChanged(
1454             appId: Int,
1455             userId: Int,
1456             permissionName: String,
1457             oldFlags: Int,
1458             newFlags: Int
1459         )
1460 
1461         /**
1462          * Called when the upcoming new state has become the current state.
1463          *
1464          * Implementations should keep this method fast to avoid stalling the locked state mutation.
1465          */
1466         abstract fun onStateMutated()
1467     }
1468 }
1469