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

Commit 101dfec4 authored by Jeff Sharkey's avatar Jeff Sharkey
Browse files

BroadcastQueue: tests for broadcasts that thaw.

Several broadcast flavors should cause us to consider thawing an
otherwise cached process, causing it to become immediately runnable.

This doesn't prevent other more nuanced policy from being added in
the future, such as letting a sender configure a yet-to-be-defined
BroadcastOption to delay thawing a manifest-targeted broadcast.

Bug: 253906105
Test: atest FrameworksMockingServicesTests:BroadcastRecordTest
Test: atest FrameworksMockingServicesTests:BroadcastQueueTest
Test: atest FrameworksMockingServicesTests:BroadcastQueueModernImplTest
Change-Id: I16cc7eb7fc28ba0f68b6fce92607827b71ec569a
parent 6d57fc31
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -643,6 +643,7 @@ class BroadcastProcessQueue {
    static final int REASON_CONTAINS_INTERACTIVE = 14;
    static final int REASON_CONTAINS_RESULT_TO = 15;
    static final int REASON_CONTAINS_INSTRUMENTED = 16;
    static final int REASON_CONTAINS_MANIFEST = 17;

    @IntDef(flag = false, prefix = { "REASON_" }, value = {
            REASON_EMPTY,
@@ -658,6 +659,7 @@ class BroadcastProcessQueue {
            REASON_CONTAINS_INTERACTIVE,
            REASON_CONTAINS_RESULT_TO,
            REASON_CONTAINS_INSTRUMENTED,
            REASON_CONTAINS_MANIFEST,
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface Reason {}
@@ -677,6 +679,7 @@ class BroadcastProcessQueue {
            case REASON_CONTAINS_INTERACTIVE: return "CONTAINS_INTERACTIVE";
            case REASON_CONTAINS_RESULT_TO: return "CONTAINS_RESULT_TO";
            case REASON_CONTAINS_INSTRUMENTED: return "CONTAINS_INSTRUMENTED";
            case REASON_CONTAINS_MANIFEST: return "CONTAINS_MANIFEST";
            default: return Integer.toString(reason);
        }
    }
@@ -725,6 +728,9 @@ class BroadcastProcessQueue {
            } else if (mCountResultTo > 0) {
                mRunnableAt = runnableAt;
                mRunnableAtReason = REASON_CONTAINS_RESULT_TO;
            } else if (mCountManifest > 0) {
                mRunnableAt = runnableAt;
                mRunnableAtReason = REASON_CONTAINS_MANIFEST;
            } else if (mProcessCached) {
                mRunnableAt = runnableAt + constants.DELAY_CACHED_MILLIS;
                mRunnableAtReason = REASON_CACHED;
+110 −3
Original line number Diff line number Diff line
@@ -16,6 +16,13 @@

package com.android.server.am;

import static com.android.server.am.BroadcastProcessQueue.REASON_CONTAINS_ALARM;
import static com.android.server.am.BroadcastProcessQueue.REASON_CONTAINS_FOREGROUND;
import static com.android.server.am.BroadcastProcessQueue.REASON_CONTAINS_INTERACTIVE;
import static com.android.server.am.BroadcastProcessQueue.REASON_CONTAINS_MANIFEST;
import static com.android.server.am.BroadcastProcessQueue.REASON_CONTAINS_ORDERED;
import static com.android.server.am.BroadcastProcessQueue.REASON_CONTAINS_PRIORITIZED;
import static com.android.server.am.BroadcastProcessQueue.REASON_CONTAINS_RESULT_TO;
import static com.android.server.am.BroadcastProcessQueue.insertIntoRunnableList;
import static com.android.server.am.BroadcastProcessQueue.removeFromRunnableList;
import static com.android.server.am.BroadcastQueueTest.CLASS_GREEN;
@@ -36,13 +43,16 @@ import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;

import android.annotation.NonNull;
import android.app.Activity;
import android.app.AppOpsManager;
import android.app.BroadcastOptions;
import android.content.IIntentReceiver;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ResolveInfo;
import android.media.AudioManager;
import android.os.Bundle;
import android.os.BundleMerger;
@@ -140,6 +150,18 @@ public class BroadcastQueueModernImplTest {
        }
    }

    private static Intent makeMockIntent() {
        return mock(Intent.class);
    }

    private static ResolveInfo makeMockManifestReceiver() {
        return mock(ResolveInfo.class);
    }

    private static BroadcastFilter makeMockRegisteredReceiver() {
        return mock(BroadcastFilter.class);
    }

    private BroadcastRecord makeBroadcastRecord(Intent intent) {
        return makeBroadcastRecord(intent, BroadcastOptions.makeBasic(),
                List.of(makeManifestReceiver(PACKAGE_GREEN, CLASS_GREEN)), false);
@@ -150,6 +172,10 @@ public class BroadcastQueueModernImplTest {
                List.of(makeManifestReceiver(PACKAGE_GREEN, CLASS_GREEN)), true);
    }

    private BroadcastRecord makeBroadcastRecord(Intent intent, List receivers) {
        return makeBroadcastRecord(intent, BroadcastOptions.makeBasic(), receivers, false);
    }

    private BroadcastRecord makeBroadcastRecord(Intent intent, BroadcastOptions options) {
        return makeBroadcastRecord(intent, options,
                List.of(makeManifestReceiver(PACKAGE_GREEN, CLASS_GREEN)), false);
@@ -157,8 +183,13 @@ public class BroadcastQueueModernImplTest {

    private BroadcastRecord makeBroadcastRecord(Intent intent, BroadcastOptions options,
            List receivers, boolean ordered) {
        return makeBroadcastRecord(intent, options, receivers, null, ordered);
    }

    private BroadcastRecord makeBroadcastRecord(Intent intent, BroadcastOptions options,
            List receivers, IIntentReceiver resultTo, boolean ordered) {
        return new BroadcastRecord(mImpl, intent, mProcess, PACKAGE_RED, null, 21, 42, false, null,
                null, null, null, AppOpsManager.OP_NONE, options, receivers, null, null,
                null, null, null, AppOpsManager.OP_NONE, options, receivers, null, resultTo,
                Activity.RESULT_OK, null, null, ordered, false, false, UserHandle.USER_SYSTEM,
                false, null, false, null);
    }
@@ -287,7 +318,8 @@ public class BroadcastQueueModernImplTest {
                PACKAGE_GREEN, getUidForPackage(PACKAGE_GREEN));

        final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
        final BroadcastRecord airplaneRecord = makeBroadcastRecord(airplane);
        final BroadcastRecord airplaneRecord = makeBroadcastRecord(airplane,
                List.of(makeMockRegisteredReceiver()));
        queue.enqueueOrReplaceBroadcast(airplaneRecord, 0);

        queue.setProcessCached(false);
@@ -367,7 +399,8 @@ public class BroadcastQueueModernImplTest {
                PACKAGE_GREEN, getUidForPackage(PACKAGE_GREEN));

        final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
        final BroadcastRecord airplaneRecord = makeBroadcastRecord(airplane);
        final BroadcastRecord airplaneRecord = makeBroadcastRecord(airplane,
                List.of(makeMockRegisteredReceiver()));
        queue.enqueueOrReplaceBroadcast(airplaneRecord, 0);

        mConstants.MAX_PENDING_BROADCASTS = 128;
@@ -381,6 +414,80 @@ public class BroadcastQueueModernImplTest {
        assertEquals(BroadcastProcessQueue.REASON_MAX_PENDING, queue.getRunnableAtReason());
    }

    /**
     * Verify that a cached process that would normally be delayed becomes
     * immediately runnable when the given broadcast is enqueued.
     */
    private void doRunnableAt_Cached(BroadcastRecord testRecord, int testRunnableAtReason) {
        final BroadcastProcessQueue queue = new BroadcastProcessQueue(mConstants,
                PACKAGE_GREEN, getUidForPackage(PACKAGE_GREEN));
        queue.setProcessCached(true);

        final BroadcastRecord lazyRecord = makeBroadcastRecord(
                new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED),
                List.of(makeMockRegisteredReceiver()));

        queue.enqueueOrReplaceBroadcast(lazyRecord, 0);
        assertThat(queue.getRunnableAt()).isGreaterThan(lazyRecord.enqueueTime);
        assertThat(queue.getRunnableAtReason()).isNotEqualTo(testRunnableAtReason);

        queue.enqueueOrReplaceBroadcast(testRecord, 0);
        assertThat(queue.getRunnableAt()).isAtMost(testRecord.enqueueTime);
        assertThat(queue.getRunnableAtReason()).isEqualTo(testRunnableAtReason);
    }

    @Test
    public void testRunnableAt_Cached_Manifest() {
        doRunnableAt_Cached(makeBroadcastRecord(makeMockIntent(), null,
                List.of(makeMockManifestReceiver()), null, false), REASON_CONTAINS_MANIFEST);
    }

    @Test
    public void testRunnableAt_Cached_Ordered() {
        doRunnableAt_Cached(makeBroadcastRecord(makeMockIntent(), null,
                List.of(makeMockRegisteredReceiver()), null, true), REASON_CONTAINS_ORDERED);
    }

    @Test
    public void testRunnableAt_Cached_ResultTo() {
        final IIntentReceiver resultTo = mock(IIntentReceiver.class);
        doRunnableAt_Cached(makeBroadcastRecord(makeMockIntent(), null,
                List.of(makeMockRegisteredReceiver()), resultTo, false), REASON_CONTAINS_RESULT_TO);
    }

    @Test
    public void testRunnableAt_Cached_Foreground() {
        final Intent foregroundIntent = new Intent();
        foregroundIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
        doRunnableAt_Cached(makeBroadcastRecord(foregroundIntent, null,
                List.of(makeMockRegisteredReceiver()), null, false), REASON_CONTAINS_FOREGROUND);
    }

    @Test
    public void testRunnableAt_Cached_Interactive() {
        final BroadcastOptions options = BroadcastOptions.makeBasic();
        options.setInteractiveBroadcast(true);
        doRunnableAt_Cached(makeBroadcastRecord(makeMockIntent(), options,
                List.of(makeMockRegisteredReceiver()), null, false), REASON_CONTAINS_INTERACTIVE);
    }

    @Test
    public void testRunnableAt_Cached_Alarm() {
        final BroadcastOptions options = BroadcastOptions.makeBasic();
        options.setAlarmBroadcast(true);
        doRunnableAt_Cached(makeBroadcastRecord(makeMockIntent(), options,
                List.of(makeMockRegisteredReceiver()), null, false), REASON_CONTAINS_ALARM);
    }

    @Test
    public void testRunnableAt_Cached_Prioritized() {
        final List receivers = List.of(
                withPriority(makeManifestReceiver(PACKAGE_RED, PACKAGE_RED), 10),
                withPriority(makeManifestReceiver(PACKAGE_GREEN, PACKAGE_GREEN), -10));
        doRunnableAt_Cached(makeBroadcastRecord(makeMockIntent(), null,
                receivers, null, false), REASON_CONTAINS_PRIORITIZED);
    }

    /**
     * Confirm that we always prefer running pending items marked as "urgent",
     * then "normal", then "offload", dispatching by the relative ordering