From 8e4ffc82c27214003150a1dc776086952d02a75a Mon Sep 17 00:00:00 2001 From: Jing Ji Date: Sun, 6 Nov 2022 11:33:57 -0800 Subject: [PATCH] Introduce foreground service type enforcement All foreground services are required to declare a type now, or it'll get a ForegroundServiceTypeNotAllowedException if the app's target SDK level is Android U or later. Upon starting the foreground service, the app is required to have been granted with the proper permissions which are required by the foreground service types it's starting with. Deprecated the type "none" and "dataSync", introduced new types: "heath", "remoteMessaging", "systemExempted" and "specialUse". The implementation of the enforcement will be in a follow up CL. Bug: 246792057 Bug: 254662338 Test: atest CtsAppFgsTestCases Change-Id: I54e60b443df8134653379a6ff13e00ed14d3f194 --- core/api/current.txt | 37 ++- core/java/android/app/AppOpsManager.java | 25 +- core/java/android/app/Service.java | 137 ++++++--- .../android/content/pm/PackageManager.java | 15 + core/java/android/content/pm/ServiceInfo.java | 265 +++++++++++++++++- core/res/AndroidManifest.xml | 110 ++++++++ core/res/res/values/attrs_manifest.xml | 110 +++++++- core/res/res/values/strings.xml | 60 ++++ .../com/android/server/am/AppFGSTracker.java | 4 +- 9 files changed, 694 insertions(+), 69 deletions(-) diff --git a/core/api/current.txt b/core/api/current.txt index b89c3f7ffd956..b01afa4aa8d19 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -91,6 +91,18 @@ package android { field public static final String EXPAND_STATUS_BAR = "android.permission.EXPAND_STATUS_BAR"; field public static final String FACTORY_TEST = "android.permission.FACTORY_TEST"; field public static final String FOREGROUND_SERVICE = "android.permission.FOREGROUND_SERVICE"; + field public static final String FOREGROUND_SERVICE_CAMERA = "android.permission.FOREGROUND_SERVICE_CAMERA"; + field public static final String FOREGROUND_SERVICE_CONNECTED_DEVICE = "android.permission.FOREGROUND_SERVICE_CONNECTED_DEVICE"; + field public static final String FOREGROUND_SERVICE_DATA_SYNC = "android.permission.FOREGROUND_SERVICE_DATA_SYNC"; + field public static final String FOREGROUND_SERVICE_HEALTH = "android.permission.FOREGROUND_SERVICE_HEALTH"; + field public static final String FOREGROUND_SERVICE_LOCATION = "android.permission.FOREGROUND_SERVICE_LOCATION"; + field public static final String FOREGROUND_SERVICE_MEDIA_PLAYBACK = "android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK"; + field public static final String FOREGROUND_SERVICE_MEDIA_PROJECTION = "android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION"; + field public static final String FOREGROUND_SERVICE_MICROPHONE = "android.permission.FOREGROUND_SERVICE_MICROPHONE"; + field public static final String FOREGROUND_SERVICE_PHONE_CALL = "android.permission.FOREGROUND_SERVICE_PHONE_CALL"; + field public static final String FOREGROUND_SERVICE_REMOTE_MESSAGING = "android.permission.FOREGROUND_SERVICE_REMOTE_MESSAGING"; + field public static final String FOREGROUND_SERVICE_SPECIAL_USE = "android.permission.FOREGROUND_SERVICE_SPECIAL_USE"; + field public static final String FOREGROUND_SERVICE_SYSTEM_EXEMPTED = "android.permission.FOREGROUND_SERVICE_SYSTEM_EXEMPTED"; field public static final String GET_ACCOUNTS = "android.permission.GET_ACCOUNTS"; field public static final String GET_ACCOUNTS_PRIVILEGED = "android.permission.GET_ACCOUNTS_PRIVILEGED"; field public static final String GET_PACKAGE_SIZE = "android.permission.GET_PACKAGE_SIZE"; @@ -6946,7 +6958,7 @@ package android.app { method public void onTrimMemory(int); method public boolean onUnbind(android.content.Intent); method public final void startForeground(int, android.app.Notification); - method public final void startForeground(int, @NonNull android.app.Notification, int); + method public final void startForeground(int, @NonNull android.app.Notification, @RequiresPermission int); method @Deprecated public final void stopForeground(boolean); method public final void stopForeground(int); method public final void stopSelf(); @@ -12194,6 +12206,7 @@ package android.content.pm { field public static final int PERMISSION_DENIED = -1; // 0xffffffff field public static final int PERMISSION_GRANTED = 0; // 0x0 field public static final String PROPERTY_MEDIA_CAPABILITIES = "android.media.PROPERTY_MEDIA_CAPABILITIES"; + field public static final String PROPERTY_SPECIAL_USE_FGS_SUBTYPE = "android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE"; field public static final int SIGNATURE_FIRST_NOT_SIGNED = -1; // 0xffffffff field public static final int SIGNATURE_MATCH = 0; // 0x0 field public static final int SIGNATURE_NEITHER_SIGNED = 1; // 0x1 @@ -12407,16 +12420,20 @@ package android.content.pm { field public static final int FLAG_SINGLE_USER = 1073741824; // 0x40000000 field public static final int FLAG_STOP_WITH_TASK = 1; // 0x1 field public static final int FLAG_USE_APP_ZYGOTE = 8; // 0x8 - field public static final int FOREGROUND_SERVICE_TYPE_CAMERA = 64; // 0x40 - field public static final int FOREGROUND_SERVICE_TYPE_CONNECTED_DEVICE = 16; // 0x10 - field public static final int FOREGROUND_SERVICE_TYPE_DATA_SYNC = 1; // 0x1 - field public static final int FOREGROUND_SERVICE_TYPE_LOCATION = 8; // 0x8 + field @RequiresPermission(allOf={android.Manifest.permission.FOREGROUND_SERVICE_CAMERA}, anyOf={android.Manifest.permission.CAMERA}, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_CAMERA = 64; // 0x40 + field @RequiresPermission(allOf={android.Manifest.permission.FOREGROUND_SERVICE_CONNECTED_DEVICE}, anyOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.CHANGE_NETWORK_STATE, android.Manifest.permission.CHANGE_WIFI_STATE, android.Manifest.permission.CHANGE_WIFI_MULTICAST_STATE, android.Manifest.permission.NFC, android.Manifest.permission.TRANSMIT_IR}, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_CONNECTED_DEVICE = 16; // 0x10 + field @Deprecated @RequiresPermission(value=android.Manifest.permission.FOREGROUND_SERVICE_DATA_SYNC, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_DATA_SYNC = 1; // 0x1 + field @RequiresPermission(allOf={android.Manifest.permission.FOREGROUND_SERVICE_HEALTH}, anyOf={android.Manifest.permission.ACTIVITY_RECOGNITION, android.Manifest.permission.BODY_SENSORS, android.Manifest.permission.HIGH_SAMPLING_RATE_SENSORS}, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_HEALTH = 256; // 0x100 + field @RequiresPermission(allOf={android.Manifest.permission.FOREGROUND_SERVICE_LOCATION}, anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_LOCATION = 8; // 0x8 field public static final int FOREGROUND_SERVICE_TYPE_MANIFEST = -1; // 0xffffffff - field public static final int FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK = 2; // 0x2 - field public static final int FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION = 32; // 0x20 - field public static final int FOREGROUND_SERVICE_TYPE_MICROPHONE = 128; // 0x80 - field public static final int FOREGROUND_SERVICE_TYPE_NONE = 0; // 0x0 - field public static final int FOREGROUND_SERVICE_TYPE_PHONE_CALL = 4; // 0x4 + field @RequiresPermission(value=android.Manifest.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK = 2; // 0x2 + field @RequiresPermission(value=android.Manifest.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION = 32; // 0x20 + field @RequiresPermission(allOf={android.Manifest.permission.FOREGROUND_SERVICE_MICROPHONE}, anyOf={android.Manifest.permission.CAPTURE_AUDIO_OUTPUT, android.Manifest.permission.RECORD_AUDIO}, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_MICROPHONE = 128; // 0x80 + field @Deprecated public static final int FOREGROUND_SERVICE_TYPE_NONE = 0; // 0x0 + field @RequiresPermission(allOf={android.Manifest.permission.FOREGROUND_SERVICE_PHONE_CALL}, anyOf={android.Manifest.permission.MANAGE_OWN_CALLS}, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_PHONE_CALL = 4; // 0x4 + field @RequiresPermission(value=android.Manifest.permission.FOREGROUND_SERVICE_REMOTE_MESSAGING, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_REMOTE_MESSAGING = 512; // 0x200 + field @RequiresPermission(value=android.Manifest.permission.FOREGROUND_SERVICE_SPECIAL_USE, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_SPECIAL_USE = 1073741824; // 0x40000000 + field @RequiresPermission(value=android.Manifest.permission.FOREGROUND_SERVICE_SYSTEM_EXEMPTED, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_SYSTEM_EXEMPTED = 1024; // 0x400 field public int flags; field public String permission; } diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index 0f4644c63b8d3..e9796dba670ce 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -1398,9 +1398,18 @@ public class AppOpsManager { */ public static final int OP_READ_WRITE_HEALTH_DATA = AppProtoEnums.APP_OP_READ_WRITE_HEALTH_DATA; + /** + * Use foreground service with the type + * {@link android.content.pm.ServiceInfo#FOREGROUND_SERVICE_TYPE_SPECIAL_USE}. + * + * @hide + */ + public static final int OP_FOREGROUND_SERVICE_SPECIAL_USE = + AppProtoEnums.APP_OP_FOREGROUND_SERVICE_SPECIAL_USE; + /** @hide */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public static final int _NUM_OP = 127; + public static final int _NUM_OP = 128; /** Access to coarse location information. */ public static final String OPSTR_COARSE_LOCATION = "android:coarse_location"; @@ -1930,6 +1939,14 @@ public class AppOpsManager { public static final String OPSTR_SYSTEM_EXEMPT_FROM_FORCED_APP_STANDBY = "android:system_exempt_from_forced_app_standby"; + /** + * Start a foreground service with the type "specialUse". + * + * @hide + */ + public static final String OPSTR_FOREGROUND_SERVICE_SPECIAL_USE = + "android:foreground_service_special_use"; + /** {@link #sAppOpsToNote} not initialized yet for this op */ private static final byte SHOULD_COLLECT_NOTE_OP_NOT_INITIALIZED = 0; /** Should not collect noting of this app-op in {@link #sAppOpsToNote} */ @@ -2026,6 +2043,7 @@ public class AppOpsManager { OP_TURN_SCREEN_ON, OP_RUN_LONG_JOBS, OP_READ_MEDIA_VISUAL_USER_SELECTED, + OP_FOREGROUND_SERVICE_SPECIAL_USE, }; static final AppOpInfo[] sAppOpInfos = new AppOpInfo[]{ @@ -2419,7 +2437,10 @@ public class AppOpsManager { OPSTR_SYSTEM_EXEMPT_FROM_FORCED_APP_STANDBY, "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() + "READ_WRITE_HEALTH_DATA").setDefaultMode(AppOpsManager.MODE_ALLOWED).build(), + new AppOpInfo.Builder(OP_FOREGROUND_SERVICE_SPECIAL_USE, + OPSTR_FOREGROUND_SERVICE_SPECIAL_USE, "FOREGROUND_SERVICE_SPECIAL_USE") + .setPermission(Manifest.permission.FOREGROUND_SERVICE_SPECIAL_USE).build(), }; // The number of longs needed to form a full bitmask of app ops diff --git a/core/java/android/app/Service.java b/core/java/android/app/Service.java index 7635138f6cdde..01e4b150fd7c6 100644 --- a/core/java/android/app/Service.java +++ b/core/java/android/app/Service.java @@ -21,6 +21,7 @@ import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MANIFEST; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresPermission; import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentCallbacks2; import android.content.ComponentName; @@ -726,10 +727,32 @@ public abstract class Service extends ContextWrapper implements ComponentCallbac * for more details. * * + *
+ *

