diff options
4 files changed, 113 insertions, 0 deletions
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java index f80121d0c9b6..d9f8d33f0545 100644 --- a/core/java/android/app/ActivityManagerInternal.java +++ b/core/java/android/app/ActivityManagerInternal.java @@ -1150,6 +1150,20 @@ public abstract class ActivityManagerInternal { public abstract void stopForegroundServiceDelegate(@NonNull ServiceConnection connection); /** + * Notifies that a media foreground service associated with a media session has + * transitioned to a "user-disengaged" state. + * Upon receiving this notification, service may be removed from the foreground state. It + * should only be called by {@link com.android.server.media.MediaSessionService} + * + * @param packageName The package name of the app running the media foreground service. + * @param userId The user ID associated with the foreground service. + * @param notificationId The ID of the media notification associated with the foreground + * service. + */ + public abstract void notifyInactiveMediaForegroundService(@NonNull String packageName, + @UserIdInt int userId, int notificationId); + + /** * Same as {@link android.app.IActivityManager#startProfile(int userId)}, but it would succeed * even if the profile is disabled - it should only be called by * {@link com.android.server.devicepolicy.DevicePolicyManagerService} when starting a profile diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index 3f540ad43da1..ab3ab159ba12 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -115,6 +115,7 @@ import static com.android.internal.util.FrameworkStatsLog.SERVICE_REQUEST_EVENT_ import static com.android.internal.util.FrameworkStatsLog.SERVICE_REQUEST_EVENT_REPORTED__PROC_START_TYPE__PROCESS_START_TYPE_WARM; import static com.android.internal.util.FrameworkStatsLog.SERVICE_REQUEST_EVENT_REPORTED__REQUEST_TYPE__BIND; import static com.android.internal.util.FrameworkStatsLog.SERVICE_REQUEST_EVENT_REPORTED__REQUEST_TYPE__START; +import static com.android.media.flags.Flags.enableNotifyingActivityManagerWithMediaSessionStatusChange; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BACKGROUND_CHECK; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_FOREGROUND_SERVICE; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_MU; @@ -9319,6 +9320,46 @@ public final class ActiveServices { } } + /** + * Handles notifications from MediaSessionService about inactive media foreground services. + * This method evaluates the provided information and determines whether to stop the + * corresponding foreground service. + * + * @param packageName The package name of the app running the foreground service. + * @param userId The user ID associated with the foreground service. + * @param notificationId The ID of the media notification associated with the foreground + * service. + */ + void notifyInactiveMediaForegroundServiceLocked(@NonNull String packageName, + @UserIdInt int userId, int notificationId) { + if (!enableNotifyingActivityManagerWithMediaSessionStatusChange()) { + return; + } + + final ServiceMap smap = mServiceMap.get(userId); + if (smap == null) { + return; + } + final int serviceSize = smap.mServicesByInstanceName.size(); + for (int i = 0; i < serviceSize; i++) { + final ServiceRecord sr = smap.mServicesByInstanceName.valueAt(i); + if (sr.appInfo.packageName.equals(packageName) && sr.isForeground) { + if (sr.foregroundServiceType + == ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK + && sr.foregroundId == notificationId) { + if (DEBUG_FOREGROUND_SERVICE) { + Slog.d(TAG, "Forcing media foreground service to background for package " + + packageName); + } + setServiceForegroundInnerLocked(sr, /* id */ 0, + /* notification */ null, /* flags */ 0, + /* foregroundServiceType */ 0, /* callingUidStart */ 0); + } + } + } + } + + private static void getClientPackages(ServiceRecord sr, ArraySet<String> output) { var connections = sr.getConnections(); for (int conni = connections.size() - 1; conni >= 0; conni--) { diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index e166807083ff..5c5361bacf5a 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -17923,6 +17923,15 @@ public class ActivityManagerService extends IActivityManager.Stub } @Override + public void notifyInactiveMediaForegroundService(@NonNull String packageName, + @UserIdInt int userId, int notificationId) { + synchronized (ActivityManagerService.this) { + mServices.notifyInactiveMediaForegroundServiceLocked(packageName, userId, + notificationId); + } + } + + @Override public ArraySet<String> getClientPackages(String servicePackageName) { synchronized (ActivityManagerService.this) { return mServices.getClientPackagesLocked(servicePackageName); diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java index 02e2c391bb27..d3d3fc968ae6 100644 --- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java +++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java @@ -39,6 +39,8 @@ import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_CRI import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_LOW; import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_MODERATE; import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_NORMAL; +import static com.android.media.flags.Flags.enableNotifyingActivityManagerWithMediaSessionStatusChange; +import static com.android.media.flags.Flags.FLAG_ENABLE_NOTIFYING_ACTIVITY_MANAGER_WITH_MEDIA_SESSION_STATUS_CHANGE; import static com.android.server.am.ActivityManagerDebugConfig.LOG_WRITER_INFO; import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; @@ -445,6 +447,8 @@ final class ActivityManagerShellCommand extends ShellCommand { return runCapabilities(pw); case "set-app-zygote-preload-timeout": return runSetAppZygotePreloadTimeout(pw); + case "set-media-foreground-service": + return runSetMediaForegroundService(pw); default: return handleDefaultCommands(cmd); } @@ -454,6 +458,48 @@ final class ActivityManagerShellCommand extends ShellCommand { return -1; } + int runSetMediaForegroundService(PrintWriter pw) throws RemoteException { + mInternal.enforceCallingPermission( + android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE, + "runSetMediaForegroundService()"); + final PrintWriter err = getErrPrintWriter(); + if (!enableNotifyingActivityManagerWithMediaSessionStatusChange()) { + err.println("Error: flag " + + FLAG_ENABLE_NOTIFYING_ACTIVITY_MANAGER_WITH_MEDIA_SESSION_STATUS_CHANGE + + " not enabled"); + return -1; + } + int userId = UserHandle.USER_CURRENT; + final String cmd = getNextArgRequired(); + if ("inactive".equals(cmd)) { + String opt; + while ((opt = getNextOption()) != null) { + if (opt.equals("--user")) { + userId = UserHandle.parseUserArg(getNextArgRequired()); + if (userId == UserHandle.USER_ALL) { + err.println( + "Error: Can't set media fgs inactive with user 'all'"); + return -1; + } + } else { + err.println("Error: Unknown option: " + opt); + return -1; + } + } + final String pkgName = getNextArgRequired(); + final int notificationId = Integer.parseInt(getNextArgRequired()); + if (notificationId == 0) { + err.println("Error: notification id cannot be zero"); + return -1; + } + mInternal.mInternal.notifyInactiveMediaForegroundService(pkgName, + userId, notificationId); + return 0; + } + err.println("Error: Unknown set-media-foreground-service command: " + cmd); + return -1; + } + int runSetAppZygotePreloadTimeout(PrintWriter pw) throws RemoteException { final String timeout = getNextArgRequired(); final int timeoutMs = Integer.parseInt(timeout); @@ -4637,6 +4683,9 @@ final class ActivityManagerShellCommand extends ShellCommand { pw.println(" --protobuf: format output using protobuffer"); pw.println(" set-app-zygote-preload-timeout <TIMEOUT_IN_MS>"); pw.println(" Set the timeout for preloading code in the app-zygote"); + pw.println(" set-media-foreground-service inactive [--user USER_ID]" + + " <PACKAGE> <NOTIFICATION_ID>"); + pw.println(" Set an app's media foreground service inactive."); Intent.printIntentArgsHelp(pw, ""); } } |