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