summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/permission/java/com/android/server/permission/access/AccessPolicy.kt2
-rw-r--r--services/permission/java/com/android/server/permission/access/permission/AppIdPermissionUpgrade.kt174
2 files changed, 173 insertions, 3 deletions
diff --git a/services/permission/java/com/android/server/permission/access/AccessPolicy.kt b/services/permission/java/com/android/server/permission/access/AccessPolicy.kt
index 1bb395441587..410539c8c5d0 100644
--- a/services/permission/java/com/android/server/permission/access/AccessPolicy.kt
+++ b/services/permission/java/com/android/server/permission/access/AccessPolicy.kt
@@ -431,7 +431,7 @@ private constructor(
companion object {
private val LOG_TAG = AccessPolicy::class.java.simpleName
- internal const val VERSION_LATEST = 16
+ internal const val VERSION_LATEST = 17
private const val TAG_ACCESS = "access"
private const val TAG_DEFAULT_PERMISSION_GRANT = "default-permission-grant"
diff --git a/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionUpgrade.kt b/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionUpgrade.kt
index 5d8886a9e2d9..022b811d9ac8 100644
--- a/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionUpgrade.kt
+++ b/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionUpgrade.kt
@@ -17,8 +17,10 @@
package com.android.server.permission.access.permission
import android.Manifest
+import android.health.connect.HealthPermissions
import android.os.Build
import android.util.Slog
+import com.android.server.permission.access.GetStateScope
import com.android.server.permission.access.MutateStateScope
import com.android.server.permission.access.immutable.* // ktlint-disable no-wildcard-imports
import com.android.server.permission.access.util.andInv
@@ -64,7 +66,7 @@ class AppIdPermissionUpgrade(private val policy: AppIdPermissionPolicy) {
", version: $version, user: $userId",
)
upgradeAuralVisualMediaPermissions(packageState, userId)
- upgradeBodySensorPermissions(packageState, userId)
+ upgradeBodySensorBackgroundPermissions(packageState, userId)
}
// TODO Enable isAtLeastU check, when moving subsystem to mainline.
if (version <= 14 /*&& SdkLevel.isAtLeastU()*/) {
@@ -75,6 +77,16 @@ class AppIdPermissionUpgrade(private val policy: AppIdPermissionPolicy) {
)
upgradeUserSelectedVisualMediaPermission(packageState, userId)
}
+ // TODO Enable isAtLeastB check, when moving subsystem to mainline.
+ if (version <= 16 /*&& SdkLevel.isAtLeastB()*/) {
+ Slog.v(
+ LOG_TAG,
+ "Upgrading body sensor / read heart rate permissions for package: $packageName" +
+ ", version: $version, user: $userId",
+ )
+ upgradeBodySensorReadHeartRatePermissions(packageState, userId)
+ }
+
// Add a new upgrade step: if (packageVersion <= LATEST_VERSION) { .... }
// Also increase LATEST_VERSION
}
@@ -182,7 +194,7 @@ class AppIdPermissionUpgrade(private val policy: AppIdPermissionPolicy) {
}
}
- private fun MutateStateScope.upgradeBodySensorPermissions(
+ private fun MutateStateScope.upgradeBodySensorBackgroundPermissions(
packageState: PackageState,
userId: Int,
) {
@@ -256,6 +268,112 @@ class AppIdPermissionUpgrade(private val policy: AppIdPermissionPolicy) {
}
}
+ /**
+ * Upgrade permissions based on the body sensors and health permissions status.
+ *
+ * Starting in BAKLAVA, the BODY_SENSORS and BODY_SENSORS_BACKGROUND permissions are being
+ * replaced by the READ_HEART_RATE and READ_HEALTH_DATA_IN_BACKGROUND permissions respectively.
+ * To ensure that older apps can continue using BODY_SENSORS without breaking we need to keep
+ * their permission state in sync with the new health permissions.
+ *
+ * The approach we take is to be as conservative as possible. This means if either permission is
+ * not granted, then we want to ensure that both end up not granted to force the user to
+ * re-grant with the expanded scope.
+ */
+ private fun MutateStateScope.upgradeBodySensorReadHeartRatePermissions(
+ packageState: PackageState,
+ userId: Int,
+ ) {
+ val androidPackage = packageState.androidPackage!!
+ if (androidPackage.targetSdkVersion >= Build.VERSION_CODES.BAKLAVA) {
+ return
+ }
+
+ // First sync BODY_SENSORS and READ_HEART_RATE, if required.
+ val isBodySensorsRequested =
+ Manifest.permission.BODY_SENSORS in androidPackage.requestedPermissions
+ val isReadHeartRateRequested =
+ HealthPermissions.READ_HEART_RATE in androidPackage.requestedPermissions
+ var isBodySensorsGranted =
+ isPermissionGranted(packageState, userId, Manifest.permission.BODY_SENSORS)
+ if (isBodySensorsRequested && isReadHeartRateRequested) {
+ val isReadHeartRateGranted =
+ isPermissionGranted(packageState, userId, HealthPermissions.READ_HEART_RATE)
+ if (isBodySensorsGranted != isReadHeartRateGranted) {
+ if (isBodySensorsGranted) {
+ if (
+ revokeRuntimePermission(
+ packageState,
+ userId,
+ Manifest.permission.BODY_SENSORS,
+ )
+ ) {
+ isBodySensorsGranted = false
+ }
+ }
+ if (isReadHeartRateGranted) {
+ revokeRuntimePermission(packageState, userId, HealthPermissions.READ_HEART_RATE)
+ }
+ }
+ }
+
+ // Then check to ensure we haven't put the background/foreground permissions out of sync.
+ var isBodySensorsBackgroundGranted =
+ isPermissionGranted(packageState, userId, Manifest.permission.BODY_SENSORS_BACKGROUND)
+ // Background permission should not be granted without the foreground permission.
+ if (!isBodySensorsGranted && isBodySensorsBackgroundGranted) {
+ if (
+ revokeRuntimePermission(
+ packageState,
+ userId,
+ Manifest.permission.BODY_SENSORS_BACKGROUND,
+ )
+ ) {
+ isBodySensorsBackgroundGranted = false
+ }
+ }
+
+ // Finally sync BODY_SENSORS_BACKGROUND and READ_HEALTH_DATA_IN_BACKGROUND, if required.
+ val isBodySensorsBackgroundRequested =
+ Manifest.permission.BODY_SENSORS_BACKGROUND in androidPackage.requestedPermissions
+ val isReadHealthDataInBackgroundRequested =
+ HealthPermissions.READ_HEALTH_DATA_IN_BACKGROUND in androidPackage.requestedPermissions
+ if (isBodySensorsBackgroundRequested && isReadHealthDataInBackgroundRequested) {
+ val isReadHealthDataInBackgroundGranted =
+ isPermissionGranted(
+ packageState,
+ userId,
+ HealthPermissions.READ_HEALTH_DATA_IN_BACKGROUND,
+ )
+ if (isBodySensorsBackgroundGranted != isReadHealthDataInBackgroundGranted) {
+ if (isBodySensorsBackgroundGranted) {
+ revokeRuntimePermission(
+ packageState,
+ userId,
+ Manifest.permission.BODY_SENSORS_BACKGROUND,
+ )
+ }
+ if (isReadHealthDataInBackgroundGranted) {
+ revokeRuntimePermission(
+ packageState,
+ userId,
+ HealthPermissions.READ_HEALTH_DATA_IN_BACKGROUND,
+ )
+ }
+ }
+ }
+ }
+
+ private fun GetStateScope.isPermissionGranted(
+ packageState: PackageState,
+ userId: Int,
+ permissionName: String,
+ ): Boolean {
+ val permissionFlags =
+ with(policy) { getPermissionFlags(packageState.appId, userId, permissionName) }
+ return PermissionFlags.isAppOpGranted(permissionFlags)
+ }
+
private fun MutateStateScope.grantRuntimePermission(
packageState: PackageState,
userId: Int,
@@ -292,6 +410,47 @@ class AppIdPermissionUpgrade(private val policy: AppIdPermissionPolicy) {
with(policy) { setPermissionFlags(appId, userId, permissionName, flags) }
}
+ /**
+ * Revoke a runtime permission for a given user from a given package.
+ *
+ * @return true if the permission was revoked, false otherwise.
+ */
+ private fun MutateStateScope.revokeRuntimePermission(
+ packageState: PackageState,
+ userId: Int,
+ permissionName: String,
+ ): Boolean {
+ Slog.v(
+ LOG_TAG,
+ "Revoking runtime permission for package: ${packageState.packageName}, " +
+ "permission: $permissionName, userId: $userId",
+ )
+ val permission = newState.systemState.permissions[permissionName]!!
+ if (packageState.getUserStateOrDefault(userId).isInstantApp && !permission.isInstant) {
+ return false
+ }
+
+ val appId = packageState.appId
+ var flags = with(policy) { getPermissionFlags(appId, userId, permissionName) }
+ if (flags.hasAnyBit(MASK_SYSTEM_OR_POLICY_FIXED)) {
+ Slog.v(
+ LOG_TAG,
+ "Not allowed to revoke $permissionName to package ${packageState.packageName} " +
+ "for user $userId",
+ )
+ return false
+ }
+
+ val newFlags =
+ flags andInv
+ (PermissionFlags.RUNTIME_GRANTED or
+ MASK_USER_SETTABLE or
+ PermissionFlags.PREGRANT or
+ PermissionFlags.ROLE)
+ with(policy) { setPermissionFlags(appId, userId, permissionName, flags) }
+ return true
+ }
+
companion object {
private val LOG_TAG = AppIdPermissionUpgrade::class.java.simpleName
@@ -302,6 +461,17 @@ class AppIdPermissionUpgrade(private val policy: AppIdPermissionPolicy) {
PermissionFlags.POLICY_FIXED or
PermissionFlags.SYSTEM_FIXED
+ private const val MASK_SYSTEM_OR_POLICY_FIXED =
+ PermissionFlags.SYSTEM_FIXED or PermissionFlags.POLICY_FIXED
+
+ private const val MASK_USER_SETTABLE =
+ PermissionFlags.USER_SET or
+ PermissionFlags.USER_FIXED or
+ PermissionFlags.APP_OP_REVOKED or
+ PermissionFlags.ONE_TIME or
+ PermissionFlags.HIBERNATION or
+ PermissionFlags.USER_SELECTED
+
private val LEGACY_RESTRICTED_PERMISSIONS =
indexedSetOf(
Manifest.permission.ACCESS_BACKGROUND_LOCATION,