diff options
author | Hui Yu <huiyu@google.com> | 2019-01-22 15:32:20 -0800 |
---|---|---|
committer | Hui Yu <huiyu@google.com> | 2019-01-31 11:50:18 -0800 |
commit | 2d4207f8c1d2e9e405617b9f991bfb9b9f7be64e (patch) | |
tree | 0b3d31647a260268f654742418e739bd82a9836f | |
parent | 28a7ebc77a408e83588c2730b877e910b8e41b59 (diff) |
Change foregroundServiceType from enum to flags
1. Now the value of manifest attribute foregroundServiceType can
be multiple flags ORed together.
2. Add a overloaded version of Service.startForeground() with an
additional parameter foregroundServiceType. The flags in parameter
foregroundServiceType must be a subset of flags specified in manifest
attribute foregroundServiceType, otherwise a IllegalArgumentException is
thrown.
3. Add a field foregroundServiceType in ServiceRecord, it is the types
that have been started on this foreground sevice.
Bug: 111453223
Test: atest frameworks/base/tests/FrameworkPerf
Change-Id: I7eb68f696e6bf75720fe9c9388a6c23a529677f7
-rw-r--r-- | api/current.txt | 15 | ||||
-rw-r--r-- | core/java/android/app/IActivityManager.aidl | 2 | ||||
-rw-r--r-- | core/java/android/app/Service.java | 53 | ||||
-rw-r--r-- | core/java/android/content/pm/PackageParser.java | 2 | ||||
-rw-r--r-- | core/java/android/content/pm/ServiceInfo.java | 46 | ||||
-rw-r--r-- | core/res/res/values/attrs_manifest.xml | 20 | ||||
-rw-r--r-- | services/core/java/com/android/server/am/ActiveServices.java | 33 | ||||
-rw-r--r-- | services/core/java/com/android/server/am/ActivityManagerService.java | 5 | ||||
-rw-r--r-- | services/core/java/com/android/server/am/ServiceRecord.java | 17 | ||||
-rw-r--r-- | tests/FrameworkPerf/AndroidManifest.xml | 3 |
10 files changed, 118 insertions, 78 deletions
diff --git a/api/current.txt b/api/current.txt index 3b6cfe3a3cee..fe037736bf0d 100644 --- a/api/current.txt +++ b/api/current.txt @@ -6176,6 +6176,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 stopForeground(boolean); method public final void stopForeground(int); method public final void stopSelf(); @@ -11919,13 +11920,13 @@ 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_DEVICE_COMPANION = 5; // 0x5 - field public static final int FOREGROUND_SERVICE_TYPE_LOCATION = 4; // 0x4 - field public static final int FOREGROUND_SERVICE_TYPE_MEDIA_PLAY = 2; // 0x2 - field public static final int FOREGROUND_SERVICE_TYPE_ONGOING_PROCESS = 6; // 0x6 - field public static final int FOREGROUND_SERVICE_TYPE_PHONE_CALL = 3; // 0x3 - field public static final int FOREGROUND_SERVICE_TYPE_SYNC = 1; // 0x1 - field public static final int FOREGROUND_SERVICE_TYPE_UNSPECIFIED = 0; // 0x0 + 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 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_NONE = 0; // 0x0 + field public static final int FOREGROUND_SERVICE_TYPE_PHONE_CALL = 4; // 0x4 field public int flags; field public String permission; } diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl index 412d7f45986c..eea054333141 100644 --- a/core/java/android/app/IActivityManager.aidl +++ b/core/java/android/app/IActivityManager.aidl @@ -203,7 +203,7 @@ interface IActivityManager { void unbindFinished(in IBinder token, in Intent service, boolean doRebind); void setProcessImportant(in IBinder token, int pid, boolean isForeground, String reason); void setServiceForeground(in ComponentName className, in IBinder token, - int id, in Notification notification, int flags); + int id, in Notification notification, int flags, int foregroundServiceType); boolean moveActivityTaskToBack(in IBinder token, boolean nonRoot); void getMemoryInfo(out ActivityManager.MemoryInfo outInfo); List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState(); diff --git a/core/java/android/app/Service.java b/core/java/android/app/Service.java index 5fa8526b5a24..87bf5ed7db65 100644 --- a/core/java/android/app/Service.java +++ b/core/java/android/app/Service.java @@ -16,7 +16,10 @@ package android.app; +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.UnsupportedAppUsage; import android.content.ComponentCallbacks2; @@ -685,12 +688,10 @@ public abstract class Service extends ContextWrapper implements ComponentCallbac * the permission {@link android.Manifest.permission#FOREGROUND_SERVICE} in order to use * this API.</p> * - * <p>To use this API, apps targeting API {@link android.os.Build.VERSION_CODES#Q} or later must - * specify the foreground service type using attribute - * {@link android.R.attr#foregroundServiceType} in service element of manifest file, otherwise - * a SecurityException is thrown when this API is called. Apps targeting API older than - * {@link android.os.Build.VERSION_CODES#Q} do not need to specify the foreground service type - * </p> + * <p>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.</p> * * @param id The identifier for this notification as per * {@link NotificationManager#notify(int, Notification) @@ -703,7 +704,42 @@ public abstract class Service extends ContextWrapper implements ComponentCallbac try { mActivityManager.setServiceForeground( new ComponentName(this, mClassName), mToken, id, - notification, 0); + notification, 0, FOREGROUND_SERVICE_TYPE_MANIFEST); + } catch (RemoteException ex) { + } + } + + /** + * An overloaded version of {@link #startForeground(int, Notification)} with additional + * foregroundServiceType parameter. + * + * <p>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.</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 + * {@link android.content.pm.ServiceInfo#FOREGROUND_SERVICE_TYPE_MANIFEST} to use all flags that + * is specified in manifest attribute foregroundServiceType.</p> + * + * @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}. + * @see {@link android.content.pm.ServiceInfo} for the set of FOREGROUND_SERVICE_TYPE flags. + */ + public final void startForeground(int id, @NonNull Notification notification, + int foregroundServiceType) { + try { + mActivityManager.setServiceForeground( + new ComponentName(this, mClassName), mToken, id, + notification, 0, foregroundServiceType); } catch (RemoteException ex) { } } @@ -731,7 +767,8 @@ public abstract class Service extends ContextWrapper implements ComponentCallbac public final void stopForeground(@StopForegroundFlags int flags) { try { mActivityManager.setServiceForeground( - new ComponentName(this, mClassName), mToken, 0, null, flags); + new ComponentName(this, mClassName), mToken, 0, null, + flags, 0); } catch (RemoteException ex) { } } diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index eb59cfc0fc4b..2c2760681219 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -5573,7 +5573,7 @@ public class PackageParser { s.info.mForegroundServiceType = sa.getInt( com.android.internal.R.styleable.AndroidManifestService_foregroundServiceType, - ServiceInfo.FOREGROUND_SERVICE_TYPE_UNSPECIFIED); + ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE); s.info.flags = 0; if (sa.getBoolean( diff --git a/core/java/android/content/pm/ServiceInfo.java b/core/java/android/content/pm/ServiceInfo.java index 8300c0c8d472..60475de351cf 100644 --- a/core/java/android/content/pm/ServiceInfo.java +++ b/core/java/android/content/pm/ServiceInfo.java @@ -101,77 +101,73 @@ public class ServiceInfo extends ComponentInfo /** * The default foreground service type if not been set in manifest file. */ - public static final int FOREGROUND_SERVICE_TYPE_UNSPECIFIED = 0; + public static final int FOREGROUND_SERVICE_TYPE_NONE = 0; /** - * Constant corresponding to <code>sync</code> in + * Constant corresponding to <code>dataSync</code> in * 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. */ - public static final int FOREGROUND_SERVICE_TYPE_SYNC = 1; + public static final int FOREGROUND_SERVICE_TYPE_DATA_SYNC = 1 << 0; /** - * Constant corresponding to <code>mediaPlay</code> in + * Constant corresponding to <code>mediaPlayback</code> in * the {@link android.R.attr#foregroundServiceType} attribute. - * Music, video, news or other media play. + * Music, video, news or other media playback. */ - public static final int FOREGROUND_SERVICE_TYPE_MEDIA_PLAY = 2; + public static final int FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK = 1 << 1; /** * Constant corresponding to <code>phoneCall</code> in * the {@link android.R.attr#foregroundServiceType} attribute. * Ongoing phone call or video conference. */ - public static final int FOREGROUND_SERVICE_TYPE_PHONE_CALL = 3; + public static final int FOREGROUND_SERVICE_TYPE_PHONE_CALL = 1 << 2; /** * Constant corresponding to <code>location</code> in * the {@link android.R.attr#foregroundServiceType} attribute. * GPS, map, navigation location update. */ - public static final int FOREGROUND_SERVICE_TYPE_LOCATION = 4; + public static final int FOREGROUND_SERVICE_TYPE_LOCATION = 1 << 3; /** - * Constant corresponding to <code>deviceCompanion</code> in + * Constant corresponding to <code>connectedDevice</code> in * the {@link android.R.attr#foregroundServiceType} attribute. * Auto, bluetooth, TV or other devices connection, monitoring and interaction. */ - public static final int FOREGROUND_SERVICE_TYPE_DEVICE_COMPANION = 5; + public static final int FOREGROUND_SERVICE_TYPE_CONNECTED_DEVICE = 1 << 4; /** - * Constant corresponding to <code>ongoingProcess</code> in - * the {@link android.R.attr#foregroundServiceType} attribute. - * Process that should not be interrupted, including installation, setup, photo - * compression etc. + * A special value indicates to use all types set in manifest file. */ - public static final int FOREGROUND_SERVICE_TYPE_ONGOING_PROCESS = 6; + public static final int FOREGROUND_SERVICE_TYPE_MANIFEST = -1; /** - * The enumeration of values for foreground service type. + * The set of flags for foreground service type. * The foreground service type is set in {@link android.R.attr#foregroundServiceType} * attribute. * @hide */ - @IntDef(flag = false, prefix = { "FOREGROUND_SERVICE_TYPE_" }, value = { - FOREGROUND_SERVICE_TYPE_UNSPECIFIED, - FOREGROUND_SERVICE_TYPE_SYNC, - FOREGROUND_SERVICE_TYPE_MEDIA_PLAY, + @IntDef(flag = true, prefix = { "FOREGROUND_SERVICE_TYPE_" }, value = { + FOREGROUND_SERVICE_TYPE_NONE, + FOREGROUND_SERVICE_TYPE_DATA_SYNC, + FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK, FOREGROUND_SERVICE_TYPE_PHONE_CALL, FOREGROUND_SERVICE_TYPE_LOCATION, - FOREGROUND_SERVICE_TYPE_DEVICE_COMPANION, - FOREGROUND_SERVICE_TYPE_ONGOING_PROCESS + FOREGROUND_SERVICE_TYPE_CONNECTED_DEVICE, }) @Retention(RetentionPolicy.SOURCE) public @interface ForegroundServiceType {} /** * The type of foreground service, set in - * {@link android.R.attr#foregroundServiceType} attribute, one value in + * {@link android.R.attr#foregroundServiceType} attribute by ORing flags in * {@link ForegroundServiceType} * @hide */ - public @ForegroundServiceType int mForegroundServiceType = FOREGROUND_SERVICE_TYPE_UNSPECIFIED; + public @ForegroundServiceType int mForegroundServiceType = FOREGROUND_SERVICE_TYPE_NONE; public ServiceInfo() { } @@ -217,6 +213,7 @@ public class ServiceInfo extends ComponentInfo super.writeToParcel(dest, parcelableFlags); dest.writeString(permission); dest.writeInt(flags); + dest.writeInt(mForegroundServiceType); } public static final Creator<ServiceInfo> CREATOR = @@ -233,5 +230,6 @@ public class ServiceInfo extends ComponentInfo super(source); permission = source.readString(); flags = source.readInt(); + mForegroundServiceType = source.readInt(); } } diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index 0abe456c82f9..f223c3d9b4a8 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -1436,26 +1436,20 @@ <attr name="usesNonSdkApi" format="boolean" /> - <!-- Specify the type of foreground service. Apps targeting API - {@link android.os.Build.VERSION_CODES#Q} or later must specify foreground service type, - otherwise a SecurityException is thrown when - {@link android.app.Service#startForeground(int, Notification)} on this service is called. - --> + <!-- Specify the type of foreground service. Multiple types can be specified by ORing the flags + together. --> <attr name="foregroundServiceType"> <!-- Data (photo, file, account) upload/download, backup/restore, import/export, fetch, transfer over network between device and cloud. --> - <enum name="sync" value="1" /> + <flag name="dataSync" value="0x01" /> <!-- Music, video, news or other media play. --> - <enum name="mediaPlay" value="2" /> + <flag name="mediaPlayback" value="0x02" /> <!-- Ongoing phone call or video conference. --> - <enum name="phoneCall" value="3" /> + <flag name="phoneCall" value="0x04" /> <!-- GPS, map, navigation location update. --> - <enum name="location" value="4" /> + <flag name="location" value="0x08" /> <!-- Auto, bluetooth, TV or other devices connection, monitoring and interaction. --> - <enum name="deviceCompanion" value="5" /> - <!-- Process that should not be interrupted, including installation, setup, photo - compression etc. --> - <enum name="ongoingProcess" value="6" /> + <flag name="connectedDevice" value="0x10" /> </attr> diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index d95604e91ca3..2f1f91e1734a 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -17,6 +17,7 @@ package com.android.server.am; import static android.content.pm.PackageManager.PERMISSION_GRANTED; +import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MANIFEST; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BACKGROUND_CHECK; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_FOREGROUND_SERVICE; @@ -218,7 +219,7 @@ public final class ActiveServices { if (DEBUG_FOREGROUND_SERVICE) { Slog.i(TAG, " Stopping fg for service " + r); } - setServiceForegroundInnerLocked(r, 0, null, 0); + setServiceForegroundInnerLocked(r, 0, null, 0, 0); } } } @@ -914,13 +915,13 @@ public final class ActiveServices { } public void setServiceForegroundLocked(ComponentName className, IBinder token, - int id, Notification notification, int flags) { + int id, Notification notification, int flags, int foregroundServiceType) { final int userId = UserHandle.getCallingUserId(); final long origId = Binder.clearCallingIdentity(); try { ServiceRecord r = findServiceLocked(className, token, userId); if (r != null) { - setServiceForegroundInnerLocked(r, id, notification, flags); + setServiceForegroundInnerLocked(r, id, notification, flags, foregroundServiceType); } } finally { Binder.restoreCallingIdentity(origId); @@ -1211,7 +1212,7 @@ public final class ActiveServices { * @param id Notification ID. Zero === exit foreground state for the given service. */ private void setServiceForegroundInnerLocked(final ServiceRecord r, int id, - Notification notification, int flags) { + Notification notification, int flags, int foregroundServiceType) { if (id != 0) { if (notification == null) { throw new IllegalArgumentException("null notification"); @@ -1244,13 +1245,20 @@ public final class ActiveServices { android.Manifest.permission.FOREGROUND_SERVICE, r.app.pid, r.appInfo.uid, "startForeground"); } - if (r.appInfo.targetSdkVersion >= Build.VERSION_CODES.Q) { - if (r.serviceInfo.getForegroundServiceType() - == ServiceInfo.FOREGROUND_SERVICE_TYPE_UNSPECIFIED) { - // STOPSHIP(b/120611119): replace log message with SecurityException. - Slog.w(TAG, "missing foregroundServiceType attribute in " - + "service element of manifest file"); - } + + int manifestType = r.serviceInfo.getForegroundServiceType(); + // If passed in foreground service type is FOREGROUND_SERVICE_TYPE_MANIFEST, + // consider it is the same as manifest foreground service type. + if (foregroundServiceType == FOREGROUND_SERVICE_TYPE_MANIFEST) { + foregroundServiceType = manifestType; + } + // Check the passed in foreground service type flags is a subset of manifest + // foreground service type flags. + if ((foregroundServiceType & manifestType) != foregroundServiceType) { + // STOPSHIP(b/120611119): replace log message with IllegalArgumentException. + Slog.w(TAG, "foregroundServiceType must be a subset of " + + "foregroundServiceType attribute in " + + "service element of manifest file"); } } boolean alreadyStartedOp = false; @@ -1307,6 +1315,7 @@ public final class ActiveServices { } notification.flags |= Notification.FLAG_FOREGROUND_SERVICE; r.foregroundNoti = notification; + r.foregroundServiceType = foregroundServiceType; if (!r.isForeground) { final ServiceMap smap = getServiceMapLocked(r.userId); if (smap != null) { @@ -1443,7 +1452,7 @@ public final class ActiveServices { ServiceRecord sr = proc.services.valueAt(i); if (sr.isForeground || sr.fgRequired) { anyForeground = true; - fgServiceTypes |= sr.serviceInfo.mForegroundServiceType; + fgServiceTypes |= sr.foregroundServiceType; break; } } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index bec738666cbb..e50381292661 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -13529,9 +13529,10 @@ public class ActivityManagerService extends IActivityManager.Stub @Override public void setServiceForeground(ComponentName className, IBinder token, - int id, Notification notification, int flags) { + int id, Notification notification, int flags, int foregroundServiceType) { synchronized(this) { - mServices.setServiceForegroundLocked(className, token, id, notification, flags); + mServices.setServiceForegroundLocked(className, token, id, notification, flags, + foregroundServiceType); } } diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java index da5ce1c45610..abc1066af046 100644 --- a/services/core/java/com/android/server/am/ServiceRecord.java +++ b/services/core/java/com/android/server/am/ServiceRecord.java @@ -16,10 +16,8 @@ package com.android.server.am; -import com.android.internal.app.procstats.ServiceState; -import com.android.internal.os.BatteryStatsImpl; -import com.android.server.LocalServices; -import com.android.server.notification.NotificationManagerInternal; +import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; +import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; import android.app.INotificationManager; import android.app.Notification; @@ -44,6 +42,11 @@ import android.util.Slog; import android.util.TimeUtils; import android.util.proto.ProtoOutputStream; import android.util.proto.ProtoUtils; + +import com.android.internal.app.procstats.ServiceState; +import com.android.internal.os.BatteryStatsImpl; +import com.android.server.LocalServices; +import com.android.server.notification.NotificationManagerInternal; import com.android.server.uri.NeededUriGrants; import com.android.server.uri.UriPermissionOwner; @@ -52,9 +55,6 @@ import java.util.ArrayList; import java.util.List; import java.util.Objects; -import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; -import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; - /** * A running application service. */ @@ -103,6 +103,7 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN boolean isForeground; // is service currently in foreground mode? int foregroundId; // Notification ID of last foreground req. Notification foregroundNoti; // Notification record of foreground state. + int foregroundServiceType; // foreground service types. long lastActivity; // last time there was some activity on the service. long startingBgTimeout; // time at which we scheduled this for a delayed start. boolean startRequested; // someone explicitly called start? @@ -722,7 +723,7 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN // If it gave us a garbage notification, it doesn't // get to be foreground. ams.setServiceForeground(instanceName, ServiceRecord.this, - 0, null, 0); + 0, null, 0, 0); ams.crashApplication(appUid, appPid, localPackageName, -1, "Bad notification for startForeground: " + e); } diff --git a/tests/FrameworkPerf/AndroidManifest.xml b/tests/FrameworkPerf/AndroidManifest.xml index ca25386a992c..4fd2043ce938 100644 --- a/tests/FrameworkPerf/AndroidManifest.xml +++ b/tests/FrameworkPerf/AndroidManifest.xml @@ -14,7 +14,7 @@ </intent-filter> </activity> <service android:name="SchedulerService" - android:foregroundServiceType="sync"> + android:foregroundServiceType="dataSync|mediaPlayback|phoneCall|location|connectedDevice"> </service> <service android:name="TestService" android:process=":test"> </service> @@ -23,7 +23,6 @@ <receiver android:name="Receiver" android:exported="true"> </receiver> </application> - <instrumentation android:name="android.test.InstrumentationTestRunner" android:targetPackage="com.android.frameworkperf" android:label="Framework Perf Runner" |