Note: + * Beginning with SDK Version {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE}, + * apps targeting SDK Version {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} + * or higher are not allowed to start foreground services without specifying a valid + * foreground service type in the manifest attribute + * {@link android.R.attr#foregroundServiceType}. + * See + * + * Behavior changes: Apps targeting Android 14 + * + * for more details. + *

+ * * @throws ForegroundServiceStartNotAllowedException * If the app targeting API is * {@link android.os.Build.VERSION_CODES#S} or later, and the service is restricted from * becoming foreground service due to background restriction. + * @throws ForegroundServiceTypeNotAllowedException + * If the app targeting API is + * {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} or later, and the manifest attribute + * {@link android.R.attr#foregroundServiceType} is not set. + * @throws SecurityException If the app targeting API is + * {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} or later and doesn't have the + * permission to start the foreground service with the specified type in the manifest attribute + * {@link android.R.attr#foregroundServiceType}. * * @param id The identifier for this notification as per * {@link NotificationManager#notify(int, Notification) @@ -748,51 +771,77 @@ public abstract class Service extends ContextWrapper implements ComponentCallbac } } - /** - * An overloaded version of {@link #startForeground(int, Notification)} with additional - * foregroundServiceType parameter. - * - *

Apps built with SDK version {@link android.os.Build.VERSION_CODES#Q} or later can specify - * the foreground service types using attribute {@link android.R.attr#foregroundServiceType} in - * service element of manifest file. The value of attribute - * {@link android.R.attr#foregroundServiceType} can be multiple flags ORed together.

- * - *

The foregroundServiceType parameter must be a subset flags of what is specified in manifest - * attribute {@link android.R.attr#foregroundServiceType}, if not, an IllegalArgumentException is - * thrown. Specify foregroundServiceType parameter as - * {@link android.content.pm.ServiceInfo#FOREGROUND_SERVICE_TYPE_MANIFEST} to use all flags that - * is specified in manifest attribute foregroundServiceType.

- * - *
- *

Note: - * Beginning with SDK Version {@link android.os.Build.VERSION_CODES#S}, - * apps targeting SDK Version {@link android.os.Build.VERSION_CODES#S} - * or higher are not allowed to start foreground services from the background. - * See - * - * Behavior changes: Apps targeting Android 12 - * - * for more details. - *

- * - * @param id The identifier for this notification as per - * {@link NotificationManager#notify(int, Notification) - * NotificationManager.notify(int, Notification)}; must not be 0. - * @param notification The Notification to be displayed. - * @param foregroundServiceType must be a subset flags of manifest attribute - * {@link android.R.attr#foregroundServiceType} flags. - * - * @throws IllegalArgumentException if param foregroundServiceType is not subset of manifest - * attribute {@link android.R.attr#foregroundServiceType}. - * @throws ForegroundServiceStartNotAllowedException - * If the app targeting API is - * {@link android.os.Build.VERSION_CODES#S} or later, and the service is restricted from - * becoming foreground service due to background restriction. - * - * @see android.content.pm.ServiceInfo#FOREGROUND_SERVICE_TYPE_MANIFEST - */ + /** + * An overloaded version of {@link #startForeground(int, Notification)} with additional + * foregroundServiceType parameter. + * + *

Apps built with SDK version {@link android.os.Build.VERSION_CODES#Q} or later can specify + * the foreground service types using attribute {@link android.R.attr#foregroundServiceType} in + * service element of manifest file. The value of attribute + * {@link android.R.attr#foregroundServiceType} can be multiple flags ORed together.

+ * + *

The foregroundServiceType parameter must be a subset flags of what is specified in + * manifest attribute {@link android.R.attr#foregroundServiceType}, if not, an + * IllegalArgumentException is thrown. Specify foregroundServiceType parameter as + * {@link android.content.pm.ServiceInfo#FOREGROUND_SERVICE_TYPE_MANIFEST} to use all flags that + * is specified in manifest attribute foregroundServiceType.

+ * + *
+ *

Note: + * Beginning with SDK Version {@link android.os.Build.VERSION_CODES#S}, + * apps targeting SDK Version {@link android.os.Build.VERSION_CODES#S} + * or higher are not allowed to start foreground services from the background. + * See + * + * Behavior changes: Apps targeting Android 12 + * + * for more details. + *

+ * + *
+ *

Note: + * Beginning with SDK Version {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE}, + * apps targeting SDK Version {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} + * or higher are not allowed to start foreground services without specifying a valid + * foreground service type in the manifest attribute + * {@link android.R.attr#foregroundServiceType}, and the parameter {@code foregroundServiceType} + * here must not be the {@link ServiceInfo#FOREGROUND_SERVICE_TYPE_NONE}. + * See + * + * Behavior changes: Apps targeting Android 14 + * + * for more details. + *

+ * + * @param id The identifier for this notification as per + * {@link NotificationManager#notify(int, Notification) + * NotificationManager.notify(int, Notification)}; must not be 0. + * @param notification The Notification to be displayed. + * @param foregroundServiceType must be a subset flags of manifest attribute + * {@link android.R.attr#foregroundServiceType} flags; must not be + * {@link ServiceInfo#FOREGROUND_SERVICE_TYPE_NONE}. + * + * @throws IllegalArgumentException if param foregroundServiceType is not subset of manifest + * attribute {@link android.R.attr#foregroundServiceType}. + * @throws ForegroundServiceStartNotAllowedException + * If the app targeting API is + * {@link android.os.Build.VERSION_CODES#S} or later, and the service is restricted from + * becoming foreground service due to background restriction. + * @throws ForegroundServiceTypeNotAllowedException + * If the app targeting API is + * {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} or later, and the manifest attribute + * {@link android.R.attr#foregroundServiceType} is not set, or the param + * {@code foregroundServiceType} is {@link ServiceInfo#FOREGROUND_SERVICE_TYPE_NONE}. + * @throws SecurityException If the app targeting API is + * {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} or later and doesn't have the + * permission to start the foreground service with the specified type in + * {@code foregroundServiceType}. + * {@link android.R.attr#foregroundServiceType}. + * + * @see android.content.pm.ServiceInfo#FOREGROUND_SERVICE_TYPE_MANIFEST + */ public final void startForeground(int id, @NonNull Notification notification, - @ForegroundServiceType int foregroundServiceType) { + @RequiresPermission @ForegroundServiceType int foregroundServiceType) { try { mActivityManager.setServiceForeground( new ComponentName(this, mClassName), mToken, id, diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index aa86af92df87c..103b3f18a33e2 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -164,6 +164,21 @@ public abstract class PackageManager { public static final String PROPERTY_NO_APP_DATA_STORAGE = "android.internal.PROPERTY_NO_APP_DATA_STORAGE"; + /** + * <service> level {@link android.content.pm.PackageManager.Property} tag specifying + * the actual use case of the service if it's foreground service with the type + * {@link ServiceInfo#FOREGROUND_SERVICE_TYPE_SPECIAL_USE}. + * + *

+ * For example: + * <service> + * <property android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE" + * android:value="foo"/> + * </service> + */ + public static final String PROPERTY_SPECIAL_USE_FGS_SUBTYPE = + "android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE"; + /** * A property value set within the manifest. *

diff --git a/core/java/android/content/pm/ServiceInfo.java b/core/java/android/content/pm/ServiceInfo.java index 88d700432e8ae..ab20b6f7f9ccb 100644 --- a/core/java/android/content/pm/ServiceInfo.java +++ b/core/java/android/content/pm/ServiceInfo.java @@ -16,7 +16,9 @@ package android.content.pm; +import android.Manifest; import android.annotation.IntDef; +import android.annotation.RequiresPermission; import android.os.Parcel; import android.os.Parcelable; import android.util.Printer; @@ -100,7 +102,15 @@ public class ServiceInfo extends ComponentInfo /** * The default foreground service type if not been set in manifest file. + * + *

Apps targeting API level {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} and + * later should NOT use this type, + * calling {@link android.app.Service#startForeground(int, android.app.Notification, int)} with + * this type will get a {@link android.app.ForegroundServiceTypeNotAllowedException}.

+ * + * @deprecated Do not use. */ + @Deprecated public static final int FOREGROUND_SERVICE_TYPE_NONE = 0; /** @@ -108,14 +118,36 @@ public class ServiceInfo extends ComponentInfo * the {@link android.R.attr#foregroundServiceType} attribute. * Data(photo, file, account) upload/download, backup/restore, import/export, fetch, * transfer over network between device and cloud. + * + *

Apps targeting API level {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} and + * later should NOT use this type: + * calling {@link android.app.Service#startForeground(int, android.app.Notification, int)} with + * this type on devices running {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} is still + * allowed, but calling it with this type on devices running future platform releases may get a + * {@link android.app.ForegroundServiceTypeNotAllowedException}.

+ * + * @deprecated Use {@link android.app.job.JobInfo.Builder} data transfer APIs instead. */ + @RequiresPermission( + value = Manifest.permission.FOREGROUND_SERVICE_DATA_SYNC, + conditional = true + ) + @Deprecated public static final int FOREGROUND_SERVICE_TYPE_DATA_SYNC = 1 << 0; /** * Constant corresponding to mediaPlayback in * the {@link android.R.attr#foregroundServiceType} attribute. * Music, video, news or other media playback. + * + *

Starting foreground service with this type from apps targeting API level + * {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} and later, will require permission + * {@link android.Manifest.permission#FOREGROUND_SERVICE_MEDIA_PLAYBACK}. */ + @RequiresPermission( + value = Manifest.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK, + conditional = true + ) public static final int FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK = 1 << 1; /** @@ -123,28 +155,94 @@ public class ServiceInfo extends ComponentInfo * the {@link android.R.attr#foregroundServiceType} attribute. * Ongoing operations related to phone calls, video conferencing, * or similar interactive communication. + * + *

Starting foreground service with this type from apps targeting API level + * {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} and later, will require permission + * {@link android.Manifest.permission#FOREGROUND_SERVICE_PHONE_CALL} and + * {@link android.Manifest.permission#MANAGE_OWN_CALLS}. */ + @RequiresPermission( + allOf = { + Manifest.permission.FOREGROUND_SERVICE_PHONE_CALL, + }, + anyOf = { + Manifest.permission.MANAGE_OWN_CALLS, + }, + conditional = true + ) public static final int FOREGROUND_SERVICE_TYPE_PHONE_CALL = 1 << 2; /** * Constant corresponding to location in * the {@link android.R.attr#foregroundServiceType} attribute. * GPS, map, navigation location update. + * + *

Starting foreground service with this type from apps targeting API level + * {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} and later, will require permission + * {@link android.Manifest.permission#FOREGROUND_SERVICE_LOCATION} and one of the + * following permissions: + * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}, + * {@link android.Manifest.permission#ACCESS_FINE_LOCATION}. */ + @RequiresPermission( + allOf = { + Manifest.permission.FOREGROUND_SERVICE_LOCATION, + }, + anyOf = { + Manifest.permission.ACCESS_COARSE_LOCATION, + Manifest.permission.ACCESS_FINE_LOCATION, + }, + conditional = true + ) public static final int FOREGROUND_SERVICE_TYPE_LOCATION = 1 << 3; /** * Constant corresponding to connectedDevice in * the {@link android.R.attr#foregroundServiceType} attribute. * Auto, bluetooth, TV or other devices connection, monitoring and interaction. + * + *

Starting foreground service with this type from apps targeting API level + * {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} and later, will require permission + * {@link android.Manifest.permission#FOREGROUND_SERVICE_CONNECTED_DEVICE} and one of the + * following permissions: + * {@link android.Manifest.permission#BLUETOOTH_CONNECT}, + * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}, + * {@link android.Manifest.permission#CHANGE_WIFI_STATE}, + * {@link android.Manifest.permission#CHANGE_WIFI_MULTICAST_STATE}, + * {@link android.Manifest.permission#NFC}, + * {@link android.Manifest.permission#TRANSMIT_IR}, + * or has been granted the access to one of the attached USB devices/accessories. */ + @RequiresPermission( + allOf = { + Manifest.permission.FOREGROUND_SERVICE_CONNECTED_DEVICE, + }, + anyOf = { + Manifest.permission.BLUETOOTH_CONNECT, + Manifest.permission.CHANGE_NETWORK_STATE, + Manifest.permission.CHANGE_WIFI_STATE, + Manifest.permission.CHANGE_WIFI_MULTICAST_STATE, + Manifest.permission.NFC, + Manifest.permission.TRANSMIT_IR, + }, + conditional = true + ) public static final int FOREGROUND_SERVICE_TYPE_CONNECTED_DEVICE = 1 << 4; /** * Constant corresponding to {@code mediaProjection} in * the {@link android.R.attr#foregroundServiceType} attribute. * Managing a media projection session, e.g for screen recording or taking screenshots. + * + *

Starting foreground service with this type from apps targeting API level + * {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} and later, will require permission + * {@link android.Manifest.permission#FOREGROUND_SERVICE_MEDIA_PROJECTION}, and the user must + * have allowed the screen capture request from this app. */ + @RequiresPermission( + value = Manifest.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION, + conditional = true + ) public static final int FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION = 1 << 5; /** @@ -155,7 +253,21 @@ public class ServiceInfo extends ComponentInfo * above, a foreground service will not be able to access the camera if this type is not * specified in the manifest and in * {@link android.app.Service#startForeground(int, android.app.Notification, int)}. + * + *

Starting foreground service with this type from apps targeting API level + * {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} and later, will require permission + * {@link android.Manifest.permission#FOREGROUND_SERVICE_CAMERA} and + * {@link android.Manifest.permission#CAMERA}. */ + @RequiresPermission( + allOf = { + Manifest.permission.FOREGROUND_SERVICE_CAMERA, + }, + anyOf = { + Manifest.permission.CAMERA, + }, + conditional = true + ) public static final int FOREGROUND_SERVICE_TYPE_CAMERA = 1 << 6; /** @@ -166,17 +278,148 @@ public class ServiceInfo extends ComponentInfo * above, a foreground service will not be able to access the microphone if this type is not * specified in the manifest and in * {@link android.app.Service#startForeground(int, android.app.Notification, int)}. + * + *

Starting foreground service with this type from apps targeting API level + * {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} and later, will require permission + * {@link android.Manifest.permission#FOREGROUND_SERVICE_MICROPHONE} and one of the following + * permissions: + * {@link android.Manifest.permission#CAPTURE_AUDIO_OUTPUT}, + * {@link android.Manifest.permission#RECORD_AUDIO}. */ + @RequiresPermission( + allOf = { + Manifest.permission.FOREGROUND_SERVICE_MICROPHONE, + }, + anyOf = { + Manifest.permission.CAPTURE_AUDIO_OUTPUT, + Manifest.permission.RECORD_AUDIO, + }, + conditional = true + ) public static final int FOREGROUND_SERVICE_TYPE_MICROPHONE = 1 << 7; /** - * The number of foreground service types, this doesn't include - * the {@link #FOREGROUND_SERVICE_TYPE_MANIFEST} and {@link #FOREGROUND_SERVICE_TYPE_NONE} - * as they're not real service types. + * Constant corresponding to {@code health} in + * the {@link android.R.attr#foregroundServiceType} attribute. + * Health, wellness and fitness. + * + *

The caller app is required to have the permissions + * {@link android.Manifest.permission#FOREGROUND_SERVICE_HEALTH} and one of the following + * permissions: + * {@link android.Manifest.permission#ACTIVITY_RECOGNITION}, + * {@link android.Manifest.permission#BODY_SENSORS}, + * {@link android.Manifest.permission#HIGH_SAMPLING_RATE_SENSORS}. + */ + @RequiresPermission( + allOf = { + Manifest.permission.FOREGROUND_SERVICE_HEALTH, + }, + anyOf = { + Manifest.permission.ACTIVITY_RECOGNITION, + Manifest.permission.BODY_SENSORS, + Manifest.permission.HIGH_SAMPLING_RATE_SENSORS, + }, + conditional = true + ) + public static final int FOREGROUND_SERVICE_TYPE_HEALTH = 1 << 8; + + /** + * Constant corresponding to {@code remoteMessaging} in + * the {@link android.R.attr#foregroundServiceType} attribute. + * Messaging use cases which host local server to relay messages across devices. + */ + @RequiresPermission( + value = Manifest.permission.FOREGROUND_SERVICE_REMOTE_MESSAGING, + conditional = true + ) + public static final int FOREGROUND_SERVICE_TYPE_REMOTE_MESSAGING = 1 << 9; + + /** + * Constant corresponding to {@code systemExempted} in + * the {@link android.R.attr#foregroundServiceType} attribute. + * The system exmpted foreground service use cases. + * + *

Note, apps are allowed to use this type only in the following cases: + *

+ *

+ */ + @RequiresPermission( + value = Manifest.permission.FOREGROUND_SERVICE_SYSTEM_EXEMPTED, + conditional = true + ) + public static final int FOREGROUND_SERVICE_TYPE_SYSTEM_EXEMPTED = 1 << 10; + + /** + * Constant corresponding to {@code specialUse} in + * the {@link android.R.attr#foregroundServiceType} attribute. + * Use cases that can't be categorized into any other foreground service types, but also + * can't use {@link android.app.job.JobInfo.Builder} APIs. + * + *

The use of this foreground service type may be restricted. Additionally, apps must declare + * a service-level {@link PackageManager#PROPERTY_SPECIAL_USE_FGS_SUBTYPE <property>} in + * {@code AndroidManifest.xml} as a hint of what the exact use case here is. + * Here is an example: + *

+     *  <uses-permission
+     *      android:name="android.permissions.FOREGROUND_SERVICE_SPECIAL_USE"
+     *  />
+     *  <service
+     *      android:name=".MySpecialForegroundService"
+     *      android:foregroundServiceType="specialUse">
+     *      <property
+     *          android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE"
+     *          android:value="foo"
+     *      />
+     * </service>
+     * 
+ * + * In a future release of Android, if the above foreground service type {@code foo} is supported + * by the platform, to offer the backward compatibility, the app could specify + * the {@code android:maxSdkVersion} attribute in the <uses-permission> section, + * and also add the foreground service type {@code foo} into + * the {@code android:foregroundServiceType}, therefore the same app could be installed + * in both platforms. + *
+     *  <uses-permission
+     *      android:name="android.permissions.FOREGROUND_SERVICE_SPECIAL_USE"
+     *      android:maxSdkVersion="last_sdk_version_without_type_foo"
+     *  />
+     *  <service
+     *      android:name=".MySpecialForegroundService"
+     *      android:foregroundServiceType="specialUse|foo">
+     *      <property
+     *          android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE""
+     *          android:value="foo"
+     *      />
+     * </service>
+     * 
+ */ + @RequiresPermission( + value = Manifest.permission.FOREGROUND_SERVICE_SPECIAL_USE, + conditional = true + ) + public static final int FOREGROUND_SERVICE_TYPE_SPECIAL_USE = 1 << 30; + + /** + * The max index being used in the definition of foreground service types. * * @hide */ - public static final int NUM_OF_FOREGROUND_SERVICE_TYPES = 8; + public static final int FOREGROUND_SERVICE_TYPES_MAX_INDEX = 30; /** * A special value indicates to use all types set in manifest file. @@ -199,7 +442,11 @@ public class ServiceInfo extends ComponentInfo FOREGROUND_SERVICE_TYPE_CONNECTED_DEVICE, FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION, FOREGROUND_SERVICE_TYPE_CAMERA, - FOREGROUND_SERVICE_TYPE_MICROPHONE + FOREGROUND_SERVICE_TYPE_MICROPHONE, + FOREGROUND_SERVICE_TYPE_HEALTH, + FOREGROUND_SERVICE_TYPE_REMOTE_MESSAGING, + FOREGROUND_SERVICE_TYPE_SYSTEM_EXEMPTED, + FOREGROUND_SERVICE_TYPE_SPECIAL_USE }) @Retention(RetentionPolicy.SOURCE) public @interface ForegroundServiceType {} @@ -275,6 +522,14 @@ public class ServiceInfo extends ComponentInfo return "camera"; case FOREGROUND_SERVICE_TYPE_MICROPHONE: return "microphone"; + case FOREGROUND_SERVICE_TYPE_HEALTH: + return "health"; + case FOREGROUND_SERVICE_TYPE_REMOTE_MESSAGING: + return "remoteMessaging"; + case FOREGROUND_SERVICE_TYPE_SYSTEM_EXEMPTED: + return "systemExempted"; + case FOREGROUND_SERVICE_TYPE_SPECIAL_USE: + return "specialUse"; default: return "unknown"; } diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 7ada5483b92be..196ea59fe0f41 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -6184,6 +6184,116 @@ android:label="@string/permlab_foregroundService" android:protectionLevel="normal|instant" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + transfer over network between device and cloud. + +

For apps with targetSdkVersion + {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} and above, this type should NOT + be used: calling + {@link android.app.Service#startForeground(int, android.app.Notification, int)} with + this type on devices running {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} + is still allowed, but calling it with this type on devices running future platform + releases may get a {@link android.app.ForegroundServiceTypeNotAllowedException}. + --> - + + or similar interactive communication. + +

For apps with targetSdkVersion + {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} and above, starting a foreground + service with this type will require permission + {@link android.Manifest.permission#FOREGROUND_SERVICE_PHONE_CALL} and + {@link android.Manifest.permission#MANAGE_OWN_CALLS}. + --> - + - + + screenshots. + +

For apps with targetSdkVersion + {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} and above, starting a foreground + service with this type will require permission + {@link android.Manifest.permission#FOREGROUND_SERVICE_MEDIA_PROJECTION}, and the user + must have allowed the screen capture request from this app. + --> + + + + + + + + Allows the app to make use of foreground services. + + run foreground service with the type \"camera\" + + Allows the app to make use of foreground services with the type \"camera\" + + + run foreground service with the type \"connectedDevice\" + + Allows the app to make use of foreground services with the type \"connectedDevice\" + + + run foreground service with the type \"dataSync\" + + Allows the app to make use of foreground services with the type \"dataSync\" + + + run foreground service with the type \"location\" + + Allows the app to make use of foreground services with the type \"location\" + + + run foreground service with the type \"mediaPlayback\" + + Allows the app to make use of foreground services with the type \"mediaPlayback\" + + + run foreground service with the type \"mediaProjection\" + + Allows the app to make use of foreground services with the type \"mediaProjection\" + + + run foreground service with the type \"microphone\" + + Allows the app to make use of foreground services with the type \"microphone\" + + + run foreground service with the type \"phoneCall\" + + Allows the app to make use of foreground services with the type \"phoneCall\" + + + run foreground service with the type \"health\" + + Allows the app to make use of foreground services with the type \"health\" + + + run foreground service with the type \"remoteMessaging\" + + Allows the app to make use of foreground services with the type \"remoteMessaging\" + + + run foreground service with the type \"systemExempted\" + + Allows the app to make use of foreground services with the type \"systemExempted\" + + + run foreground service with the type \"specialUse\" + + Allows the app to make use of foreground services with the type \"specialUse\" + measure app storage space diff --git a/services/core/java/com/android/server/am/AppFGSTracker.java b/services/core/java/com/android/server/am/AppFGSTracker.java index 50515cd923d1f..1f98aba5bbd78 100644 --- a/services/core/java/com/android/server/am/AppFGSTracker.java +++ b/services/core/java/com/android/server/am/AppFGSTracker.java @@ -16,10 +16,10 @@ package com.android.server.am; +import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPES_MAX_INDEX; import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION; import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK; import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE; -import static android.content.pm.ServiceInfo.NUM_OF_FOREGROUND_SERVICE_TYPES; import static android.content.pm.ServiceInfo.foregroundServiceTypeToLabel; import static android.os.PowerExemptionManager.REASON_DENIED; @@ -645,7 +645,7 @@ final class AppFGSTracker extends BaseAppStateDurationsTracker(); mTracker = tracker;