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

Commit 67080b5c authored by Jeff Sharkey's avatar Jeff Sharkey
Browse files

BroadcastQueue: misc fixes before dogfooding.

Many test suites rely on broadcasts being processed quickly, and
there's a wide spectrum of use-cases, where the sender and/or the
receiver are being actively "instrumented".  This change adds logic
to make sure that no delays are applied in these cases.

Also add a counter for the recently added "interactive" flag, since
that's a signal that no delays should be applied.

Update getPreferredSchedulingGroupLocked() to match the logic we
use for selecting an ANR timeout duration, by only using the
"default" scheduling group for foreground broadcasts.  (Future
changes can expand this to "interactive" broadcasts if desired.)

Offer to deliver "resultTo" for non-ordered broadcasts, which will
be needed as part of upcoming BOOT and SCREEN changes.  Similar to
above, this is yet another case where no delays should be applied,
to ensure the "resultTo" doesn't get stuck waiting hours behind a
frozen or cached app.

Update KEY_DELAY constants to not use HW_TIMEOUT_MULTIPLIER, since
these are delays, not timeouts.  (Applying the multiplier causes
tests failures due to delaying too long on cloud devices.)

Fix obscure bug where callers were able register receivers without
providing an IApplicationThread; we need that to find the relevant
ProcessRecord for things like OOM adjustment, unfreezing, and more.

