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

Commit db863fce authored by Sudheer Shanka's avatar Sudheer Shanka Committed by Android (Google) Code Review
Browse files

Merge "Kill the cached process if it sends excessive broadcasts." into main

parents 85cae1da 67621c2b
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -487,6 +487,15 @@ public final class ApplicationExitInfo implements Parcelable {
     */
    public static final int SUBREASON_FREEZER_BINDER_ASYNC_FULL = 31;

    /**
     * The process was killed because it was sending too many broadcasts while it is in the
     * Cached state. This would be set only when the reason is {@link #REASON_OTHER}.
     *
     * For internal use only.
     * @hide
     */
    public static final int SUBREASON_EXCESSIVE_OUTGOING_BROADCASTS_WHILE_CACHED = 32;

    // If there is any OEM code which involves additional app kill reasons, it should
    // be categorized in {@link #REASON_OTHER}, with subreason code starting from 1000.

@@ -665,6 +674,7 @@ public final class ApplicationExitInfo implements Parcelable {
        SUBREASON_EXCESSIVE_BINDER_OBJECTS,
        SUBREASON_OOM_KILL,
        SUBREASON_FREEZER_BINDER_ASYNC_FULL,
        SUBREASON_EXCESSIVE_OUTGOING_BROADCASTS_WHILE_CACHED,
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface SubReason {}
@@ -1396,6 +1406,8 @@ public final class ApplicationExitInfo implements Parcelable {
                return "OOM KILL";
            case SUBREASON_FREEZER_BINDER_ASYNC_FULL:
                return "FREEZER BINDER ASYNC FULL";
            case SUBREASON_EXCESSIVE_OUTGOING_BROADCASTS_WHILE_CACHED:
                return "EXCESSIVE_OUTGOING_BROADCASTS_WHILE_CACHED";
            default:
                return "UNKNOWN";
        }
+1 −1
Original line number Diff line number Diff line
@@ -281,7 +281,7 @@ public class BroadcastConstants {
     * For {@link BroadcastQueueModernImpl}: Maximum number of outgoing broadcasts from a
     * freezable process that will be allowed before killing the process.
     */
    public long MAX_FROZEN_OUTGOING_BROADCASTS = DEFAULT_MAX_FROZEN_OUTGOING_BROADCASTS;
    public int MAX_FROZEN_OUTGOING_BROADCASTS = DEFAULT_MAX_FROZEN_OUTGOING_BROADCASTS;
    private static final String KEY_MAX_FROZEN_OUTGOING_BROADCASTS =
            "max_frozen_outgoing_broadcasts";
    private static final int DEFAULT_MAX_FROZEN_OUTGOING_BROADCASTS = 32;
+4 −0
Original line number Diff line number Diff line
@@ -277,6 +277,10 @@ class BroadcastProcessQueue {
        mOutgoingBroadcasts.clear();
    }

    public void clearOutgoingBroadcasts() {
        mOutgoingBroadcasts.clear();
    }

    /**
     * Enqueue the given broadcast to be dispatched to this process at some
     * future point in time. The target receiver is indicated by the given index
+12 −3
Original line number Diff line number Diff line
@@ -166,7 +166,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
    /**
     * Map from UID to per-process broadcast queues. If a UID hosts more than
     * one process, each additional process is stored as a linked list using
     * {@link BroadcastProcessQueue#next}.
     * {@link BroadcastProcessQueue#processNameNext}.
     *
     * @see #getProcessQueue
     * @see #getOrCreateProcessQueue
@@ -661,6 +661,10 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
        final BroadcastProcessQueue queue = getProcessQueue(app);
        if (queue != null) {
            setQueueProcess(queue, app);
            // Outgoing broadcasts should be cleared when the process dies but there have been
            // issues due to AMS not always informing the BroadcastQueue of process deaths.
            // So, clear them when a new process starts as well.
            queue.clearOutgoingBroadcasts();
        }

        boolean didSomething = false;
@@ -730,6 +734,8 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
                demoteFromRunningLocked(queue);
            }

            queue.clearOutgoingBroadcasts();

            // Skip any pending registered receivers, since the old process
            // would never be around to receive them
            boolean didSomething = queue.forEachMatchingBroadcast((r, i) -> {
@@ -781,8 +787,11 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
            final BroadcastProcessQueue queue = getOrCreateProcessQueue(
                    r.callerApp.processName, r.callerApp.uid);
            if (queue.getOutgoingBroadcastCount() >= mConstants.MAX_FROZEN_OUTGOING_BROADCASTS) {
                // TODO: Kill the process if the outgoing broadcasts count is
                // beyond a certain limit.
                r.callerApp.killLocked("Too many outgoing broadcasts in cached state",
                        ApplicationExitInfo.REASON_OTHER,
                        ApplicationExitInfo.SUBREASON_EXCESSIVE_OUTGOING_BROADCASTS_WHILE_CACHED,
                        true /* noisy */);
                return;
            }
            queue.enqueueOutgoingBroadcast(r);
            mHistory.onBroadcastFrozenLocked(r);
+31 −0
Original line number Diff line number Diff line
@@ -41,6 +41,7 @@ import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.same;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doNothing;
@@ -57,6 +58,7 @@ import android.annotation.Nullable;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.app.ApplicationExitInfo;
import android.app.BackgroundStartPrivileges;
import android.app.BroadcastOptions;
import android.app.IApplicationThread;
@@ -239,6 +241,7 @@ public class BroadcastQueueTest extends BaseBroadcastQueueTest {
        mConstants.TIMEOUT = 200;
        mConstants.ALLOW_BG_ACTIVITY_START_TIMEOUT = 0;
        mConstants.PENDING_COLD_START_CHECK_INTERVAL_MILLIS = 500;
        mConstants.MAX_FROZEN_OUTGOING_BROADCASTS = 10;
    }

    @After
@@ -2368,6 +2371,34 @@ public class BroadcastQueueTest extends BaseBroadcastQueueTest {
        verifyScheduleReceiver(times(1), receiverYellowApp, timeTick);
    }

    @Test
    @RequiresFlagsEnabled(Flags.FLAG_DEFER_OUTGOING_BROADCASTS)
    public void testKillProcess_excessiveOutgoingBroadcastsWhileCached() throws Exception {
        final ProcessRecord callerApp = makeActiveProcessRecord(PACKAGE_RED);
        setProcessFreezable(callerApp, true /* pendingFreeze */, false /* frozen */);
        waitForIdle();

        final int count = mConstants.MAX_FROZEN_OUTGOING_BROADCASTS + 1;
        for (int i = 0; i < count; ++i) {
            final Intent timeTick = new Intent(Intent.ACTION_TIME_TICK + "_" + i);
            enqueueBroadcast(makeBroadcastRecord(timeTick, callerApp, List.of(
                    makeManifestReceiver(PACKAGE_BLUE, CLASS_BLUE))));
        }
        // Verify that we invoke the call to freeze the caller app.
        verify(mAms.mOomAdjuster.mCachedAppOptimizer, atLeastOnce())
                .freezeAppAsyncImmediateLSP(callerApp);

        // Verify that the caller process is killed
        assertTrue(callerApp.isKilled());
        verify(mProcessList).noteAppKill(same(callerApp),
                eq(ApplicationExitInfo.REASON_OTHER),
                eq(ApplicationExitInfo.SUBREASON_EXCESSIVE_OUTGOING_BROADCASTS_WHILE_CACHED),
                any(String.class));

        waitForIdle();
        assertNull(mAms.getProcessRecordLocked(PACKAGE_BLUE, getUidForPackage(PACKAGE_BLUE)));
    }

    private long getReceiverScheduledTime(@NonNull BroadcastRecord r, @NonNull Object receiver) {
        for (int i = 0; i < r.receivers.size(); ++i) {
            if (isReceiverEquals(receiver, r.receivers.get(i))) {