1 /* <lambda>null2 * Copyright (C) 2019 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.permissioncontroller.permission.service 18 19 import android.Manifest.permission 20 import android.Manifest.permission_group 21 import android.content.Context 22 import android.content.pm.PackageInfo 23 import android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT 24 import android.content.pm.PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE 25 import android.content.pm.PermissionInfo 26 import android.os.Build 27 import android.os.Process.myUserHandle 28 import android.permission.PermissionManager 29 import android.util.Log 30 import com.android.modules.utils.build.SdkLevel 31 import com.android.permissioncontroller.DeviceUtils 32 import com.android.permissioncontroller.PermissionControllerStatsLog 33 import com.android.permissioncontroller.PermissionControllerStatsLog.RUNTIME_PERMISSIONS_UPGRADE_RESULT 34 import com.android.permissioncontroller.permission.data.LightAppPermGroupLiveData 35 import com.android.permissioncontroller.permission.data.LightPermInfoLiveData 36 import com.android.permissioncontroller.permission.data.PreinstalledUserPackageInfosLiveData 37 import com.android.permissioncontroller.permission.data.SmartUpdateMediatorLiveData 38 import com.android.permissioncontroller.permission.data.UserPackageInfosLiveData 39 import com.android.permissioncontroller.permission.data.get 40 import com.android.permissioncontroller.permission.model.livedatatypes.LightAppPermGroup 41 import com.android.permissioncontroller.permission.model.livedatatypes.LightPackageInfo 42 import com.android.permissioncontroller.permission.model.livedatatypes.LightPermission 43 import com.android.permissioncontroller.permission.utils.IPC 44 import com.android.permissioncontroller.permission.utils.KotlinUtils.grantBackgroundRuntimePermissions 45 import com.android.permissioncontroller.permission.utils.KotlinUtils.grantForegroundRuntimePermissions 46 import com.android.permissioncontroller.permission.utils.PermissionMapping 47 import com.android.permissioncontroller.permission.utils.PermissionMapping.getPlatformPermissionNamesOfGroup 48 import com.android.permissioncontroller.permission.utils.PermissionMapping.getRuntimePlatformPermissionNames 49 import com.android.permissioncontroller.permission.utils.Utils.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT 50 import com.android.permissioncontroller.permission.utils.application 51 import kotlinx.coroutines.GlobalScope 52 import kotlinx.coroutines.launch 53 54 /** This class handles upgrading the runtime permissions database */ 55 object RuntimePermissionsUpgradeController { 56 private val LOG_TAG = RuntimePermissionsUpgradeController::class.java.simpleName 57 private const val DEBUG = false 58 59 // The latest version of the runtime permissions database 60 private val LATEST_VERSION = 61 if (SdkLevel.isAtLeastU()) { 62 11 63 } else if (SdkLevel.isAtLeastT()) { 64 10 65 } else { 66 9 67 } 68 69 @Suppress("MissingPermission") 70 fun upgradeIfNeeded(context: Context, onComplete: Runnable) { 71 val permissionManager = context.getSystemService(PermissionManager::class.java) 72 val storedVersion = permissionManager!!.runtimePermissionsVersion 73 val currentVersion = minOf(storedVersion, LATEST_VERSION) 74 75 GlobalScope.launch(IPC) { 76 val upgradedVersion = onUpgradeLocked(context, currentVersion) 77 if (upgradedVersion != LATEST_VERSION) { 78 Log.wtf( 79 "PermissionControllerService", 80 "warning: upgrading permission database" + 81 " to version $LATEST_VERSION left it at $currentVersion instead; this is " + 82 "probably a bug. Did you update LATEST_VERSION?", 83 Throwable() 84 ) 85 throw RuntimeException("db upgrade error") 86 } 87 88 if (storedVersion != upgradedVersion) { 89 permissionManager.runtimePermissionsVersion = LATEST_VERSION 90 } 91 onComplete.run() 92 } 93 } 94 95 /** 96 * Create exemptions for select restricted permissions of select apps. 97 * 98 * @param permissionInfos permissions to exempt 99 * @param pkgs packages to exempt 100 * @return the exemptions to apply 101 */ 102 private fun getExemptions( 103 permissions: Set<String>, 104 pkgs: List<LightPackageInfo>, 105 flags: Int = FLAG_PERMISSION_WHITELIST_UPGRADE 106 ): List<RestrictionExemption> { 107 val exemptions = mutableListOf<RestrictionExemption>() 108 109 for (pkg in pkgs) { 110 for (permission in permissions intersect pkg.requestedPermissions) { 111 exemptions.add(RestrictionExemption(pkg.packageName, permission, flags)) 112 } 113 } 114 115 return exemptions 116 } 117 118 /** 119 * You must perform all necessary mutations to bring the runtime permissions database from the 120 * old to the new version. When you add a new upgrade step you *must* update LATEST_VERSION. 121 * 122 * <p> NOTE: Relies upon the fact that the system will attempt to upgrade every version after 123 * currentVersion in order, without skipping any versions. Should this become the case, this 124 * method MUST be updated. 125 * 126 * @param context The current context 127 * @param currentVersion The current version of the permission database 128 */ 129 private suspend fun onUpgradeLocked(context: Context, currentVersion: Int): Int { 130 var sdkUpgradedFromP = false 131 var isNewUser = false 132 133 if (currentVersion <= -1) { 134 sdkUpgradedFromP = true 135 } else if (currentVersion == 0) { 136 isNewUser = true 137 } 138 139 val needBackgroundAppPermGroups = sdkUpgradedFromP && currentVersion <= 6 140 val needAccessMediaAppPermGroups = !isNewUser && currentVersion <= 7 141 val needGrantedExternalStorage = currentVersion <= 9 && SdkLevel.isAtLeastT() 142 val needBodySensorsAppPermGroups = 143 DeviceUtils.isWear(context) && currentVersion <= 9 && SdkLevel.isAtLeastT() 144 val needGrantedReadMediaVisual = currentVersion <= 10 && SdkLevel.isAtLeastU() 145 val isDeviceUpgrading = context.packageManager.isDeviceUpgrading 146 147 // All data needed by this method. 148 // 149 // All data is loaded once and then not updated. 150 val upgradeDataProvider = 151 object : SmartUpdateMediatorLiveData<UpgradeData>() { 152 /** Provides all preinstalled packages in the system */ 153 private val preinstalledPkgInfoProvider = 154 PreinstalledUserPackageInfosLiveData[myUserHandle()] 155 156 /** Provides all platform runtime permission infos */ 157 private val platformRuntimePermissionInfoProviders = 158 mutableListOf<LightPermInfoLiveData>() 159 160 /** {@link #platformRuntimePermissionInfoProvider} that already provided a result */ 161 private val platformRuntimePermissionInfoProvidersDone = 162 mutableSetOf<LightPermInfoLiveData>() 163 164 /** Provides all packages in the system */ 165 private val pkgInfoProvider = UserPackageInfosLiveData[myUserHandle()] 166 167 /** Provides all {@link LightAppPermGroup} this upgrade needs */ 168 private var permGroupProviders: MutableSet<LightAppPermGroupLiveData>? = null 169 170 /** {@link #permGroupProviders} that already provided a result */ 171 private val permGroupProvidersDone = mutableSetOf<LightAppPermGroupLiveData>() 172 173 init { 174 // First step: Load packages + perm infos 175 addSource(pkgInfoProvider) { pkgInfos -> 176 if (pkgInfos != null) { 177 removeSource(pkgInfoProvider) 178 179 addSource(preinstalledPkgInfoProvider) { preinstalledPkgInfos -> 180 if (preinstalledPkgInfos != null) { 181 removeSource(preinstalledPkgInfoProvider) 182 183 update() 184 } 185 } 186 } 187 } 188 189 for (platformRuntimePermission in getRuntimePlatformPermissionNames()) { 190 val permProvider = LightPermInfoLiveData[platformRuntimePermission] 191 platformRuntimePermissionInfoProviders.add(permProvider) 192 193 addSource(permProvider) { permInfo -> 194 if (permInfo != null) { 195 platformRuntimePermissionInfoProvidersDone.add(permProvider) 196 removeSource(permProvider) 197 198 update() 199 } 200 } 201 } 202 } 203 204 override fun onUpdate() { 205 if (permGroupProviders == null && pkgInfoProvider.value != null) { 206 // Second step: Trigger load of app-perm-groups 207 208 permGroupProviders = mutableSetOf() 209 210 // Only load app-perm-groups needed for this upgrade 211 if ( 212 needBackgroundAppPermGroups || 213 needAccessMediaAppPermGroups || 214 needGrantedExternalStorage || 215 needGrantedReadMediaVisual || 216 needBodySensorsAppPermGroups 217 ) { 218 for ((pkgName, _, requestedPerms, requestedPermFlags) in 219 pkgInfoProvider.value!!) { 220 var requestsAccessMediaLocation = false 221 var hasGrantedExternalStorage = false 222 var hasGrantedReadMediaVisual = false 223 224 for ((perm, flags) in requestedPerms.zip(requestedPermFlags)) { 225 if ( 226 needBackgroundAppPermGroups && 227 perm == permission.ACCESS_BACKGROUND_LOCATION 228 ) { 229 permGroupProviders!!.add( 230 LightAppPermGroupLiveData[ 231 pkgName, permission_group.LOCATION, myUserHandle()] 232 ) 233 } 234 235 if ( 236 needAccessMediaAppPermGroups || 237 needGrantedExternalStorage || 238 needGrantedReadMediaVisual 239 ) { 240 if ( 241 needAccessMediaAppPermGroups && 242 perm == permission.ACCESS_MEDIA_LOCATION 243 ) { 244 requestsAccessMediaLocation = true 245 } 246 247 val isGranted = 248 flags and PackageInfo.REQUESTED_PERMISSION_GRANTED != 0 249 if (perm == permission.READ_EXTERNAL_STORAGE && isGranted) { 250 hasGrantedExternalStorage = true 251 } 252 if ( 253 PermissionMapping.getGroupOfPlatformPermission(perm) == 254 permission_group.READ_MEDIA_VISUAL && isGranted 255 ) { 256 hasGrantedReadMediaVisual = true 257 } 258 } 259 260 if ( 261 needBodySensorsAppPermGroups && 262 perm == permission.BODY_SENSORS_BACKGROUND 263 ) { 264 permGroupProviders!!.add( 265 LightAppPermGroupLiveData[ 266 pkgName, permission_group.SENSORS, myUserHandle()] 267 ) 268 } 269 } 270 271 val accessMediaLocationPermGroup = 272 if (SdkLevel.isAtLeastT()) permission_group.READ_MEDIA_VISUAL 273 else permission_group.STORAGE 274 275 if (hasGrantedExternalStorage) { 276 if (needGrantedExternalStorage) { 277 permGroupProviders!!.add( 278 LightAppPermGroupLiveData[ 279 pkgName, permission_group.STORAGE, myUserHandle()] 280 ) 281 if (SdkLevel.isAtLeastT()) { 282 permGroupProviders!!.add( 283 LightAppPermGroupLiveData[ 284 pkgName, 285 permission_group.READ_MEDIA_VISUAL, 286 myUserHandle()] 287 ) 288 permGroupProviders!!.add( 289 LightAppPermGroupLiveData[ 290 pkgName, 291 permission_group.READ_MEDIA_AURAL, 292 myUserHandle()] 293 ) 294 } 295 } else if (requestsAccessMediaLocation) { 296 permGroupProviders!!.add( 297 LightAppPermGroupLiveData[ 298 pkgName, 299 accessMediaLocationPermGroup, 300 myUserHandle()] 301 ) 302 } 303 } 304 if (hasGrantedReadMediaVisual && needGrantedReadMediaVisual) { 305 permGroupProviders!!.add( 306 LightAppPermGroupLiveData[ 307 pkgName, 308 permission_group.READ_MEDIA_VISUAL, 309 myUserHandle()] 310 ) 311 } 312 } 313 } 314 315 // Wait until groups are loaded and then trigger third step 316 for (permGroupProvider in permGroupProviders!!) { 317 addSource(permGroupProvider) { group -> 318 if (group != null) { 319 permGroupProvidersDone.add(permGroupProvider) 320 removeSource(permGroupProvider) 321 322 update() 323 } 324 } 325 } 326 327 // If no group need to be loaded, directly switch to third step 328 if (permGroupProviders!!.isEmpty()) { 329 update() 330 } 331 } else if ( 332 permGroupProviders != null && 333 permGroupProvidersDone.size == permGroupProviders!!.size && 334 preinstalledPkgInfoProvider.value != null && 335 platformRuntimePermissionInfoProviders.size == 336 platformRuntimePermissionInfoProvidersDone.size 337 ) { 338 // Third step: All packages, perm infos and perm groups are loaded, set 339 // value 340 341 val bgGroups = mutableListOf<LightAppPermGroup>() 342 val storageGroups = mutableListOf<LightAppPermGroup>() 343 val bgSensorsGroups = mutableListOf<LightAppPermGroup>() 344 345 for (group in permGroupProviders!!.mapNotNull { it.value }) { 346 when (group.permGroupName) { 347 permission_group.LOCATION -> { 348 bgGroups.add(group) 349 } 350 permission_group.STORAGE -> { 351 storageGroups.add(group) 352 } 353 permission_group.READ_MEDIA_AURAL -> { 354 storageGroups.add(group) 355 } 356 permission_group.READ_MEDIA_VISUAL -> { 357 storageGroups.add(group) 358 } 359 permission_group.SENSORS -> { 360 bgSensorsGroups.add(group) 361 } 362 } 363 } 364 365 val restrictedPermissions = mutableSetOf<String>() 366 for (permInfoLiveDt in platformRuntimePermissionInfoProviders) { 367 val permInfo = permInfoLiveDt.value!! 368 369 if ( 370 permInfo.flags and 371 (PermissionInfo.FLAG_HARD_RESTRICTED or 372 PermissionInfo.FLAG_SOFT_RESTRICTED) == 0 373 ) { 374 continue 375 } 376 377 restrictedPermissions.add(permInfo.name) 378 } 379 380 value = 381 UpgradeData( 382 preinstalledPkgInfoProvider.value!!, 383 restrictedPermissions, 384 pkgInfoProvider.value!!, 385 bgGroups, 386 storageGroups, 387 bgSensorsGroups 388 ) 389 } 390 } 391 } 392 393 // Trigger loading of data and wait until data is loaded 394 val upgradeData = upgradeDataProvider.getInitializedValue(forceUpdate = true)!! 395 396 // Only exempt permissions that are in the OTA. Apps that are updated via OTAs are never 397 // installed. Hence their permission are never exempted. This code replaces that by 398 // always exempting them. For non-OTA updates the installer should do the exemption. 399 // If a restricted permission can't be exempted by the installer then it should be filtered 400 // out here. 401 val preinstalledAppExemptions = 402 getExemptions(upgradeData.restrictedPermissions, upgradeData.preinstalledPkgs) 403 404 val (newVersion, upgradeExemptions, grants) = 405 onUpgradeLockedDataLoaded( 406 currentVersion, 407 upgradeData.pkgs, 408 upgradeData.restrictedPermissions, 409 upgradeData.bgGroups, 410 upgradeData.storageGroups, 411 upgradeData.bgSensorsGroups, 412 isDeviceUpgrading 413 ) 414 415 // Do not run in parallel. Measurements have shown that this is slower than sequential 416 for (exemption in (preinstalledAppExemptions union upgradeExemptions)) { 417 exemption.applyToPlatform(context) 418 } 419 420 for (grant in grants) { 421 grant.applyToPlatform(context) 422 } 423 424 return newVersion 425 } 426 427 private fun onUpgradeLockedDataLoaded( 428 currVersion: Int, 429 pkgs: List<LightPackageInfo>, 430 restrictedPermissions: Set<String>, 431 bgApps: List<LightAppPermGroup>, 432 storageAndMediaAppPermGroups: List<LightAppPermGroup>, 433 bgSensorsGroups: List<LightAppPermGroup>, 434 isDeviceUpgrading: Boolean 435 ): Triple<Int, List<RestrictionExemption>, List<Grant>> { 436 val exemptions = mutableListOf<RestrictionExemption>() 437 val grants = mutableListOf<Grant>() 438 439 var currentVersion = currVersion 440 var sdkUpgradedFromP = false 441 var isNewUser = false 442 val bgAppsWithExemption = bgApps.map { it.packageName to it }.toMap().toMutableMap() 443 444 if (currentVersion <= -1) { 445 Log.i(LOG_TAG, "Upgrading from Android P") 446 447 sdkUpgradedFromP = true 448 449 currentVersion = 0 450 } else { 451 // If the initial version is 0 the permission state was just created 452 if (currentVersion == 0) { 453 isNewUser = true 454 } 455 } 456 457 if (currentVersion == 0) { 458 Log.i(LOG_TAG, "Grandfathering SMS and CallLog permissions") 459 460 val permissions = 461 restrictedPermissions intersect 462 (getPlatformPermissionNamesOfGroup(permission_group.SMS) + 463 getPlatformPermissionNamesOfGroup(permission_group.CALL_LOG)) 464 465 exemptions.addAll(getExemptions(permissions, pkgs)) 466 467 currentVersion = 1 468 } 469 470 if (currentVersion == 1) { 471 // moved to step 4->5 as it has to be after the grandfathering of loc bg perms 472 currentVersion = 2 473 } 474 475 if (currentVersion == 2) { 476 // moved to step 5->6 to clean up broken permission state during dogfooding 477 currentVersion = 3 478 } 479 480 if (currentVersion == 3) { 481 Log.i(LOG_TAG, "Grandfathering location background permissions") 482 483 val bgLocExemptions = getExemptions(setOf(permission.ACCESS_BACKGROUND_LOCATION), pkgs) 484 485 // Adjust bgApps as if the exemption was applied 486 for ((pkgName, _) in bgLocExemptions) { 487 val bgApp = bgAppsWithExemption[pkgName] ?: continue 488 val perm = bgApp.allPermissions[permission.ACCESS_BACKGROUND_LOCATION] ?: continue 489 490 val allPermissionsWithxemption = bgApp.allPermissions.toMutableMap() 491 allPermissionsWithxemption[permission.ACCESS_BACKGROUND_LOCATION] = 492 LightPermission( 493 perm.pkgInfo, 494 perm.permInfo, 495 perm.isGrantedIncludingAppOp, 496 perm.flags or FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT, 497 perm.foregroundPerms 498 ) 499 500 bgAppsWithExemption[pkgName] = 501 LightAppPermGroup( 502 bgApp.packageInfo, 503 bgApp.permGroupInfo, 504 allPermissionsWithxemption, 505 bgApp.hasInstallToRuntimeSplit, 506 bgApp.specialLocationGrant 507 ) 508 } 509 510 exemptions.addAll(bgLocExemptions) 511 512 currentVersion = 4 513 } 514 515 if (currentVersion == 4) { 516 // moved to step 5->6 to clean up broken permission state during beta 4->5 upgrade 517 currentVersion = 5 518 } 519 520 if (currentVersion == 5) { 521 Log.i(LOG_TAG, "Grandfathering Storage permissions") 522 523 val permissions = 524 restrictedPermissions intersect 525 getPlatformPermissionNamesOfGroup(permission_group.STORAGE) 526 527 // We don't want to allow modification of storage post install, so put it 528 // on the internal system exemptlist to prevent the installer changing it. 529 exemptions.addAll(getExemptions(permissions, pkgs)) 530 531 currentVersion = 6 532 } 533 534 if (currentVersion == 6) { 535 if (sdkUpgradedFromP) { 536 Log.i(LOG_TAG, "Expanding location permissions") 537 for (appPermGroup in bgAppsWithExemption.values) { 538 if ( 539 appPermGroup.foreground.isGranted && 540 appPermGroup.hasBackgroundGroup && 541 !appPermGroup.background.isUserSet && 542 !appPermGroup.background.isSystemFixed && 543 !appPermGroup.background.isPolicyFixed && 544 !appPermGroup.background.isUserFixed 545 ) { 546 grants.add(Grant(true, appPermGroup)) 547 } 548 } 549 } else { 550 Log.i( 551 LOG_TAG, 552 "Not expanding location permissions as this is not an upgrade " + 553 "from Android P" 554 ) 555 } 556 557 currentVersion = 7 558 } 559 560 if (currentVersion == 7) { 561 if (!isNewUser) { 562 Log.i(LOG_TAG, "Expanding read storage to access media location") 563 564 for (appPermGroup in storageAndMediaAppPermGroups) { 565 val perm = 566 appPermGroup.permissions[permission.ACCESS_MEDIA_LOCATION] ?: continue 567 568 if ( 569 !perm.isUserSet && 570 !perm.isSystemFixed && 571 !perm.isPolicyFixed && 572 !perm.isGrantedIncludingAppOp 573 ) { 574 grants.add( 575 Grant(false, appPermGroup, listOf(permission.ACCESS_MEDIA_LOCATION)) 576 ) 577 } 578 } 579 } else { 580 Log.i( 581 LOG_TAG, 582 "Not expanding read storage to access media location as this is " + "a new user" 583 ) 584 } 585 586 currentVersion = 8 587 } 588 589 if (currentVersion == 8) { 590 // Removed 591 592 currentVersion = 9 593 } 594 595 if (currentVersion == 9 && SdkLevel.isAtLeastT()) { 596 if (isNewUser) { 597 Log.i( 598 LOG_TAG, 599 "Not migrating STORAGE and BODY_SENSORS permissions as this is a new user" 600 ) 601 } else if (!isDeviceUpgrading) { 602 Log.i( 603 LOG_TAG, 604 "Not migrating STORAGE and BODY_SENSORS permissions as" + 605 " this device is not performing an upgrade" 606 ) 607 } else { 608 Log.i(LOG_TAG, "Migrating STORAGE permissions to READ_MEDIA permissions") 609 610 // Upon upgrading to platform 33, for all targetSdk>=33 apps, do the following: 611 // If STORAGE is granted, and the user has not set READ_MEDIA_AURAL or 612 // READ_MEDIA_VISUAL, grant READ_MEDIA_AURAL and READ_MEDIA_VISUAL 613 val storageAppPermGroups = 614 storageAndMediaAppPermGroups.filter { 615 it.packageInfo.targetSdkVersion >= Build.VERSION_CODES.TIRAMISU && 616 it.permGroupInfo.name == permission_group.STORAGE && 617 it.isGranted && 618 it.isUserSet 619 } 620 for (storageAppPermGroup in storageAppPermGroups) { 621 val pkgName = storageAppPermGroup.packageInfo.packageName 622 val auralAppPermGroup = 623 storageAndMediaAppPermGroups.firstOrNull { 624 it.packageInfo.packageName == pkgName && 625 it.permGroupInfo.name == permission_group.READ_MEDIA_AURAL && 626 !it.isUserSet && 627 !it.isUserFixed 628 } 629 val visualAppPermGroup = 630 storageAndMediaAppPermGroups.firstOrNull { 631 it.packageInfo.packageName == pkgName && 632 it.permGroupInfo.name == permission_group.READ_MEDIA_VISUAL && 633 !it.permissions 634 .filter { it.key != permission.ACCESS_MEDIA_LOCATION } 635 .any { it.value.isUserSet || it.value.isUserFixed } 636 } 637 638 if (auralAppPermGroup != null) { 639 grants.add(Grant(false, auralAppPermGroup)) 640 } 641 if (visualAppPermGroup != null) { 642 grants.add(Grant(false, visualAppPermGroup)) 643 } 644 } 645 646 // Granting body sensors background permission to apps that had the pre-split body 647 // sensors permission granted. 648 Log.i(LOG_TAG, "Grandfathering body sensors background permissions") 649 650 for (bgSensorsGroup in bgSensorsGroups) { 651 val perm = 652 bgSensorsGroup.allPermissions[permission.BODY_SENSORS_BACKGROUND] 653 ?: continue 654 if (perm.flags and FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT != 0) { 655 continue 656 } 657 658 // Exempt the background permission to allow setting from users. 659 val pkgName = bgSensorsGroup.packageName 660 exemptions.add( 661 RestrictionExemption( 662 pkgName, 663 permission.BODY_SENSORS_BACKGROUND, 664 FLAG_PERMISSION_WHITELIST_UPGRADE 665 ) 666 ) 667 668 val allPermissionsWithExemption = bgSensorsGroup.allPermissions.toMutableMap() 669 allPermissionsWithExemption[permission.BODY_SENSORS_BACKGROUND] = 670 LightPermission( 671 perm.pkgInfo, 672 perm.permInfo, 673 perm.isGrantedIncludingAppOp, 674 perm.flags or FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT, 675 perm.foregroundPerms 676 ) 677 val group = 678 LightAppPermGroup( 679 bgSensorsGroup.packageInfo, 680 bgSensorsGroup.permGroupInfo, 681 allPermissionsWithExemption, 682 bgSensorsGroup.hasInstallToRuntimeSplit, 683 bgSensorsGroup.specialLocationGrant 684 ) 685 686 // Grant the background permission only if foreground permission is granted. 687 if (group.foreground.isGranted) { 688 if (DEBUG) { 689 Log.i(LOG_TAG, "$pkgName Granted body sensors background permissions") 690 } 691 grants.add(Grant(isBackground = true, group = group)) 692 } 693 } 694 } 695 currentVersion = 10 696 } 697 698 if (currentVersion == 10 && SdkLevel.isAtLeastU()) { 699 // On U, if the app is granted READ_MEDIA_VISUAL, expand the grant to 700 // READ_MEDIA_VISUAL_USER_SELECTED 701 if (isDeviceUpgrading && !isNewUser) { 702 Log.i( 703 LOG_TAG, 704 "Grandfathering READ_MEDIA_VISUAL_USER_SELECTED to apps already " + 705 "granted visual permissions" 706 ) 707 val visualAppPermGroups = 708 storageAndMediaAppPermGroups.filter { 709 it.packageInfo.targetSdkVersion >= Build.VERSION_CODES.TIRAMISU && 710 it.permGroupInfo.name == permission_group.READ_MEDIA_VISUAL && 711 it.isGranted && 712 it.isUserSet 713 } 714 visualAppPermGroups.forEach { grants.add(Grant(false, it)) } 715 } 716 currentVersion = 11 717 } 718 719 // XXX: Add new upgrade steps above this point. 720 721 return Triple(currentVersion, exemptions, grants) 722 } 723 724 /** All data needed by {@link #onUpgradeLocked} */ 725 private data class UpgradeData( 726 /** Preinstalled packages */ 727 val preinstalledPkgs: List<LightPackageInfo>, 728 /** Restricted permissions */ 729 val restrictedPermissions: Set<String>, 730 /** Currently installed packages */ 731 val pkgs: List<LightPackageInfo>, 732 /** 733 * Background Location groups that need to be inspected by 734 * {@link #onUpgradeLockedDataLoaded} 735 */ 736 val bgGroups: List<LightAppPermGroup>, 737 /** Storage groups that need to be inspected by {@link #onUpgradeLockedDataLoaded} */ 738 val storageGroups: List<LightAppPermGroup>, 739 /** 740 * Background Sensors groups that need to be inspected by {@link #onUpgradeLockedDataLoaded} 741 */ 742 val bgSensorsGroups: List<LightAppPermGroup>, 743 ) 744 745 /** A restricted permission of an app that should be exempted */ 746 private data class RestrictionExemption( 747 /** Name of package to exempt */ 748 val pkgName: String, 749 /** Name of permissions to exempt */ 750 val permission: String, 751 /** Name of permissions to exempt */ 752 val flags: Int = FLAG_PERMISSION_WHITELIST_UPGRADE 753 ) { 754 /** 755 * Exempt the permission by updating the platform state. 756 * 757 * @param context context to use when calling the platform 758 */ 759 fun applyToPlatform(context: Context) { 760 context.packageManager.addWhitelistedRestrictedPermission(pkgName, permission, flags) 761 } 762 } 763 764 /** A permission group of an app that should get granted */ 765 private data class Grant( 766 /** Should the grant be for the foreground or background permissions */ 767 private val isBackground: Boolean, 768 /** Group to be granted */ 769 private val group: LightAppPermGroup, 770 /** Which of the permissions in the group should be granted */ 771 private val permissions: List<String> = group.permissions.keys.toList() 772 ) { 773 /** 774 * Grant the permission by updating the platform state. 775 * 776 * @param context context to use when calling the platform 777 */ 778 fun applyToPlatform(context: Context) { 779 if (isBackground) { 780 val newGroup = 781 grantBackgroundRuntimePermissions(context.application, group, permissions) 782 783 logRuntimePermissionUpgradeResult( 784 newGroup, 785 permissions intersect newGroup.backgroundPermNames 786 ) 787 } else { 788 val newGroup = 789 grantForegroundRuntimePermissions(context.application, group, permissions) 790 791 logRuntimePermissionUpgradeResult( 792 newGroup, 793 permissions intersect newGroup.foregroundPermNames 794 ) 795 } 796 } 797 798 /** 799 * Log to the platform that permissions were granted due to an update 800 * 801 * @param permissionGroup The group that was granted 802 * @param filterPermissions Out of the group which permissions were granted 803 */ 804 private fun logRuntimePermissionUpgradeResult( 805 permissionGroup: LightAppPermGroup, 806 filterPermissions: Iterable<String> 807 ) { 808 val uid = permissionGroup.packageInfo.uid 809 val packageName = permissionGroup.packageName 810 for (permName in filterPermissions) { 811 val permission = permissionGroup.permissions[permName] ?: continue 812 PermissionControllerStatsLog.write( 813 RUNTIME_PERMISSIONS_UPGRADE_RESULT, 814 permission.name, 815 uid, 816 packageName 817 ) 818 Log.i( 819 LOG_TAG, 820 "Runtime permission upgrade logged for permissionName=" + 821 permission.name + 822 " uid=" + 823 uid + 824 " packageName=" + 825 packageName 826 ) 827 } 828 } 829 } 830 } /* do nothing - hide constructor */ 831