Bug: 253906105
Test: atest FrameworksMockingServicesTests:BroadcastRecordTest
Test: atest FrameworksMockingServicesTests:BroadcastQueueTest
Test: atest FrameworksMockingServicesTests:BroadcastQueueModernImplTest
Test: atest Launcher3Tests:AddConfigWidgetTest
Test: atest CtsWindowManagerDeviceTestCases:ActivityVisibilityTests
Test: atest CtsActivityManagerBackgroundActivityTestCases:BackgroundActivityLaunchTest
Change-Id: I3424da03655457f58d66df761f63fd37ea2c9391
parent 937e6ea6
Loading
Loading
Loading
Loading
+12 −20
Original line number Diff line number Diff line
@@ -13373,13 +13373,10 @@ public class ActivityManagerService extends IActivityManager.Stub
        int callingPid;
        boolean instantApp;
        synchronized(this) {
            if (caller != null) {
            callerApp = getRecordForAppLOSP(caller);
            if (callerApp == null) {
                    throw new SecurityException(
                            "Unable to find app for caller " + caller
                            + " (pid=" + Binder.getCallingPid()
                            + ") when registering receiver " + receiver);
                Slog.w(TAG, "registerReceiverWithFeature: no app for " + caller);
                return null;
            }
            if (callerApp.info.uid != SYSTEM_UID
                    && !callerApp.getPkgList().containsKey(callerPackage)
@@ -13389,11 +13386,6 @@ public class ActivityManagerService extends IActivityManager.Stub
            }
            callingUid = callerApp.info.uid;
            callingPid = callerApp.getPid();
            } else {
                callerPackage = null;
                callingUid = Binder.getCallingUid();
                callingPid = Binder.getCallingPid();
            }
            instantApp = isInstantApp(callerApp, callerPackage, callingUid);
            userId = mUserController.handleIncomingUser(callingPid, callingUid, userId, true,
+2 −2
Original line number Diff line number Diff line
@@ -167,7 +167,7 @@ public class BroadcastConstants {
     */
    public long DELAY_NORMAL_MILLIS = DEFAULT_DELAY_NORMAL_MILLIS;
    private static final String KEY_DELAY_NORMAL_MILLIS = "bcast_delay_normal_millis";
    private static final long DEFAULT_DELAY_NORMAL_MILLIS = 10_000 * Build.HW_TIMEOUT_MULTIPLIER;
    private static final long DEFAULT_DELAY_NORMAL_MILLIS = 1_000;

    /**
     * For {@link BroadcastQueueModernImpl}: Delay to apply to broadcasts
@@ -175,7 +175,7 @@ public class BroadcastConstants {
     */
    public long DELAY_CACHED_MILLIS = DEFAULT_DELAY_CACHED_MILLIS;
    private static final String KEY_DELAY_CACHED_MILLIS = "bcast_delay_cached_millis";
    private static final long DEFAULT_DELAY_CACHED_MILLIS = 30_000 * Build.HW_TIMEOUT_MULTIPLIER;
    private static final long DEFAULT_DELAY_CACHED_MILLIS = 10_000;

    /**
     * For {@link BroadcastQueueModernImpl}: Maximum number of complete
+90 −21
Original line number Diff line number Diff line
@@ -147,12 +147,16 @@ class BroadcastProcessQueue {
    private int mCountOrdered;
    private int mCountAlarm;
    private int mCountPrioritized;
    private int mCountInteractive;
    private int mCountResultTo;
    private int mCountInstrumented;

    private @UptimeMillisLong long mRunnableAt = Long.MAX_VALUE;
    private @Reason int mRunnableAtReason = REASON_EMPTY;
    private boolean mRunnableAtInvalidated;

    private boolean mProcessCached;
    private boolean mProcessInstrumented;

    private String mCachedToString;
    private String mCachedToShortString;
@@ -296,6 +300,18 @@ class BroadcastProcessQueue {
        return didSomething;
    }

    /**
     * Update the actively running "warm" process for this process.
     */
    public void setProcess(@Nullable ProcessRecord app) {
        this.app = app;
        if (app != null) {
            setProcessInstrumented(app.getActiveInstrumentation() != null);
        } else {
            setProcessInstrumented(false);
        }
    }

    /**
     * Update if this process is in the "cached" state, typically signaling that
     * broadcast dispatch should be paused or delayed.
@@ -307,6 +323,18 @@ class BroadcastProcessQueue {
        }
    }

    /**
     * Update if this process is in the "instrumented" state, typically
     * signaling that broadcast dispatch should bypass all pauses or delays, to
     * avoid holding up test suites.
     */
    public void setProcessInstrumented(boolean instrumented) {
        if (mProcessInstrumented != instrumented) {
            mProcessInstrumented = instrumented;
            invalidateRunnableAt();
        }
    }

    /**
     * Return if we know of an actively running "warm" process for this queue.
     */
@@ -315,13 +343,12 @@ class BroadcastProcessQueue {
    }

    public int getPreferredSchedulingGroupLocked() {
        if (mCountForeground > 0 || mCountOrdered > 0 || mCountAlarm > 0) {
            // We have an important broadcast somewhere down the queue, so
        if (mCountForeground > 0) {
            // We have a foreground broadcast somewhere down the queue, so
            // boost priority until we drain them all
            return ProcessList.SCHED_GROUP_DEFAULT;
        } else if ((mActive != null)
                && (mActive.isForeground() || mActive.ordered || mActive.alarm)) {
            // We have an important broadcast right now, so boost priority
        } else if ((mActive != null) && mActive.isForeground()) {
            // We have a foreground broadcast right now, so boost priority
            return ProcessList.SCHED_GROUP_DEFAULT;
        } else if (!isIdle()) {
            return ProcessList.SCHED_GROUP_BACKGROUND;
@@ -389,6 +416,15 @@ class BroadcastProcessQueue {
        if (record.prioritized) {
            mCountPrioritized++;
        }
        if (record.interactive) {
            mCountInteractive++;
        }
        if (record.resultTo != null) {
            mCountResultTo++;
        }
        if (record.callerInstrumented) {
            mCountInstrumented++;
        }
        invalidateRunnableAt();
    }

@@ -408,6 +444,15 @@ class BroadcastProcessQueue {
        if (record.prioritized) {
            mCountPrioritized--;
        }
        if (record.interactive) {
            mCountInteractive--;
        }
        if (record.resultTo != null) {
            mCountResultTo--;
        }
        if (record.callerInstrumented) {
            mCountInstrumented--;
        }
        invalidateRunnableAt();
    }

@@ -553,25 +598,33 @@ class BroadcastProcessQueue {
    }

    static final int REASON_EMPTY = 0;
    static final int REASON_CONTAINS_FOREGROUND = 1;
    static final int REASON_CONTAINS_ORDERED = 2;
    static final int REASON_CONTAINS_ALARM = 3;
    static final int REASON_CONTAINS_PRIORITIZED = 4;
    static final int REASON_CACHED = 5;
    static final int REASON_NORMAL = 6;
    static final int REASON_MAX_PENDING = 7;
    static final int REASON_BLOCKED = 8;
    static final int REASON_CACHED = 1;
    static final int REASON_NORMAL = 2;
    static final int REASON_MAX_PENDING = 3;
    static final int REASON_BLOCKED = 4;
    static final int REASON_INSTRUMENTED = 5;
    static final int REASON_CONTAINS_FOREGROUND = 10;
    static final int REASON_CONTAINS_ORDERED = 11;
    static final int REASON_CONTAINS_ALARM = 12;
    static final int REASON_CONTAINS_PRIORITIZED = 13;
    static final int REASON_CONTAINS_INTERACTIVE = 14;
    static final int REASON_CONTAINS_RESULT_TO = 15;
    static final int REASON_CONTAINS_INSTRUMENTED = 16;

    @IntDef(flag = false, prefix = { "REASON_" }, value = {
            REASON_EMPTY,
            REASON_CONTAINS_FOREGROUND,
            REASON_CONTAINS_ORDERED,
            REASON_CONTAINS_ALARM,
            REASON_CONTAINS_PRIORITIZED,
            REASON_CACHED,
            REASON_NORMAL,
            REASON_MAX_PENDING,
            REASON_BLOCKED,
            REASON_INSTRUMENTED,
            REASON_CONTAINS_FOREGROUND,
            REASON_CONTAINS_ORDERED,
            REASON_CONTAINS_ALARM,
            REASON_CONTAINS_PRIORITIZED,
            REASON_CONTAINS_INTERACTIVE,
            REASON_CONTAINS_RESULT_TO,
            REASON_CONTAINS_INSTRUMENTED,
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface Reason {}
@@ -579,14 +632,18 @@ class BroadcastProcessQueue {
    static @NonNull String reasonToString(@Reason int reason) {
        switch (reason) {
            case REASON_EMPTY: return "EMPTY";
            case REASON_CONTAINS_FOREGROUND: return "CONTAINS_FOREGROUND";
            case REASON_CONTAINS_ORDERED: return "CONTAINS_ORDERED";
            case REASON_CONTAINS_ALARM: return "CONTAINS_ALARM";
            case REASON_CONTAINS_PRIORITIZED: return "CONTAINS_PRIORITIZED";
            case REASON_CACHED: return "CACHED";
            case REASON_NORMAL: return "NORMAL";
            case REASON_MAX_PENDING: return "MAX_PENDING";
            case REASON_BLOCKED: return "BLOCKED";
            case REASON_INSTRUMENTED: return "INSTRUMENTED";
            case REASON_CONTAINS_FOREGROUND: return "CONTAINS_FOREGROUND";
            case REASON_CONTAINS_ORDERED: return "CONTAINS_ORDERED";
            case REASON_CONTAINS_ALARM: return "CONTAINS_ALARM";
            case REASON_CONTAINS_PRIORITIZED: return "CONTAINS_PRIORITIZED";
            case REASON_CONTAINS_INTERACTIVE: return "CONTAINS_INTERACTIVE";
            case REASON_CONTAINS_RESULT_TO: return "CONTAINS_RESULT_TO";
            case REASON_CONTAINS_INSTRUMENTED: return "CONTAINS_INSTRUMENTED";
            default: return Integer.toString(reason);
        }
    }
@@ -631,6 +688,18 @@ class BroadcastProcessQueue {
            } else if (mCountPrioritized > 0) {
                mRunnableAt = runnableAt;
                mRunnableAtReason = REASON_CONTAINS_PRIORITIZED;
            } else if (mCountInteractive > 0) {
                mRunnableAt = runnableAt;
                mRunnableAtReason = REASON_CONTAINS_INTERACTIVE;
            } else if (mCountResultTo > 0) {
                mRunnableAt = runnableAt;
                mRunnableAtReason = REASON_CONTAINS_RESULT_TO;
            } else if (mCountInstrumented > 0) {
                mRunnableAt = runnableAt;
                mRunnableAtReason = REASON_CONTAINS_INSTRUMENTED;
            } else if (mProcessInstrumented) {
                mRunnableAt = runnableAt;
                mRunnableAtReason = REASON_INSTRUMENTED;
            } else if (mProcessCached) {
                mRunnableAt = runnableAt + constants.DELAY_CACHED_MILLIS;
                mRunnableAtReason = REASON_CACHED;
+20 −17
Original line number Diff line number Diff line
@@ -441,7 +441,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
        // relevant per-process queue
        final BroadcastProcessQueue queue = getProcessQueue(app);
        if (queue != null) {
            queue.app = app;
            queue.setProcess(app);
        }

        boolean didSomething = false;
@@ -478,7 +478,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
        // relevant per-process queue
        final BroadcastProcessQueue queue = getProcessQueue(app);
        if (queue != null) {
            queue.app = null;
            queue.setProcess(null);
        }

        if ((mRunningColdStart != null) && (mRunningColdStart == queue)) {
@@ -816,6 +816,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
        }

        final BroadcastRecord r = queue.getActive();
        if (r.ordered) {
            r.resultCode = resultCode;
            r.resultData = resultData;
            r.resultExtras = resultExtras;
@@ -823,14 +824,15 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
                r.resultAbort = resultAbort;
            }

        // When the caller aborted an ordered broadcast, we mark all remaining
        // receivers as skipped
        if (r.ordered && r.resultAbort) {
            // When the caller aborted an ordered broadcast, we mark all
            // remaining receivers as skipped
            if (r.resultAbort) {
                for (int i = r.terminalCount + 1; i < r.receivers.size(); i++) {
                    setDeliveryState(null, null, r, i, r.receivers.get(i),
                            BroadcastRecord.DELIVERY_SKIPPED);
                }
            }
        }

        return finishReceiverLocked(queue, BroadcastRecord.DELIVERY_DELIVERED);
    }
@@ -925,7 +927,8 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
            notifyFinishReceiver(queue, r, index, receiver);

            // When entire ordered broadcast finished, deliver final result
            if (r.ordered && (r.terminalCount == r.receivers.size())) {
            final boolean recordFinished = (r.terminalCount == r.receivers.size());
            if (recordFinished) {
                scheduleResultTo(r);
            }

@@ -1217,7 +1220,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue {

    private void updateWarmProcess(@NonNull BroadcastProcessQueue queue) {
        if (!queue.isProcessWarm()) {
            queue.app = mService.getProcessRecordLocked(queue.processName, queue.uid);
            queue.setProcess(mService.getProcessRecordLocked(queue.processName, queue.uid));
        }
    }

+4 −0
Original line number Diff line number Diff line
@@ -78,6 +78,7 @@ final class BroadcastRecord extends Binder {
    final int callingPid;   // the pid of who sent this
    final int callingUid;   // the uid of who sent this
    final boolean callerInstantApp; // caller is an Instant App?
    final boolean callerInstrumented; // caller is being instrumented
    final boolean ordered;  // serialize the send to receivers?
    final boolean sticky;   // originated from existing sticky data?
    final boolean alarm;    // originated from an alarm triggering?
@@ -365,6 +366,8 @@ final class BroadcastRecord extends Binder {
        callingPid = _callingPid;
        callingUid = _callingUid;
        callerInstantApp = _callerInstantApp;
        callerInstrumented = (_callerApp != null)
                ? (_callerApp.getActiveInstrumentation() != null) : false;
        resolvedType = _resolvedType;
        requiredPermissions = _requiredPermissions;
        excludedPermissions = _excludedPermissions;
@@ -411,6 +414,7 @@ final class BroadcastRecord extends Binder {
        callingPid = from.callingPid;
        callingUid = from.callingUid;
        callerInstantApp = from.callerInstantApp;
        callerInstrumented = from.callerInstrumented;
        ordered = from.ordered;
        sticky = from.sticky;
        initialSticky = from.initialSticky;
Loading