summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/app/ContextImpl.java13
-rw-r--r--core/java/android/app/IActivityManager.aidl3
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java11
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java36
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerShellCommand.java2
-rw-r--r--services/core/java/com/android/server/am/ServiceRecord.java6
6 files changed, 58 insertions, 13 deletions
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 505b498e3cf6..d0fd92294979 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -187,6 +187,16 @@ class ContextImpl extends Context {
private static final String XATTR_INODE_CODE_CACHE = "user.inode_code_cache";
/**
+ * Special intent extra that critical system apps can use to hide the notification for a
+ * foreground service. This extra should be placed in the intent passed into {@link
+ * #startForegroundService(Intent)}.
+ *
+ * @hide
+ */
+ private static final String EXTRA_HIDDEN_FOREGROUND_SERVICE =
+ "android.intent.extra.HIDDEN_FOREGROUND_SERVICE";
+
+ /**
* Map from package name, to preference name, to cached preferences.
*/
@GuardedBy("ContextImpl.class")
@@ -1697,9 +1707,12 @@ class ContextImpl extends Context {
try {
validateServiceIntent(service);
service.prepareToLeaveProcess(this);
+ final boolean hideForegroundNotification = requireForeground
+ && service.getBooleanExtra(EXTRA_HIDDEN_FOREGROUND_SERVICE, false);
ComponentName cn = ActivityManager.getService().startService(
mMainThread.getApplicationThread(), service,
service.resolveTypeIfNeeded(getContentResolver()), requireForeground,
+ hideForegroundNotification,
getOpPackageName(), getAttributionTag(), user.getIdentifier());
if (cn != null) {
if (cn.getPackageName().equals("!")) {
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 945957738f8e..2abe9cf9fce5 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -155,7 +155,8 @@ interface IActivityManager {
boolean refContentProvider(in IBinder connection, int stableDelta, int unstableDelta);
PendingIntent getRunningServiceControlPanel(in ComponentName service);
ComponentName startService(in IApplicationThread caller, in Intent service,
- in String resolvedType, boolean requireForeground, in String callingPackage,
+ in String resolvedType, boolean requireForeground,
+ boolean hideForegroundNotification, in String callingPackage,
in String callingFeatureId, int userId);
@UnsupportedAppUsage
int stopService(in IApplicationThread caller, in Intent service,
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 3f867f656c24..7d88a8a4ec01 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -453,16 +453,16 @@ public final class ActiveServices {
}
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
- int callingPid, int callingUid, boolean fgRequired, String callingPackage,
- @Nullable String callingFeatureId, final int userId)
+ int callingPid, int callingUid, boolean fgRequired, boolean hideFgNotification,
+ String callingPackage, @Nullable String callingFeatureId, final int userId)
throws TransactionTooLargeException {
return startServiceLocked(caller, service, resolvedType, callingPid, callingUid, fgRequired,
- callingPackage, callingFeatureId, userId, false);
+ hideFgNotification, callingPackage, callingFeatureId, userId, false);
}
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
- int callingPid, int callingUid, boolean fgRequired, String callingPackage,
- @Nullable String callingFeatureId, final int userId,
+ int callingPid, int callingUid, boolean fgRequired, boolean hideFgNotification,
+ String callingPackage, @Nullable String callingFeatureId, final int userId,
boolean allowBackgroundActivityStarts) throws TransactionTooLargeException {
if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "startService: " + service
+ " type=" + resolvedType + " args=" + service.getExtras());
@@ -609,6 +609,7 @@ public final class ActiveServices {
r.startRequested = true;
r.delayedStop = false;
r.fgRequired = fgRequired;
+ r.hideFgNotification = hideFgNotification;
r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
service, neededGrants, callingUid));
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 82abb988cb2c..44e3bbf91565 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1438,6 +1438,10 @@ public class ActivityManagerService extends IActivityManager.Stub
final Injector mInjector;
+ /** The package verifier app. */
+ private String mPackageVerifier;
+ private int mPackageVerifierUid = UserHandle.USER_NULL;
+
static final class ProcessChangeItem {
static final int CHANGE_ACTIVITIES = 1<<0;
static final int CHANGE_FOREGROUND_SERVICES = 1<<1;
@@ -2362,6 +2366,18 @@ public class ActivityManagerService extends IActivityManager.Stub
if (phase == PHASE_SYSTEM_SERVICES_READY) {
mService.mBatteryStatsService.systemServicesReady();
mService.mServices.systemServicesReady();
+ mService.mPackageVerifier = ArrayUtils.firstOrNull(
+ LocalServices.getService(PackageManagerInternal.class).getKnownPackageNames(
+ PackageManagerInternal.PACKAGE_VERIFIER, UserHandle.USER_SYSTEM));
+ if (mService.mPackageVerifier != null) {
+ try {
+ mService.mPackageVerifierUid =
+ getContext().getPackageManager().getPackageUid(
+ mService.mPackageVerifier, UserHandle.USER_SYSTEM);
+ } catch (NameNotFoundException e) {
+ Slog.wtf(TAG, "Package manager couldn't get package verifier uid", e);
+ }
+ }
} else if (phase == PHASE_ACTIVITY_MANAGER_READY) {
mService.startBroadcastObservers();
} else if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
@@ -15007,8 +15023,8 @@ public class ActivityManagerService extends IActivityManager.Stub
@Override
public ComponentName startService(IApplicationThread caller, Intent service,
- String resolvedType, boolean requireForeground, String callingPackage,
- String callingFeatureId, int userId)
+ String resolvedType, boolean requireForeground, boolean hideForegroundNotification,
+ String callingPackage, String callingFeatureId, int userId)
throws TransactionTooLargeException {
enforceNotIsolatedCaller("startService");
// Refuse possible leaked file descriptors
@@ -15020,17 +15036,27 @@ public class ActivityManagerService extends IActivityManager.Stub
throw new IllegalArgumentException("callingPackage cannot be null");
}
+ final int callingUid = Binder.getCallingUid();
+ if (requireForeground && hideForegroundNotification) {
+ if (!UserHandle.isSameApp(callingUid, mPackageVerifierUid)
+ || !callingPackage.equals(mPackageVerifier)) {
+ throw new IllegalArgumentException(
+ "Only the package verifier can hide its foreground service notification");
+ }
+ Slog.i(TAG, "Foreground service notification hiding requested by " + callingPackage);
+ }
+
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE,
"*** startService: " + service + " type=" + resolvedType + " fg=" + requireForeground);
synchronized(this) {
final int callingPid = Binder.getCallingPid();
- final int callingUid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
ComponentName res;
try {
res = mServices.startServiceLocked(caller, service,
resolvedType, callingPid, callingUid,
- requireForeground, callingPackage, callingFeatureId, userId);
+ requireForeground, hideForegroundNotification,
+ callingPackage, callingFeatureId, userId);
} finally {
Binder.restoreCallingIdentity(origId);
}
@@ -19470,7 +19496,7 @@ public class ActivityManagerService extends IActivityManager.Stub
ComponentName res;
try {
res = mServices.startServiceLocked(null, service,
- resolvedType, -1, uid, fgRequired, callingPackage,
+ resolvedType, -1, uid, fgRequired, false, callingPackage,
callingFeatureId, userId, allowBackgroundActivityStarts);
} finally {
Binder.restoreCallingIdentity(origId);
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 149e3baa90e7..a512cca7bac4 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -654,7 +654,7 @@ final class ActivityManagerShellCommand extends ShellCommand {
pw.println("Starting service: " + intent);
pw.flush();
ComponentName cn = mInterface.startService(null, intent, intent.getType(),
- asForeground, SHELL_PACKAGE_NAME, null, mUserId);
+ asForeground, false, SHELL_PACKAGE_NAME, null, mUserId);
if (cn == null) {
err.println("Error: Not found; no service started.");
return -1;
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 828ac71eccfe..19d5a3125f3a 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -104,6 +104,7 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
boolean whitelistManager; // any bindings to this service have BIND_ALLOW_WHITELIST_MANAGEMENT?
boolean delayed; // are we waiting to start this service in the background?
boolean fgRequired; // is the service required to go foreground after starting?
+ boolean hideFgNotification; // Hide the fg service notification
boolean fgWaiting; // is a timeout for going foreground already scheduled?
boolean isForeground; // is service currently in foreground mode?
int foregroundId; // Notification ID of last foreground req.
@@ -823,6 +824,9 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
}
public void postNotification() {
+ if (hideFgNotification) {
+ return;
+ }
final int appUid = appInfo.uid;
final int appPid = app.pid;
if (foregroundId != 0 && foregroundNoti != null) {
@@ -915,7 +919,7 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
}
if (localForegroundNoti.getSmallIcon() == null) {
// Notifications whose icon is 0 are defined to not show
- // a notification, silently ignoring it. We don't want to
+ // a notification. We don't want to
// just ignore it, we want to prevent the service from
// being foreground.
throw new RuntimeException("invalid service notification: "