diff --git a/core/api/system-current.txt b/core/api/system-current.txt index b5b87c1353e7c..053df4fe32aef 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -588,6 +588,7 @@ package android.app { field public static final String OPSTR_READ_MEDIA_IMAGES = "android:read_media_images"; field public static final String OPSTR_READ_MEDIA_VIDEO = "android:read_media_video"; field public static final String OPSTR_READ_MEDIA_VISUAL_USER_SELECTED = "android:read_media_visual_user_selected"; + field public static final String OPSTR_READ_WRITE_HEALTH_DATA = "android:read_write_health_data"; field public static final String OPSTR_RECEIVE_AMBIENT_TRIGGER_AUDIO = "android:receive_ambient_trigger_audio"; field public static final String OPSTR_RECEIVE_EMERGENCY_BROADCAST = "android:receive_emergency_broadcast"; field public static final String OPSTR_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO = "android:receive_explicit_user_interaction_audio"; diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index dc325ff96de16..afe0662b0c541 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -42,6 +42,7 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.ParceledListSlice; import android.database.DatabaseUtils; +import android.healthconnect.HealthConnectManager; import android.media.AudioAttributes.AttributeUsage; import android.os.Binder; import android.os.Build; @@ -1390,9 +1391,16 @@ public class AppOpsManager { public static final int OP_SYSTEM_EXEMPT_FROM_FORCED_APP_STANDBY = AppProtoEnums.APP_OP_SYSTEM_EXEMPT_FROM_FORCED_APP_STANDBY; + /** + * An app op for reading/writing health connect data. + * + * @hide + */ + public static final int OP_READ_WRITE_HEALTH_DATA = AppProtoEnums.APP_OP_READ_WRITE_HEALTH_DATA; + /** @hide */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public static final int _NUM_OP = 126; + public static final int _NUM_OP = 127; /** Access to coarse location information. */ public static final String OPSTR_COARSE_LOCATION = "android:coarse_location"; @@ -1872,6 +1880,15 @@ public class AppOpsManager { public static final String OPSTR_READ_MEDIA_VISUAL_USER_SELECTED = "android:read_media_visual_user_selected"; + /** + * An app op for reading/writing health connect data. + * + * @hide + */ + @SystemApi + public static final String OPSTR_READ_WRITE_HEALTH_DATA = + "android:read_write_health_data"; + /** * Record audio from near-field microphone (ie. TV remote) * Allows audio recording regardless of sensor privacy state, @@ -2400,7 +2417,9 @@ public class AppOpsManager { "SYSTEM_EXEMPT_FROM_APP_STANDBY").build(), new AppOpInfo.Builder(OP_SYSTEM_EXEMPT_FROM_FORCED_APP_STANDBY, OPSTR_SYSTEM_EXEMPT_FROM_FORCED_APP_STANDBY, - "SYSTEM_EXEMPT_FROM_FORCED_APP_STANDBY").build() + "SYSTEM_EXEMPT_FROM_FORCED_APP_STANDBY").build(), + new AppOpInfo.Builder(OP_READ_WRITE_HEALTH_DATA, OPSTR_READ_WRITE_HEALTH_DATA, + "READ_WRITE_HEALTH_DATA").setDefaultMode(AppOpsManager.MODE_ALLOWED).build() }; /** @@ -2557,7 +2576,14 @@ public class AppOpsManager { @TestApi public static int permissionToOpCode(String permission) { Integer boxedOpCode = sPermToOp.get(permission); - return boxedOpCode != null ? boxedOpCode : OP_NONE; + if (boxedOpCode != null) { + return boxedOpCode; + } + if (HealthConnectManager.isHealthPermission(ActivityThread.currentApplication(), + permission)) { + return OP_READ_WRITE_HEALTH_DATA; + } + return OP_NONE; } /** @@ -7221,10 +7247,14 @@ public class AppOpsManager { */ public static @Nullable String permissionToOp(@NonNull String permission) { final Integer opCode = sPermToOp.get(permission); - if (opCode == null) { - return null; + if (opCode != null) { + return sAppOpInfos[opCode].name; } - return sAppOpInfos[opCode].name; + if (HealthConnectManager.isHealthPermission(ActivityThread.currentApplication(), + permission)) { + return sAppOpInfos[OP_READ_WRITE_HEALTH_DATA].name; + } + return null; } /** diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java index 5f9ab959f80ad..5a638bbd5abdd 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java @@ -50,6 +50,7 @@ import android.content.pm.ParceledListSlice; import android.content.pm.PermissionGroupInfo; import android.content.pm.PermissionInfo; import android.content.pm.permission.SplitPermissionInfoParcelable; +import android.healthconnect.HealthConnectManager; import android.os.Binder; import android.os.IBinder; import android.os.Process; @@ -1156,7 +1157,8 @@ public class PermissionManagerService extends IPermissionManager.Stub { if (permissionInfo == null) { try { permissionInfo = context.getPackageManager().getPermissionInfo(permission, 0); - if (PLATFORM_PACKAGE_NAME.equals(permissionInfo.packageName)) { + if (PLATFORM_PACKAGE_NAME.equals(permissionInfo.packageName) + || HealthConnectManager.isHealthPermission(context, permission)) { // Double addition due to concurrency is fine - the backing // store is concurrent. sPlatformPermissions.put(permission, permissionInfo);