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