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

Commit 1a798641 authored by Chris Tate's avatar Chris Tate Committed by Android (Google) Code Review
Browse files

Merge "Implement alarm precedence for broadcast delivery"

parents ec6d2a87 71249db6
Loading
Loading
Loading
Loading
+31 −0
Original line number Diff line number Diff line
@@ -146,6 +146,7 @@ final class ActivityManagerConstants extends ContentObserver {
    static final String KEY_NETWORK_ACCESS_TIMEOUT_MS = "network_access_timeout_ms";

    private static final int DEFAULT_MAX_CACHED_PROCESSES = 32;
    private static final boolean DEFAULT_PRIORITIZE_ALARM_BROADCASTS = true;
    private static final long DEFAULT_FGSERVICE_MIN_SHOWN_TIME = 2*1000;
    private static final long DEFAULT_FGSERVICE_MIN_REPORT_TIME = 3*1000;
    private static final long DEFAULT_FGSERVICE_SCREEN_ON_BEFORE_TIME = 1*1000;
@@ -325,6 +326,14 @@ final class ActivityManagerConstants extends ContentObserver {
     */
    private static final String KEY_PROCESS_KILL_TIMEOUT = "process_kill_timeout";

    /**
     * {@code true} to send in-flight alarm broadcasts ahead of non-alarms; {@code false}
     * to queue alarm broadcasts identically to non-alarms [i.e. the pre-U behavior]; or
     * {@code null} or empty string in order to fall back to whatever the build-time default
     * was for the device.
     */
    private static final String KEY_PRIORITIZE_ALARM_BROADCASTS = "prioritize_alarm_broadcasts";

    private static final String KEY_DEFER_BOOT_COMPLETED_BROADCAST =
            "defer_boot_completed_broadcast";

@@ -666,6 +675,12 @@ final class ActivityManagerConstants extends ContentObserver {
    volatile @BroadcastConstants.DeferBootCompletedBroadcastType int mDeferBootCompletedBroadcast =
            DEFAULT_DEFER_BOOT_COMPLETED_BROADCAST;

    /**
     * Whether alarm broadcasts are delivered immediately, or queued along with the rest
     * of the pending ordered broadcasts.
     */
    volatile boolean mPrioritizeAlarmBroadcasts = DEFAULT_PRIORITIZE_ALARM_BROADCASTS;

    /**
     * How long the Context.startForegroundService() grace period is to get around to
     * calling Service.startForeground() before we generate ANR.
@@ -977,6 +992,9 @@ final class ActivityManagerConstants extends ContentObserver {
                            case KEY_PROCESS_KILL_TIMEOUT:
                                updateProcessKillTimeout();
                                break;
                            case KEY_PRIORITIZE_ALARM_BROADCASTS:
                                updatePrioritizeAlarmBroadcasts();
                                break;
                            case KEY_DEFER_BOOT_COMPLETED_BROADCAST:
                                updateDeferBootCompletedBroadcast();
                                break;
@@ -1446,6 +1464,17 @@ final class ActivityManagerConstants extends ContentObserver {
        }
    }

    private void updatePrioritizeAlarmBroadcasts() {
        // Flag value can be something that evaluates to `true` or `false`,
        // or empty/null.  If it's empty/null, the platform default is used.
        final String flag = DeviceConfig.getString(
                DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
                KEY_PRIORITIZE_ALARM_BROADCASTS,
                "");
        mPrioritizeAlarmBroadcasts = TextUtils.isEmpty(flag)
                ? DEFAULT_PRIORITIZE_ALARM_BROADCASTS
                : Boolean.parseBoolean(flag);
    }
    private void updateDeferBootCompletedBroadcast() {
        mDeferBootCompletedBroadcast = DeviceConfig.getInt(
                DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
@@ -1786,6 +1815,8 @@ final class ActivityManagerConstants extends ContentObserver {
        pw.print("="); pw.println(mComponentAliasOverrides);
        pw.print("  "); pw.print(KEY_DEFER_BOOT_COMPLETED_BROADCAST);
        pw.print("="); pw.println(mDeferBootCompletedBroadcast);
        pw.print("  "); pw.print(KEY_PRIORITIZE_ALARM_BROADCASTS);
        pw.print("="); pw.println(mPrioritizeAlarmBroadcasts);
        pw.print("  "); pw.print(KEY_NO_KILL_CACHED_PROCESSES_UNTIL_BOOT_COMPLETED);
        pw.print("="); pw.println(mNoKillCachedProcessesUntilBootCompleted);
        pw.print("  "); pw.print(KEY_NO_KILL_CACHED_PROCESSES_POST_BOOT_COMPLETED_DURATION_MILLIS);
+73 −25
Original line number Diff line number Diff line
@@ -181,7 +181,7 @@ public class BroadcastDispatcher {
                for (int i = 0; i < numEntries; i++) {
                    if (recipientUid == mDeferredBroadcasts.get(i).uid) {
                        Deferrals d = mDeferredBroadcasts.remove(i);
                        mAlarmBroadcasts.add(d);
                        mAlarmDeferrals.add(d);
                        break;
                    }
                }
@@ -201,10 +201,10 @@ public class BroadcastDispatcher {

                // No longer an alarm target, so resume ordinary deferral policy
                if (newCount <= 0) {
                    final int numEntries = mAlarmBroadcasts.size();
                    final int numEntries = mAlarmDeferrals.size();
                    for (int i = 0; i < numEntries; i++) {
                        if (recipientUid == mAlarmBroadcasts.get(i).uid) {
                            Deferrals d = mAlarmBroadcasts.remove(i);
                        if (recipientUid == mAlarmDeferrals.get(i).uid) {
                            Deferrals d = mAlarmDeferrals.remove(i);
                            insertLocked(mDeferredBroadcasts, d);
                            break;
                        }
@@ -234,7 +234,13 @@ public class BroadcastDispatcher {
    // General deferrals not holding up alarms
    private final ArrayList<Deferrals> mDeferredBroadcasts = new ArrayList<>();
    // Deferrals that *are* holding up alarms; ordered by alarm dispatch time
    private final ArrayList<Deferrals> mAlarmBroadcasts = new ArrayList<>();
    private final ArrayList<Deferrals> mAlarmDeferrals = new ArrayList<>();
    // Under the "deliver alarm broadcasts immediately" policy, the queue of
    // upcoming alarm broadcasts.  These are always delivered first - if the
    // policy is changed on the fly from immediate-alarm-delivery to the previous
    // in-order-queueing behavior, pending immediate alarm deliveries will drain
    // and then the behavior settle into the pre-U semantics.
    private final ArrayList<BroadcastRecord> mAlarmQueue = new ArrayList<>();

    // Next outbound broadcast, established by getNextBroadcastLocked()
    private BroadcastRecord mCurrentBroadcast;
@@ -528,8 +534,9 @@ public class BroadcastDispatcher {
        synchronized (mLock) {
            return mCurrentBroadcast == null
                    && mOrderedBroadcasts.isEmpty()
                    && mAlarmQueue.isEmpty()
                    && isDeferralsListEmpty(mDeferredBroadcasts)
                    && isDeferralsListEmpty(mAlarmBroadcasts);
                    && isDeferralsListEmpty(mAlarmDeferrals);
        }
    }

@@ -557,7 +564,13 @@ public class BroadcastDispatcher {
        }
        sb.append(mOrderedBroadcasts.size());
        sb.append(" ordered");
        int n = pendingInDeferralsList(mAlarmBroadcasts);
        int n = mAlarmQueue.size();
        if (n > 0) {
            sb.append(", ");
            sb.append(n);
            sb.append(" alarms");
        }
        n = pendingInDeferralsList(mAlarmDeferrals);
        if (n > 0) {
            sb.append(", ");
            sb.append(n);
@@ -592,8 +605,16 @@ public class BroadcastDispatcher {
    // ----------------------------------
    // BroadcastQueue operation support
    void enqueueOrderedBroadcastLocked(BroadcastRecord r) {
        final ArrayList<BroadcastRecord> queue =
                (r.alarm && mQueue.mService.mConstants.mPrioritizeAlarmBroadcasts)
                        ? mAlarmQueue
                        : mOrderedBroadcasts;

        if (r.receivers == null || r.receivers.isEmpty()) {
            mOrderedBroadcasts.add(r);
            // Fast no-op path for broadcasts that won't actually be dispatched to
            // receivers - we still need to handle completion callbacks and historical
            // records, but we don't need to consider the fancy cases.
            queue.add(r);
            return;
        }

@@ -622,7 +643,8 @@ public class BroadcastDispatcher {
                return;
            }
        } else {
            mOrderedBroadcasts.add(r);
            // Ordinary broadcast, so put it on the appropriate queue and carry on
            queue.add(r);
        }
    }

@@ -652,10 +674,13 @@ public class BroadcastDispatcher {
    BroadcastRecord replaceBroadcastLocked(BroadcastRecord r, String typeForLogging) {
        // Simple case, in the ordinary queue.
        BroadcastRecord old = replaceBroadcastLocked(mOrderedBroadcasts, r, typeForLogging);

        // ... or possibly in the simple alarm queue
        if (old == null) {
            old = replaceBroadcastLocked(mAlarmQueue, r, typeForLogging);
        }
        // If we didn't find it, less-simple:  in a deferral queue?
        if (old == null) {
            old = replaceDeferredBroadcastLocked(mAlarmBroadcasts, r, typeForLogging);
            old = replaceDeferredBroadcastLocked(mAlarmDeferrals, r, typeForLogging);
        }
        if (old == null) {
            old = replaceDeferredBroadcastLocked(mDeferredBroadcasts, r, typeForLogging);
@@ -705,6 +730,10 @@ public class BroadcastDispatcher {
        // "yes we would do something" circumstance
        boolean didSomething = cleanupBroadcastListDisabledReceiversLocked(mOrderedBroadcasts,
                packageName, filterByClasses, userId, doit);
        if (doit || !didSomething) {
            didSomething = cleanupBroadcastListDisabledReceiversLocked(mAlarmQueue,
                    packageName, filterByClasses, userId, doit);
        }
        if (doit || !didSomething) {
            ArrayList<BroadcastRecord> lockedBootCompletedBroadcasts = new ArrayList<>();
            for (int u = 0, usize = mUser2Deferred.size(); u < usize; u++) {
@@ -731,7 +760,7 @@ public class BroadcastDispatcher {
                    packageName, filterByClasses, userId, doit);
        }
        if (doit || !didSomething) {
            didSomething |= cleanupDeferralsListDisabledReceiversLocked(mAlarmBroadcasts,
            didSomething |= cleanupDeferralsListDisabledReceiversLocked(mAlarmDeferrals,
                    packageName, filterByClasses, userId, doit);
        }
        if (doit || !didSomething) {
@@ -781,12 +810,15 @@ public class BroadcastDispatcher {
        if (mCurrentBroadcast != null) {
            mCurrentBroadcast.dumpDebug(proto, fieldId);
        }
        for (Deferrals d : mAlarmBroadcasts) {
        for (Deferrals d : mAlarmDeferrals) {
            d.dumpDebug(proto, fieldId);
        }
        for (BroadcastRecord br : mOrderedBroadcasts) {
            br.dumpDebug(proto, fieldId);
        }
        for (BroadcastRecord br : mAlarmQueue) {
            br.dumpDebug(proto, fieldId);
        }
        for (Deferrals d : mDeferredBroadcasts) {
            d.dumpDebug(proto, fieldId);
        }
@@ -816,23 +848,33 @@ public class BroadcastDispatcher {
            return mCurrentBroadcast;
        }

        final boolean someQueued = !mOrderedBroadcasts.isEmpty();

        BroadcastRecord next = null;

        // Alarms in flight take precedence over everything else.  This queue
        // will be non-empty only when the relevant policy is in force, but if
        // policy has changed on the fly we still need to drain this before we
        // settle into the legacy behavior.
        if (!mAlarmQueue.isEmpty()) {
            next = mAlarmQueue.remove(0);
        }

        // Next in precedence are deferred BOOT_COMPLETED broadcasts
        if (next == null) {
            next = dequeueDeferredBootCompletedBroadcast();
        }

        if (next == null && !mAlarmBroadcasts.isEmpty()) {
            next = popLocked(mAlarmBroadcasts);
        // Alarm-related deferrals are next in precedence...
        if (next == null && !mAlarmDeferrals.isEmpty()) {
            next = popLocked(mAlarmDeferrals);
            if (DEBUG_BROADCAST_DEFERRAL && next != null) {
                Slog.i(TAG, "Next broadcast from alarm targets: " + next);
            }
        }

        final boolean someQueued = !mOrderedBroadcasts.isEmpty();

        if (next == null && !mDeferredBroadcasts.isEmpty()) {
            // We're going to deliver either:
            // A this point we're going to deliver either:
            // 1. the next "overdue" deferral; or
            // 2. the next ordinary ordered broadcast; *or*
            // 3. the next not-yet-overdue deferral.
@@ -937,7 +979,7 @@ public class BroadcastDispatcher {
                    scheduleDeferralCheckLocked(true);
                } else {
                    // alarm-related: strict order-encountered
                    mAlarmBroadcasts.add(d);
                    mAlarmDeferrals.add(d);
                }
            } else {
                // We're already deferring, but something was slow again.  Reset the
@@ -999,7 +1041,7 @@ public class BroadcastDispatcher {
     * immediately deliverable.  Used by the wait-for-broadcast-idle mechanism.
     */
    public void cancelDeferralsLocked() {
        zeroDeferralTimes(mAlarmBroadcasts);
        zeroDeferralTimes(mAlarmDeferrals);
        zeroDeferralTimes(mDeferredBroadcasts);
    }

@@ -1023,7 +1065,7 @@ public class BroadcastDispatcher {
        Deferrals d = findUidLocked(uid, mDeferredBroadcasts);
        // ...but if not there, also check alarm-prioritized deferrals
        if (d == null) {
            d = findUidLocked(uid, mAlarmBroadcasts);
            d = findUidLocked(uid, mAlarmDeferrals);
        }
        return d;
    }
@@ -1035,7 +1077,7 @@ public class BroadcastDispatcher {
    private boolean removeDeferral(Deferrals d) {
        boolean didRemove = mDeferredBroadcasts.remove(d);
        if (!didRemove) {
            didRemove = mAlarmBroadcasts.remove(d);
            didRemove = mAlarmDeferrals.remove(d);
        }
        return didRemove;
    }
@@ -1103,14 +1145,20 @@ public class BroadcastDispatcher {
        } else {
            pw.println("  (null)");
        }
        printed |= dumper.didPrint();

        dumper.setHeading("Active alarm broadcasts");
        dumper.setLabel("Active Alarm Broadcast");
        for (BroadcastRecord br : mAlarmQueue) {
            dumper.dump(br);
        }
        printed |= dumper.didPrint();

        dumper.setHeading("Active ordered broadcasts");
        dumper.setLabel("Active Ordered Broadcast");
        for (Deferrals d : mAlarmBroadcasts) {
        for (Deferrals d : mAlarmDeferrals) {
            d.dumpLocked(dumper);
        }
        printed |= dumper.didPrint();

        for (BroadcastRecord br : mOrderedBroadcasts) {
            dumper.dump(br);
        }