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

Commit a8f9ad3c authored by Jeff Sharkey's avatar Jeff Sharkey Committed by Android (Google) Code Review
Browse files

Merge changes from topic "sep23"

* changes:
  BroadcastQueue: implement ANR timeouts.
  BroadcastQueue: limit runnable to avoid starvation.
  BroadcastQueue: add TEST_MAPPING coverage.
  BroadcastQueue: store "runnable" as linked list.
parents fd032bc0 dd35750c
Loading
Loading
Loading
Loading
+6 −1
Original line number Original line Diff line number Diff line
@@ -2440,7 +2440,8 @@ public class ActivityManagerService extends IActivityManager.Stub
        if (mEnableModernQueue) {
        if (mEnableModernQueue) {
            mBroadcastQueues = new BroadcastQueue[1];
            mBroadcastQueues = new BroadcastQueue[1];
            mBroadcastQueues[0] = new BroadcastQueueModernImpl(this, mHandler, foreConstants);
            mBroadcastQueues[0] = new BroadcastQueueModernImpl(this, mHandler,
                    foreConstants, backConstants);
        } else {
        } else {
            mBroadcastQueues = new BroadcastQueue[4];
            mBroadcastQueues = new BroadcastQueue[4];
            mBroadcastQueues[BROADCAST_QUEUE_FG] = new BroadcastQueueImpl(this, mHandler,
            mBroadcastQueues[BROADCAST_QUEUE_FG] = new BroadcastQueueImpl(this, mHandler,
@@ -6557,6 +6558,10 @@ public class ActivityManagerService extends IActivityManager.Stub
        }
        }
    }
    }
    void appNotResponding(@NonNull ProcessRecord anrProcess, @NonNull TimeoutRecord timeoutRecord) {
        mAnrHelper.appNotResponding(anrProcess, timeoutRecord);
    }
    void startPersistentApps(int matchFlags) {
    void startPersistentApps(int matchFlags) {
        if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL) return;
        if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL) return;
+87 −7
Original line number Original line Diff line number Diff line
@@ -24,6 +24,7 @@ import android.annotation.UptimeMillisLong;
import android.os.UserHandle;
import android.os.UserHandle;
import android.util.IndentingPrintWriter;
import android.util.IndentingPrintWriter;


import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.SomeArgs;
import com.android.internal.os.SomeArgs;


import java.util.ArrayDeque;
import java.util.ArrayDeque;
@@ -40,7 +41,7 @@ import java.util.ArrayDeque;
 * be dispatched, and a single active broadcast which is currently being
 * be dispatched, and a single active broadcast which is currently being
 * dispatched.
 * dispatched.
 */
 */
class BroadcastProcessQueue implements Comparable<BroadcastProcessQueue> {
class BroadcastProcessQueue {
    /**
    /**
     * Default delay to apply to background broadcasts, giving a chance for
     * Default delay to apply to background broadcasts, giving a chance for
     * debouncing of rapidly changing events.
     * debouncing of rapidly changing events.
@@ -61,7 +62,14 @@ class BroadcastProcessQueue implements Comparable<BroadcastProcessQueue> {
     * Linked list connection to another process under this {@link #uid} which
     * Linked list connection to another process under this {@link #uid} which
     * has a different {@link #processName}.
     * has a different {@link #processName}.
     */
     */
    @Nullable BroadcastProcessQueue next;
    @Nullable BroadcastProcessQueue processNameNext;

    /**
     * Linked list connections to runnable process with lower and higher
     * {@link #getRunnableAt()} times.
     */
    @Nullable BroadcastProcessQueue runnableAtNext;
    @Nullable BroadcastProcessQueue runnableAtPrev;


    /**
    /**
     * Currently known details about the target process; typically undefined
     * Currently known details about the target process; typically undefined
@@ -87,6 +95,15 @@ class BroadcastProcessQueue implements Comparable<BroadcastProcessQueue> {
     */
     */
    private int mActiveIndex;
    private int mActiveIndex;


