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

Commit 0b3f85a6 authored by Christopher Tate's avatar Christopher Tate
Browse files

Properly reset FGS notification associations

When the service is brought down, the notification needs to be
properly freed from FGS-related policy.  When the same notification is
being shared by multiple live FGS instances, it needs to remain flagged
until the last of them exits that state.

Along the way, fix a latent bug that resulted in incorrect notification
behavior when an FGS's associated notification had id 0.

Bug: 191518901
Test: CtsAppTestCases:android.app.cts.ServiceTest
Change-Id: If8bae1c04d98cbab848823c86951544f792efba4
parent c46c9e64
Loading
Loading
Loading
Loading
+32 −2
Original line number Diff line number Diff line
@@ -1976,7 +1976,7 @@ public final class ActiveServices {
                r.foregroundId = 0;
                r.foregroundNoti = null;
            } else if (r.appInfo.targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP) {
                r.stripForegroundServiceFlagFromNotification();
                dropFgsNotificationStateLocked(r);
                if ((flags & Service.STOP_FOREGROUND_DETACH) != 0) {
                    r.foregroundId = 0;
                    r.foregroundNoti = null;
@@ -4225,9 +4225,10 @@ public final class ActiveServices {
        }

        r.isForeground = false;
        r.mFgsNotificationWasDeferred = false;
        dropFgsNotificationStateLocked(r);
        r.foregroundId = 0;
        r.foregroundNoti = null;
        r.mFgsNotificationWasDeferred = false;
        resetFgsRestrictionLocked(r);

        // Clear start entries.
@@ -4291,6 +4292,35 @@ public final class ActiveServices {
        smap.ensureNotStartingBackgroundLocked(r);
    }

    private void dropFgsNotificationStateLocked(ServiceRecord r) {
        // If this is the only FGS using this notification, clear its FGS flag
        boolean shared = false;
        final ServiceMap smap = mServiceMap.get(r.userId);
        if (smap != null) {
            // Is any other FGS using this notification?
            final int numServices = smap.mServicesByInstanceName.size();
            for (int i = 0; i < numServices; i++) {
                final ServiceRecord sr = smap.mServicesByInstanceName.valueAt(i);
                if (sr == r) {
                    continue;
                }
                if (sr.isForeground
                        && r.foregroundId == sr.foregroundId
                        && r.appInfo.packageName.equals(sr.appInfo.packageName)) {
                    shared = true;
                    break;
                }
            }
        } else {
            Slog.wtf(TAG, "FGS " + r + " not found!");
        }

        // No other FGS is sharing this notification, so we're done with it
        if (!shared) {
            r.stripForegroundServiceFlagFromNotification();
        }
    }

    void removeConnectionLocked(ConnectionRecord c, ProcessRecord skipApp,
            ActivityServiceConnectionsHolder skipAct, boolean enqueueOomAdj) {
        IBinder binder = c.conn.asBinder();
+6 −5
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import static android.app.PendingIntent.FLAG_IMMUTABLE;
import static android.app.PendingIntent.FLAG_UPDATE_CURRENT;
import static android.os.PowerExemptionManager.REASON_DENIED;

import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_FOREGROUND_SERVICE;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;

@@ -928,13 +929,17 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
    public void postNotification() {
        final int appUid = appInfo.uid;
        final int appPid = app.getPid();
        if (foregroundId != 0 && foregroundNoti != null) {
        if (isForeground && foregroundNoti != null) {
            // Do asynchronous communication with notification manager to
            // avoid deadlocks.
            final String localPackageName = packageName;
            final int localForegroundId = foregroundId;
            final Notification _foregroundNoti = foregroundNoti;
            final ServiceRecord record = this;
            if (DEBUG_FOREGROUND_SERVICE) {
                Slog.d(TAG, "Posting notification " + _foregroundNoti
                        + " for foreground service " + this);
            }
            ams.mHandler.post(new Runnable() {
                public void run() {
                    NotificationManagerInternal nm = LocalServices.getService(
@@ -1066,10 +1071,6 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
    }

    public void stripForegroundServiceFlagFromNotification() {
        if (foregroundId == 0) {
            return;
        }

        final int localForegroundId = foregroundId;
        final int localUserId = userId;
        final String localPackageName = packageName;