Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8e4ffc82 authored by Jing Ji's avatar Jing Ji
Browse files

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
parent 69027e0b
Loading
Loading
Loading
Loading
+27 −10
Original line number Diff line number Diff line
@@ -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;
  }
+23 −2
Original line number Diff line number Diff line
@@ -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
+93 −44
Original line number Diff line number Diff line
@@ -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.
     * </div>
     *
     * <div class="caution">
     * <p><strong>Note:</strong>
     * 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
     * <a href="{@docRoot}/about/versions/14/behavior-changes-14">
     * Behavior changes: Apps targeting Android 14
     * </a>
     * for more details.
     * </div>
     *
     * @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)
@@ -757,9 +780,9 @@ public abstract class Service extends ContextWrapper implements ComponentCallbac
     * service element of manifest file. The value of attribute
     * {@link android.R.attr#foregroundServiceType} can be multiple flags ORed together.</p>
     *
   * <p>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
     * <p>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.</p>
     *
@@ -775,12 +798,28 @@ public abstract class Service extends ContextWrapper implements ComponentCallbac
     * for more details.
     * </div>
     *
     * <div class="caution">
     * <p><strong>Note:</strong>
     * 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
     * <a href="{@docRoot}/about/versions/14/behavior-changes-14">
     * Behavior changes: Apps targeting Android 14
     * </a>
     * for more details.
     * </div>
     *
     * @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.
     * {@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}.
@@ -788,11 +827,21 @@ public abstract class Service extends ContextWrapper implements ComponentCallbac
     * 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,
+15 −0
Original line number Diff line number Diff line
@@ -164,6 +164,21 @@ public abstract class PackageManager {
    public static final String PROPERTY_NO_APP_DATA_STORAGE =
            "android.internal.PROPERTY_NO_APP_DATA_STORAGE";

    /**
     * &lt;service&gt; 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}.
     *
     * <p>
     * For example:
     * &lt;service&gt;
     *   &lt;property android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE"
     *     android:value="foo"/&gt;
     * &lt;/service&gt;
     */
    public static final String PROPERTY_SPECIAL_USE_FGS_SUBTYPE =
            "android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE";

    /**
     * A property value set within the manifest.
     * <p>
+260 −5

File changed.

Preview size limit exceeded, changes collapsed.

Loading