    /**
     * Count of {@link #mActive} broadcasts that have been dispatched since this
     * queue was last idle.
     */
    private int mActiveCountSinceIdle;

    /**
     * Count of {@link #mPending} broadcasts of these various flavors.
     */
    private int mCountForeground;
    private int mCountForeground;
    private int mCountOrdered;
    private int mCountOrdered;
    private int mCountAlarm;
    private int mCountAlarm;
@@ -162,6 +179,14 @@ class BroadcastProcessQueue implements Comparable<BroadcastProcessQueue> {
        }
        }
    }
    }


    /**
     * Count of {@link #mActive} broadcasts that have been dispatched since this
     * queue was last idle.
     */
    public int getActiveCountSinceIdle() {
        return mActiveCountSinceIdle;
    }

    /**
    /**
     * Set the currently active broadcast to the next pending broadcast.
     * Set the currently active broadcast to the next pending broadcast.
     */
     */
@@ -171,6 +196,7 @@ class BroadcastProcessQueue implements Comparable<BroadcastProcessQueue> {
        final SomeArgs next = mPending.removeFirst();
        final SomeArgs next = mPending.removeFirst();
        mActive = (BroadcastRecord) next.arg1;
        mActive = (BroadcastRecord) next.arg1;
        mActiveIndex = next.argi1;
        mActiveIndex = next.argi1;
        mActiveCountSinceIdle++;
        next.recycle();
        next.recycle();
        if (mActive.isForeground()) {
        if (mActive.isForeground()) {
            mCountForeground--;
            mCountForeground--;
@@ -190,6 +216,7 @@ class BroadcastProcessQueue implements Comparable<BroadcastProcessQueue> {
    public void makeActiveIdle() {
    public void makeActiveIdle() {
        mActive = null;
        mActive = null;
        mActiveIndex = 0;
        mActiveIndex = 0;
        mActiveCountSinceIdle = 0;
    }
    }


    public void setActiveDeliveryState(int deliveryState) {
    public void setActiveDeliveryState(int deliveryState) {
@@ -257,11 +284,64 @@ class BroadcastProcessQueue implements Comparable<BroadcastProcessQueue> {
        }
        }
    }
    }


    @Override
    /**
    public int compareTo(BroadcastProcessQueue o) {
     * Insert the given queue into a sorted linked list of "runnable" queues.
        if (mRunnableAtInvalidated) updateRunnableAt();
     *
        if (o.mRunnableAtInvalidated) o.updateRunnableAt();
     * @param head the current linked list head
        return Long.compare(mRunnableAt, o.mRunnableAt);
     * @param item the queue to insert
     * @return a potentially updated linked list head
     */
    @VisibleForTesting
    static @Nullable BroadcastProcessQueue insertIntoRunnableList(
            @Nullable BroadcastProcessQueue head, @NonNull BroadcastProcessQueue item) {
        if (head == null) {
            return item;
        }
        final long itemRunnableAt = item.getRunnableAt();
        BroadcastProcessQueue test = head;
        BroadcastProcessQueue tail = null;
        while (test != null) {
            if (test.getRunnableAt() >= itemRunnableAt) {
                item.runnableAtNext = test;
                item.runnableAtPrev = test.runnableAtPrev;
                if (item.runnableAtNext != null) {
                    item.runnableAtNext.runnableAtPrev = item;
                }
                if (item.runnableAtPrev != null) {
                    item.runnableAtPrev.runnableAtNext = item;
                }
                return (test == head) ? item : head;
            }
            tail = test;
            test = test.runnableAtNext;
        }
        item.runnableAtPrev = tail;
        item.runnableAtPrev.runnableAtNext = item;
        return head;
    }

    /**
     * Remove the given queue from a sorted linked list of "runnable" queues.
     *
     * @param head the current linked list head
     * @param item the queue to remove
     * @return a potentially updated linked list head
     */
    @VisibleForTesting
    static @Nullable BroadcastProcessQueue removeFromRunnableList(
            @Nullable BroadcastProcessQueue head, @NonNull BroadcastProcessQueue item) {
        if (head == item) {
            head = item.runnableAtNext;
        }
        if (item.runnableAtNext != null) {
            item.runnableAtNext.runnableAtPrev = item.runnableAtPrev;
        }
        if (item.runnableAtPrev != null) {
            item.runnableAtPrev.runnableAtNext = item.runnableAtNext;
        }
        item.runnableAtNext = null;
        item.runnableAtPrev = null;
        return head;
    }
    }


    @Override
    @Override
+4 −8
Original line number Original line Diff line number Diff line
@@ -40,26 +40,20 @@ public abstract class BroadcastQueue {


    final @NonNull ActivityManagerService mService;
    final @NonNull ActivityManagerService mService;
    final @NonNull Handler mHandler;
    final @NonNull Handler mHandler;
    final @NonNull BroadcastConstants mConstants;
    final @NonNull BroadcastSkipPolicy mSkipPolicy;
    final @NonNull BroadcastSkipPolicy mSkipPolicy;
    final @NonNull BroadcastHistory mHistory;
    final @NonNull BroadcastHistory mHistory;
    final @NonNull String mQueueName;
    final @NonNull String mQueueName;


    BroadcastQueue(@NonNull ActivityManagerService service, @NonNull Handler handler,
    BroadcastQueue(@NonNull ActivityManagerService service, @NonNull Handler handler,
            @NonNull String name, @NonNull BroadcastConstants constants,
            @NonNull String name, @NonNull BroadcastSkipPolicy skipPolicy,
            @NonNull BroadcastSkipPolicy skipPolicy, @NonNull BroadcastHistory history) {
            @NonNull BroadcastHistory history) {
        mService = Objects.requireNonNull(service);
        mService = Objects.requireNonNull(service);
        mHandler = Objects.requireNonNull(handler);
        mHandler = Objects.requireNonNull(handler);
        mQueueName = Objects.requireNonNull(name);
        mQueueName = Objects.requireNonNull(name);
        mConstants = Objects.requireNonNull(constants);
        mSkipPolicy = Objects.requireNonNull(skipPolicy);
        mSkipPolicy = Objects.requireNonNull(skipPolicy);
        mHistory = Objects.requireNonNull(history);
        mHistory = Objects.requireNonNull(history);
    }
    }


    void start(@NonNull ContentResolver resolver) {
        mConstants.startObserving(mHandler, resolver);
    }

    static void checkState(boolean state, String msg) {
    static void checkState(boolean state, String msg) {
        if (!state) {
        if (!state) {
            Slog.wtf(TAG, msg, new Throwable());
            Slog.wtf(TAG, msg, new Throwable());
@@ -75,6 +69,8 @@ public abstract class BroadcastQueue {
        return mQueueName;
        return mQueueName;
    }
    }


    public abstract void start(@NonNull ContentResolver resolver);

    public abstract boolean isDelayBehindServices();
    public abstract boolean isDelayBehindServices();


    /**
    /**
+6 −3
Original line number Original line Diff line number Diff line
@@ -97,6 +97,8 @@ public class BroadcastQueueImpl extends BroadcastQueue {
    private static final String TAG_MU = TAG + POSTFIX_MU;
    private static final String TAG_MU = TAG + POSTFIX_MU;
    private static final String TAG_BROADCAST = TAG + POSTFIX_BROADCAST;
    private static final String TAG_BROADCAST = TAG + POSTFIX_BROADCAST;


    final BroadcastConstants mConstants;

    /**
    /**
     * If true, we can delay broadcasts while waiting services to finish in the previous
     * If true, we can delay broadcasts while waiting services to finish in the previous
     * receiver's process.
     * receiver's process.
@@ -193,14 +195,15 @@ public class BroadcastQueueImpl extends BroadcastQueue {
    BroadcastQueueImpl(ActivityManagerService service, Handler handler,
    BroadcastQueueImpl(ActivityManagerService service, Handler handler,
            String name, BroadcastConstants constants, BroadcastSkipPolicy skipPolicy,
            String name, BroadcastConstants constants, BroadcastSkipPolicy skipPolicy,
            BroadcastHistory history, boolean allowDelayBehindServices, int schedGroup) {
            BroadcastHistory history, boolean allowDelayBehindServices, int schedGroup) {
        super(service, handler, name, constants, skipPolicy, history);
        super(service, handler, name, skipPolicy, history);
        mHandler = new BroadcastHandler(handler.getLooper());
        mHandler = new BroadcastHandler(handler.getLooper());
        mConstants = constants;
        mDelayBehindServices = allowDelayBehindServices;
        mDelayBehindServices = allowDelayBehindServices;
        mSchedGroup = schedGroup;
        mSchedGroup = schedGroup;
        mDispatcher = new BroadcastDispatcher(this, mConstants, mHandler, mService);
        mDispatcher = new BroadcastDispatcher(this, mConstants, mHandler, mService);
    }
    }


    void start(ContentResolver resolver) {
    public void start(ContentResolver resolver) {
        mDispatcher.start();
        mDispatcher.start();
        mConstants.startObserving(mHandler, resolver);
        mConstants.startObserving(mHandler, resolver);
    }
    }
@@ -1657,7 +1660,7 @@ public class BroadcastQueueImpl extends BroadcastQueue {


            // The ANR should only be triggered if we have a process record (app is non-null)
            // The ANR should only be triggered if we have a process record (app is non-null)
            if (!debugging && app != null) {
            if (!debugging && app != null) {
                mService.mAnrHelper.appNotResponding(app, timeoutRecord);
                mService.appNotResponding(app, timeoutRecord);
            }
            }


        } finally {
        } finally {
+113 −38
Original line number Original line Diff line number Diff line
@@ -20,6 +20,8 @@ import static android.os.Process.ZYGOTE_POLICY_FLAG_EMPTY;
import static android.os.Process.ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE;
import static android.os.Process.ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE;


import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST;
import static com.android.server.am.BroadcastProcessQueue.insertIntoRunnableList;
import static com.android.server.am.BroadcastProcessQueue.removeFromRunnableList;
import static com.android.server.am.BroadcastRecord.getReceiverProcessName;
import static com.android.server.am.BroadcastRecord.getReceiverProcessName;
import static com.android.server.am.BroadcastRecord.getReceiverUid;
import static com.android.server.am.BroadcastRecord.getReceiverUid;
import static com.android.server.am.OomAdjuster.OOM_ADJ_REASON_START_RECEIVER;
import static com.android.server.am.OomAdjuster.OOM_ADJ_REASON_START_RECEIVER;
@@ -37,6 +39,7 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.ResolveInfo;
import android.os.Bundle;
import android.os.Bundle;
import android.os.Handler;
import android.os.Handler;
import android.os.Message;
import android.os.RemoteException;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.SystemClock;
import android.util.IndentingPrintWriter;
import android.util.IndentingPrintWriter;
@@ -46,6 +49,8 @@ import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
import android.util.proto.ProtoOutputStream;


import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.os.TimeoutRecord;
import com.android.server.am.BroadcastRecord.DeliveryState;


import java.io.FileDescriptor;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.io.PrintWriter;
@@ -66,15 +71,17 @@ import java.util.concurrent.CountDownLatch;
 */
 */
class BroadcastQueueModernImpl extends BroadcastQueue {
class BroadcastQueueModernImpl extends BroadcastQueue {
    BroadcastQueueModernImpl(ActivityManagerService service, Handler handler,
    BroadcastQueueModernImpl(ActivityManagerService service, Handler handler,
            BroadcastConstants constants) {
            BroadcastConstants fgConstants, BroadcastConstants bgConstants) {
        this(service, handler, constants, new BroadcastSkipPolicy(service),
        this(service, handler, fgConstants, bgConstants, new BroadcastSkipPolicy(service),
                new BroadcastHistory());
                new BroadcastHistory());
    }
    }


    BroadcastQueueModernImpl(ActivityManagerService service, Handler handler,
    BroadcastQueueModernImpl(ActivityManagerService service, Handler handler,
            BroadcastConstants constants, BroadcastSkipPolicy skipPolicy,
            BroadcastConstants fgConstants, BroadcastConstants bgConstants,
            BroadcastHistory history) {
            BroadcastSkipPolicy skipPolicy, BroadcastHistory history) {
        super(service, handler, "modern", constants, skipPolicy, history);
        super(service, handler, "modern", skipPolicy, history);
        mFgConstants = Objects.requireNonNull(fgConstants);
        mBgConstants = Objects.requireNonNull(bgConstants);
        mLocalHandler = new Handler(handler.getLooper(), mLocalCallback);
        mLocalHandler = new Handler(handler.getLooper(), mLocalCallback);
    }
    }


@@ -99,6 +106,14 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
    // TODO: shift hard-coded defaults to BroadcastConstants
    // TODO: shift hard-coded defaults to BroadcastConstants
    private static final int MAX_RUNNING_PROCESS_QUEUES = 4;
    private static final int MAX_RUNNING_PROCESS_QUEUES = 4;


    /**
     * Maximum number of active broadcasts to dispatch to a "running" process
     * queue before we retire them back to being "runnable" to give other
     * processes a chance to run.
     */
    // TODO: shift hard-coded defaults to BroadcastConstants
    private static final int MAX_RUNNING_ACTIVE_BROADCASTS = 16;

    /**
    /**
     * Map from UID to per-process broadcast queues. If a UID hosts more than
     * 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
     * one process, each additional process is stored as a linked list using
@@ -111,12 +126,14 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
    private final SparseArray<BroadcastProcessQueue> mProcessQueues = new SparseArray<>();
    private final SparseArray<BroadcastProcessQueue> mProcessQueues = new SparseArray<>();


    /**
    /**
     * Collection of queues which are "runnable". They're sorted by
     * Head of linked list containing queues which are "runnable". They're
     * {@link BroadcastProcessQueue#getRunnableAt()} so that we prefer
     * sorted by {@link BroadcastProcessQueue#getRunnableAt()} so that we prefer
     * dispatching of longer-waiting broadcasts first.
     * dispatching of longer-waiting broadcasts first.
     *
     * @see BroadcastProcessQueue#insertIntoRunnableList
     * @see BroadcastProcessQueue#removeFromRunnableList
     */
     */
    @GuardedBy("mService")
    private BroadcastProcessQueue mRunnableHead = null;
    private final ArrayList<BroadcastProcessQueue> mRunnable = new ArrayList<>();


    /**
    /**
     * Collection of queues which are "running". This will never be larger than
     * Collection of queues which are "running". This will never be larger than
@@ -139,7 +156,11 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
    @GuardedBy("mService")
    @GuardedBy("mService")
    private final ArrayList<CountDownLatch> mWaitingForIdle = new ArrayList<>();
    private final ArrayList<CountDownLatch> mWaitingForIdle = new ArrayList<>();


    private final BroadcastConstants mFgConstants;
    private final BroadcastConstants mBgConstants;

    private static final int MSG_UPDATE_RUNNING_LIST = 1;
    private static final int MSG_UPDATE_RUNNING_LIST = 1;
    private static final int MSG_DELIVERY_TIMEOUT = 2;


    private void enqueueUpdateRunningList() {
    private void enqueueUpdateRunningList() {
        mLocalHandler.removeMessages(MSG_UPDATE_RUNNING_LIST);
        mLocalHandler.removeMessages(MSG_UPDATE_RUNNING_LIST);
@@ -156,6 +177,13 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
                }
                }
                return true;
                return true;
            }
            }
            case MSG_DELIVERY_TIMEOUT: {
                synchronized (mService) {
                    finishReceiverLocked((BroadcastProcessQueue) msg.obj,
                            BroadcastRecord.DELIVERY_TIMEOUT);
                }
                return true;
            }
        }
        }
        return false;
        return false;
    };
    };
@@ -176,12 +204,29 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
            return;
            return;
        }
        }


        // TODO: better optimize by using insertion sort data structure
        final boolean wantQueue = queue.isRunnable();
        mRunnable.remove(queue);
        final boolean inQueue = (queue == mRunnableHead) || (queue.runnableAtPrev != null)
        if (queue.isRunnable()) {
                || (queue.runnableAtNext != null);
            mRunnable.add(queue);
        if (wantQueue) {
            if (inQueue) {
                // We're in a good state, but our position within the linked
                // list might need to move based on a runnableAt change
                final boolean prevLower = (queue.runnableAtPrev != null)
                        ? queue.runnableAtPrev.getRunnableAt() <= queue.getRunnableAt() : true;
                final boolean nextHigher = (queue.runnableAtNext != null)
                        ? queue.runnableAtNext.getRunnableAt() >= queue.getRunnableAt() : true;
                if (prevLower && nextHigher) {
                    return;
                } else {
                    mRunnableHead = removeFromRunnableList(mRunnableHead, queue);
                    mRunnableHead = insertIntoRunnableList(mRunnableHead, queue);
                }
            } else {
                mRunnableHead = insertIntoRunnableList(mRunnableHead, queue);
            }
        } else if (inQueue) {
            mRunnableHead = removeFromRunnableList(mRunnableHead, queue);
        }
        }
        mRunnable.sort(null);
    }
    }


    /**
    /**
@@ -196,6 +241,8 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
        int avail = MAX_RUNNING_PROCESS_QUEUES - mRunning.size();
        int avail = MAX_RUNNING_PROCESS_QUEUES - mRunning.size();
        if (avail == 0) return;
        if (avail == 0) return;


        final long now = SystemClock.uptimeMillis();

        // If someone is waiting to go idle, everything is runnable now
        // If someone is waiting to go idle, everything is runnable now
        final boolean waitingForIdle = !mWaitingForIdle.isEmpty();
        final boolean waitingForIdle = !mWaitingForIdle.isEmpty();


@@ -204,9 +251,9 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
        mLocalHandler.removeMessages(MSG_UPDATE_RUNNING_LIST);
        mLocalHandler.removeMessages(MSG_UPDATE_RUNNING_LIST);


        boolean updateOomAdj = false;
        boolean updateOomAdj = false;
        final long now = SystemClock.uptimeMillis();
        BroadcastProcessQueue queue = mRunnableHead;
        for (int i = 0; i < mRunnable.size() && avail > 0; i++) {
        while (queue != null && avail > 0) {
            final BroadcastProcessQueue queue = mRunnable.get(i);
            BroadcastProcessQueue nextQueue = queue.runnableAtNext;
            final long runnableAt = queue.getRunnableAt();
            final long runnableAt = queue.getRunnableAt();


            // If queues beyond this point aren't ready to run yet, schedule
            // If queues beyond this point aren't ready to run yet, schedule
@@ -228,6 +275,8 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
                if (mRunningColdStart == null) {
                if (mRunningColdStart == null) {
                    mRunningColdStart = queue;
                    mRunningColdStart = queue;
                } else {
                } else {
                    // Move to considering next runnable queue
                    queue = nextQueue;
                    continue;
                    continue;
                }
                }
            }
            }
@@ -236,10 +285,11 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
                    + " from runnable to running; process is " + queue.app);
                    + " from runnable to running; process is " + queue.app);


            // Allocate this available permit and start running!
            // Allocate this available permit and start running!
            mRunnable.remove(i);
            mRunning.add(queue);
            mRunning.add(queue);
            avail--;
            avail--;
            i--;

            // Remove ourselves from linked list of runnable things
            mRunnableHead = removeFromRunnableList(mRunnableHead, queue);


            queue.makeActiveNextPending();
            queue.makeActiveNextPending();


@@ -253,6 +303,9 @@ class BroadcastQueueModernImpl extends BroadcastQueue {


            mService.enqueueOomAdjTargetLocked(queue.app);
            mService.enqueueOomAdjTargetLocked(queue.app);
            updateOomAdj = true;
            updateOomAdj = true;

            // Move to considering next runnable queue
            queue = nextQueue;
        }
        }


        if (updateOomAdj) {
        if (updateOomAdj) {
@@ -381,7 +434,12 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
        final BroadcastRecord r = queue.getActive();
        final BroadcastRecord r = queue.getActive();
        final Object receiver = queue.getActiveReceiver();
        final Object receiver = queue.getActiveReceiver();


        // TODO: schedule ANR timeout trigger event
        if (!r.timeoutExempt) {
            final long timeout = r.isForeground() ? mFgConstants.TIMEOUT : mBgConstants.TIMEOUT;
            mLocalHandler.sendMessageDelayed(
                    Message.obtain(mLocalHandler, MSG_DELIVERY_TIMEOUT, queue), timeout);
        }

        // TODO: apply temp allowlist exemptions
        // TODO: apply temp allowlist exemptions
        // TODO: apply background activity launch exemptions
        // TODO: apply background activity launch exemptions


@@ -436,20 +494,34 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
        return finishReceiverLocked(queue, BroadcastRecord.DELIVERY_DELIVERED);
        return finishReceiverLocked(queue, BroadcastRecord.DELIVERY_DELIVERED);
    }
    }


    private boolean finishReceiverLocked(@NonNull BroadcastProcessQueue queue, int deliveryState) {
    private boolean finishReceiverLocked(@NonNull BroadcastProcessQueue queue,
            @DeliveryState int deliveryState) {
        checkState(queue.isActive(), "isActive");
        checkState(queue.isActive(), "isActive");


        queue.setActiveDeliveryState(deliveryState);

        if (deliveryState != BroadcastRecord.DELIVERY_DELIVERED) {
        if (deliveryState != BroadcastRecord.DELIVERY_DELIVERED) {
            Slog.w(TAG, "Failed delivery of " + queue.getActive() + " to " + queue);
            Slog.w(TAG, "Delivery state of " + queue.getActive() + " to " + queue + " changed to "
                    + BroadcastRecord.deliveryStateToString(deliveryState));
        }
        }


        queue.setActiveDeliveryState(deliveryState);
        if (deliveryState == BroadcastRecord.DELIVERY_TIMEOUT) {
            if (queue.app != null && !queue.app.isDebugging()) {
                mService.appNotResponding(queue.app, TimeoutRecord
                        .forBroadcastReceiver("Broadcast of " + queue.getActive().toShortString()));
            }
        } else {
            mLocalHandler.removeMessages(MSG_DELIVERY_TIMEOUT, queue);
        }


        // TODO: cancel any outstanding ANR timeout
        // TODO: limit number of broadcasts in a row to avoid starvation
        // TODO: if we're the last receiver of this broadcast, record to history
        // TODO: if we're the last receiver of this broadcast, record to history


        if (queue.isRunnable() && queue.isProcessWarm()) {
        // Even if we have more broadcasts, if we've made reasonable progress
        // and someone else is waiting, retire ourselves to avoid starvation
        final boolean shouldRetire = (mRunnableHead != null)
                && (queue.getActiveCountSinceIdle() > MAX_RUNNING_ACTIVE_BROADCASTS);

        if (queue.isRunnable() && queue.isProcessWarm() && !shouldRetire) {
            // We're on a roll; move onto the next broadcast for this process
            // We're on a roll; move onto the next broadcast for this process
            queue.makeActiveNextPending();
            queue.makeActiveNextPending();
            scheduleReceiverWarmLocked(queue);
            scheduleReceiverWarmLocked(queue);
@@ -475,8 +547,9 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
    }
    }


    @Override
    @Override
    void start(@NonNull ContentResolver resolver) {
    public void start(@NonNull ContentResolver resolver) {
        super.start(resolver);
        mFgConstants.startObserving(mHandler, resolver);
        mBgConstants.startObserving(mHandler, resolver);


        mService.registerUidObserver(new UidObserver() {
        mService.registerUidObserver(new UidObserver() {
            @Override
            @Override
@@ -486,7 +559,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
                    while (leaf != null) {
                    while (leaf != null) {
                        leaf.setProcessCached(cached);
                        leaf.setProcessCached(cached);
                        updateRunnableList(leaf);
                        updateRunnableList(leaf);
                        leaf = leaf.next;
                        leaf = leaf.processNameNext;
                    }
                    }
                    enqueueUpdateRunningList();
                    enqueueUpdateRunningList();
                }
                }
@@ -496,7 +569,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue {


    @Override
    @Override
    public boolean isIdleLocked() {
    public boolean isIdleLocked() {
        return mRunnable.isEmpty() && mRunning.isEmpty();
        return (mRunnableHead == null) && mRunning.isEmpty();
    }
    }


    @Override
    @Override
@@ -521,7 +594,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue {


    @Override
    @Override
    public String describeStateLocked() {
    public String describeStateLocked() {
        return mRunnable.size() + " runnable, " + mRunning.size() + " running";
        return mRunning.size() + " running";
    }
    }


    @Override
    @Override
@@ -551,10 +624,10 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
        while (leaf != null) {
        while (leaf != null) {
            if (Objects.equals(leaf.processName, processName)) {
            if (Objects.equals(leaf.processName, processName)) {
                return leaf;
                return leaf;
            } else if (leaf.next == null) {
            } else if (leaf.processNameNext == null) {
                break;
                break;
            }
            }
            leaf = leaf.next;
            leaf = leaf.processNameNext;
        }
        }


        BroadcastProcessQueue created = new BroadcastProcessQueue(processName, uid);
        BroadcastProcessQueue created = new BroadcastProcessQueue(processName, uid);
@@ -563,7 +636,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
        if (leaf == null) {
        if (leaf == null) {
            mProcessQueues.put(uid, created);
            mProcessQueues.put(uid, created);
        } else {
        } else {
            leaf.next = created;
            leaf.processNameNext = created;
        }
        }
        return created;
        return created;
    }
    }
@@ -578,7 +651,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
            if (Objects.equals(leaf.processName, processName)) {
            if (Objects.equals(leaf.processName, processName)) {
                return leaf;
                return leaf;
            }
            }
            leaf = leaf.next;
            leaf = leaf.processNameNext;
        }
        }
        return null;
        return null;
    }
    }
@@ -606,7 +679,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
            BroadcastProcessQueue leaf = mProcessQueues.valueAt(i);
            BroadcastProcessQueue leaf = mProcessQueues.valueAt(i);
            while (leaf != null) {
            while (leaf != null) {
                leaf.dumpLocked(ipw);
                leaf.dumpLocked(ipw);
                leaf = leaf.next;
                leaf = leaf.processNameNext;
            }
            }
        }
        }
        ipw.decreaseIndent();
        ipw.decreaseIndent();
@@ -614,13 +687,15 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
        ipw.println();
        ipw.println();
        ipw.println("🧍 Runnable:");
        ipw.println("🧍 Runnable:");
        ipw.increaseIndent();
        ipw.increaseIndent();
        if (mRunnable.isEmpty()) {
        if (mRunnableHead == null) {
            ipw.println("(none)");
            ipw.println("(none)");
        } else {
        } else {
            for (BroadcastProcessQueue queue : mRunnable) {
            BroadcastProcessQueue queue = mRunnableHead;
            while (queue != null) {
                TimeUtils.formatDuration(queue.getRunnableAt(), now, ipw);
                TimeUtils.formatDuration(queue.getRunnableAt(), now, ipw);
                ipw.print(' ');
                ipw.print(' ');
                ipw.println(queue.toShortString());
                ipw.println(queue.toShortString());
                queue = queue.runnableAtNext;
            }
            }
        }
        }
        ipw.decreaseIndent();
        ipw.decreaseIndent();
Loading