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

Commit fdd36b53 authored by Shai Barack's avatar Shai Barack Committed by Mark Fasheh
Browse files

CombinedMessageQueue add peekWhenForTest and popForTest methods

The intention here is that tests should be able to call these methods
instead of reaching into MessageQueue internals via reflection.

Test: atest MessageQueueTest
Test: atest TestLooperManagerTest
Flag: android.os.message_queue_testability
Bug: 379472827
Change-Id: I5ff9dcac41f76aeabbce51f7d6db2ed5582c5664
parent 49c5896a
Loading
Loading
Loading
Loading
+139 −29
Original line number Diff line number Diff line
@@ -18,6 +18,8 @@ package android.os;

import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.annotation.TestApi;
import android.app.ActivityThread;
import android.app.Instrumentation;
@@ -27,11 +29,14 @@ import android.os.UserHandle;
import android.ravenwood.annotation.RavenwoodKeepWholeClass;
import android.ravenwood.annotation.RavenwoodRedirect;
import android.ravenwood.annotation.RavenwoodRedirectionClass;
import android.ravenwood.annotation.RavenwoodReplace;
import android.ravenwood.annotation.RavenwoodThrow;
import android.util.Log;
import android.util.Printer;
import android.util.SparseArray;
import android.util.proto.ProtoOutputStream;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.ravenwood.RavenwoodEnvironment;

import dalvik.annotation.optimization.NeverCompile;
@@ -174,6 +179,28 @@ public final class MessageQueue {
        }
    }

    @RavenwoodReplace
    private static void throwIfNotTest() {
        final ActivityThread activityThread = ActivityThread.currentActivityThread();
        if (activityThread == null) {
            // Only tests can reach here.
            return;
        }
        final Instrumentation instrumentation = activityThread.getInstrumentation();
        if (instrumentation == null) {
            // Only tests can reach here.
            return;
        }
        if (instrumentation.isInstrumenting()) {
            return;
        }
        throw new IllegalStateException("Test-only API called not from a test!");
    }

    private static void throwIfNotTest$ravenwood() {
        return;
    }

    private static boolean isInstrumenting() {
        final ActivityThread activityThread = ActivityThread.currentActivityThread();
        if (activityThread == null) {
@@ -203,12 +230,9 @@ public final class MessageQueue {

    private static final class MatchDeliverableMessages extends MessageCompare {
        @Override
        public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r,
        public boolean compareMessage(MessageNode n, Handler h, int what, Object object, Runnable r,
                long when) {
            if (m.when <= when) {
                return true;
            }
            return false;
            return n.mMessage.when <= when;
        }
    }
    private final MatchDeliverableMessages mMatchDeliverableMessages =
@@ -355,7 +379,7 @@ public final class MessageQueue {
     * @see OnFileDescriptorEventListener
     * @see #removeOnFileDescriptorEventListener
     */
    @android.ravenwood.annotation.RavenwoodThrow(blockedBy = android.os.ParcelFileDescriptor.class)
    @RavenwoodThrow(blockedBy = android.os.ParcelFileDescriptor.class)
    public void addOnFileDescriptorEventListener(@NonNull FileDescriptor fd,
            @OnFileDescriptorEventListener.Events int events,
            @NonNull OnFileDescriptorEventListener listener) {
@@ -389,7 +413,7 @@ public final class MessageQueue {
     * @see OnFileDescriptorEventListener
     * @see #addOnFileDescriptorEventListener
     */
    @android.ravenwood.annotation.RavenwoodThrow(blockedBy = android.os.ParcelFileDescriptor.class)
    @RavenwoodThrow(blockedBy = android.os.ParcelFileDescriptor.class)
    public void removeOnFileDescriptorEventListener(@NonNull FileDescriptor fd) {
        if (fd == null) {
            throw new IllegalArgumentException("fd must not be null");
@@ -405,7 +429,7 @@ public final class MessageQueue {
        }
    }

    @android.ravenwood.annotation.RavenwoodThrow(blockedBy = android.os.ParcelFileDescriptor.class)
    @RavenwoodThrow(blockedBy = android.os.ParcelFileDescriptor.class)
    private void updateOnFileDescriptorEventListenerLocked(FileDescriptor fd, int events,
            OnFileDescriptorEventListener listener) {
        final int fdNum = fd.getInt$();
@@ -528,7 +552,7 @@ public final class MessageQueue {
    /* This is only read/written from the Looper thread. For use with Concurrent MQ */
    private int mNextPollTimeoutMillis;
    private boolean mMessageDirectlyQueued;
    private Message nextMessage() {
    private Message nextMessage(boolean peek) {
        int i = 0;

        while (true) {
@@ -690,7 +714,7 @@ public final class MessageQueue {
            if (sState.compareAndSet(this, sStackStateActive, nextOp)) {
                mMessageCounts.clearCounts();
                if (found != null) {
                    if (!removeFromPriorityQueue(found)) {
                    if (!peek && !removeFromPriorityQueue(found)) {
                        /*
                         * RemoveMessages() might be able to pull messages out from under us
                         * However we can detect that here and just loop around if it happens.
@@ -724,7 +748,7 @@ public final class MessageQueue {
            mMessageDirectlyQueued = false;
            nativePollOnce(ptr, mNextPollTimeoutMillis);

            Message msg = nextMessage();
            Message msg = nextMessage(false);
            if (msg != null) {
                msg.markInUse();
                return msg;
@@ -1043,8 +1067,9 @@ public final class MessageQueue {
        }

        @Override
        public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r,
        public boolean compareMessage(MessageNode n, Handler h, int what, Object object, Runnable r,
                long when) {
            final Message m = n.mMessage;
            if (m.target == null && m.arg1 == mBarrierToken) {
                return true;
            }
@@ -1247,10 +1272,92 @@ public final class MessageQueue {
        return true;
    }

    private Message legacyPeekOrPop(boolean peek) {
        synchronized (this) {
            // Try to retrieve the next message.  Return if found.
            final long now = SystemClock.uptimeMillis();
            Message prevMsg = null;
            Message msg = mMessages;
            if (msg != null && msg.target == null) {
                // Stalled by a barrier.  Find the next asynchronous message in the queue.
                do {
                    prevMsg = msg;
                    msg = msg.next;
                } while (msg != null && !msg.isAsynchronous());
            }
            if (msg != null) {
                if (now >= msg.when) {
                    // Got a message.
                    mBlocked = false;
                    if (peek) {
                        return msg;
                    }
                    if (prevMsg != null) {
                        prevMsg.next = msg.next;
                        if (prevMsg.next == null) {
                            mLast = prevMsg;
                        }
                    } else {
                        mMessages = msg.next;
                        if (msg.next == null) {
                            mLast = null;
                        }
                    }
                    msg.next = null;
                    msg.markInUse();
                    if (msg.isAsynchronous()) {
                        mAsyncMessageCount--;
                    }
                    if (TRACE) {
                        Trace.setCounter("MQ.Delivered", mMessagesDelivered.incrementAndGet());
                    }
                    return msg;
                }
            }
        }
        return null;
    }

    /**
     * Get the timestamp of the next executable message in our priority queue.
     * Returns null if there are no messages ready for delivery.
     *
     * Caller must ensure that this doesn't race 'next' from the Looper thread.
     */
    @SuppressLint("VisiblySynchronized") // Legacy MessageQueue synchronizes on this
    Long peekWhenForTest() {
        throwIfNotTest();
        Message ret;
        if (mUseConcurrent) {
            ret = nextMessage(true);
        } else {
            ret = legacyPeekOrPop(true);
        }
        return ret != null ? ret.when : null;
    }

    /**
     * Return the next executable message in our priority queue.
     * Returns null if there are no messages ready for delivery
     *
     * Caller must ensure that this doesn't race 'next' from the Looper thread.
     */
    @SuppressLint("VisiblySynchronized") // Legacy MessageQueue synchronizes on this
    @Nullable
    Message popForTest() {
        throwIfNotTest();
        if (mUseConcurrent) {
            return nextMessage(false);
        } else {
            return legacyPeekOrPop(false);
        }
    }

    private static final class MatchHandlerWhatAndObject extends MessageCompare {
        @Override
        public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r,
        public boolean compareMessage(MessageNode n, Handler h, int what, Object object, Runnable r,
                long when) {
            final Message m = n.mMessage;
            if (m.target == h && m.what == what && (object == null || m.obj == object)) {
                return true;
            }
@@ -1281,8 +1388,9 @@ public final class MessageQueue {

    private static final class MatchHandlerWhatAndObjectEquals extends MessageCompare {
        @Override
        public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r,
        public boolean compareMessage(MessageNode n, Handler h, int what, Object object, Runnable r,
                long when) {
            final Message m = n.mMessage;
            if (m.target == h && m.what == what && (object == null || object.equals(m.obj))) {
                return true;
            }
@@ -1314,8 +1422,9 @@ public final class MessageQueue {

    private static final class MatchHandlerRunnableAndObject extends MessageCompare {
        @Override
        public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r,
        public boolean compareMessage(MessageNode n, Handler h, int what, Object object, Runnable r,
                long when) {
            final Message m = n.mMessage;
            if (m.target == h && m.callback == r && (object == null || m.obj == object)) {
                return true;
            }
@@ -1348,12 +1457,9 @@ public final class MessageQueue {

    private static final class MatchHandler extends MessageCompare {
        @Override
        public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r,
        public boolean compareMessage(MessageNode n, Handler h, int what, Object object, Runnable r,
                long when) {
            if (m.target == h) {
                return true;
            }
            return false;
            return n.mMessage.target == h;
        }
    }
    private final MatchHandler mMatchHandler = new MatchHandler();
@@ -1531,8 +1637,9 @@ public final class MessageQueue {

    private static final class MatchHandlerRunnableAndObjectEquals extends MessageCompare {
        @Override
        public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r,
        public boolean compareMessage(MessageNode n, Handler h, int what, Object object, Runnable r,
                long when) {
            final Message m = n.mMessage;
            if (m.target == h && m.callback == r && (object == null || object.equals(m.obj))) {
                return true;
            }
@@ -1594,8 +1701,9 @@ public final class MessageQueue {

    private static final class MatchHandlerAndObject extends MessageCompare {
        @Override
        public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r,
        public boolean compareMessage(MessageNode n, Handler h, int what, Object object, Runnable r,
                long when) {
            final Message m = n.mMessage;
            if (m.target == h && (object == null || m.obj == object)) {
                return true;
            }
@@ -1655,8 +1763,9 @@ public final class MessageQueue {

    private static final class MatchHandlerAndObjectEquals extends MessageCompare {
        @Override
        public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r,
        public boolean compareMessage(MessageNode n, Handler h, int what, Object object, Runnable r,
                long when) {
            final Message m = n.mMessage;
            if (m.target == h && (object == null || object.equals(m.obj))) {
                return true;
            }
@@ -1762,7 +1871,7 @@ public final class MessageQueue {

    private static final class MatchAllMessages extends MessageCompare {
        @Override
        public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r,
        public boolean compareMessage(MessageNode n, Handler h, int what, Object object, Runnable r,
                long when) {
            return true;
        }
@@ -1774,8 +1883,9 @@ public final class MessageQueue {

    private static final class MatchAllFutureMessages extends MessageCompare {
        @Override
        public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r,
        public boolean compareMessage(MessageNode n, Handler h, int what, Object object, Runnable r,
                long when) {
            final Message m = n.mMessage;
                    if (m.when > when) {
                return true;
            }
@@ -2482,7 +2592,7 @@ public final class MessageQueue {
     * This class is used to find matches for hasMessages() and removeMessages()
     */
    private abstract static class MessageCompare {
        public abstract boolean compareMessage(Message m, Handler h, int what, Object object,
        public abstract boolean compareMessage(MessageNode n, Handler h, int what, Object object,
                Runnable r, long when);
    }

@@ -2517,7 +2627,7 @@ public final class MessageQueue {
        MessageNode p = (MessageNode) top;

        while (true) {
            if (compare.compareMessage(p.mMessage, h, what, object, r, when)) {
            if (compare.compareMessage(p, h, what, object, r, when)) {
                found = true;
                if (DEBUG) {
                    Log.d(TAG_C, "stackHasMessages node matches");
@@ -2562,7 +2672,7 @@ public final class MessageQueue {
        while (iterator.hasNext()) {
            MessageNode msg = iterator.next();

            if (compare.compareMessage(msg.mMessage, h, what, object, r, when)) {
            if (compare.compareMessage(msg, h, what, object, r, when)) {
                if (removeMatches) {
                    found = true;
                    if (queue.remove(msg)) {
+100 −24
Original line number Diff line number Diff line
@@ -16,9 +16,12 @@

package android.os;

import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.TestApi;
import android.app.ActivityThread;
import android.app.Instrumentation;
import android.ravenwood.annotation.RavenwoodKeepWholeClass;
import android.ravenwood.annotation.RavenwoodRedirect;
import android.ravenwood.annotation.RavenwoodRedirectionClass;
@@ -364,6 +367,28 @@ public final class MessageQueue {
        mPtr = nativeInit();
    }

    @android.ravenwood.annotation.RavenwoodReplace
    private static void throwIfNotTest() {
        final ActivityThread activityThread = ActivityThread.currentActivityThread();
        if (activityThread == null) {
            // Only tests can reach here.
            return;
        }
        final Instrumentation instrumentation = activityThread.getInstrumentation();
        if (instrumentation == null) {
            // Only tests can reach here.
            return;
        }
        if (instrumentation.isInstrumenting()) {
            return;
        }
        throw new IllegalStateException("Test-only API called not from a test!");
    }

    private static void throwIfNotTest$ravenwood() {
        return;
    }

    @Override
    protected void finalize() throws Throwable {
        try {
@@ -384,8 +409,9 @@ public final class MessageQueue {

    private static final class MatchDeliverableMessages extends MessageCompare {
        @Override
        public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r,
                long when) {
        public boolean compareMessage(MessageNode n, Handler h, int what, Object object,
                Runnable r, long when) {
            final Message m = n.mMessage;
            if (m.when <= when) {
                return true;
            }
@@ -562,7 +588,7 @@ public final class MessageQueue {
    private static final AtomicLong mMessagesDelivered = new AtomicLong();
    private boolean mMessageDirectlyQueued;

    private Message nextMessage() {
    private Message nextMessage(boolean peek) {
        int i = 0;

        while (true) {
@@ -724,7 +750,7 @@ public final class MessageQueue {
            if (sState.compareAndSet(this, sStackStateActive, nextOp)) {
                mMessageCounts.clearCounts();
                if (found != null) {
                    if (!removeFromPriorityQueue(found)) {
                    if (!peek && !removeFromPriorityQueue(found)) {
                        /*
                         * RemoveMessages() might be able to pull messages out from under us
                         * However we can detect that here and just loop around if it happens.
@@ -993,8 +1019,9 @@ public final class MessageQueue {
        }

        @Override
        public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r,
                long when) {
        public boolean compareMessage(MessageNode n, Handler h, int what, Object object,
                Runnable r, long when) {
            final Message m = n.mMessage;
            if (m.target == null && m.arg1 == mBarrierToken) {
                return true;
            }
@@ -1039,6 +1066,47 @@ public final class MessageQueue {
        }
    }

    private static final class MatchEarliestMessage extends MessageCompare {
        MessageNode mEarliest = null;

        @Override
        public boolean compareMessage(MessageNode n, Handler h, int what, Object object,
                Runnable r, long when) {
            final Message m = n.mMessage;
            if (mEarliest == null || mEarliest.mMessage.when > m.when) {
                mEarliest = n;
            }

            return false;
        }
    }

    /**
     * Get the timestamp of the next executable message in our priority queue.
     * Returns null if there are no messages ready for delivery.
     *
     * Caller must ensure that this doesn't race 'next' from the Looper thread.
     */
    @SuppressLint("VisiblySynchronized") // Legacy MessageQueue synchronizes on this
    Long peekWhenForTest() {
        throwIfNotTest();
        Message ret = nextMessage(true);
        return ret != null ? ret.when : null;
    }

    /**
     * Return the next executable message in our priority queue.
     * Returns null if there are no messages ready for delivery
     *
     * Caller must ensure that this doesn't race 'next' from the Looper thread.
     */
    @SuppressLint("VisiblySynchronized") // Legacy MessageQueue synchronizes on this
    @Nullable
    Message popForTest() {
        throwIfNotTest();
        return nextMessage(false);
    }

    private StateNode getStateNode(StackNode node) {
        if (node.isMessageNode()) {
            return ((MessageNode) node).mBottomOfStack;
@@ -1058,7 +1126,7 @@ public final class MessageQueue {
     * This class is used to find matches for hasMessages() and removeMessages()
     */
    private abstract static class MessageCompare {
        public abstract boolean compareMessage(Message m, Handler h, int what, Object object,
        public abstract boolean compareMessage(MessageNode n, Handler h, int what, Object object,
                Runnable r, long when);
    }

@@ -1167,8 +1235,9 @@ public final class MessageQueue {

    private static final class MatchHandlerWhatAndObject extends MessageCompare {
        @Override
        public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r,
                long when) {
        public boolean compareMessage(MessageNode n, Handler h, int what, Object object,
                Runnable r, long when) {
            final Message m = n.mMessage;
            if (m.target == h && m.what == what && (object == null || m.obj == object)) {
                return true;
            }
@@ -1187,8 +1256,9 @@ public final class MessageQueue {

    private static final class MatchHandlerWhatAndObjectEquals extends MessageCompare {
        @Override
        public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r,
        public boolean compareMessage(MessageNode n, Handler h, int what, Object object, Runnable r,
                long when) {
            final Message m = n.mMessage;
            if (m.target == h && m.what == what && (object == null || object.equals(m.obj))) {
                return true;
            }
@@ -1208,8 +1278,9 @@ public final class MessageQueue {

    private static final class MatchHandlerRunnableAndObject extends MessageCompare {
        @Override
        public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r,
                long when) {
        public boolean compareMessage(MessageNode n, Handler h, int what, Object object,
                Runnable r, long when) {
            final Message m = n.mMessage;
            if (m.target == h && m.callback == r && (object == null || m.obj == object)) {
                return true;
            }
@@ -1229,8 +1300,9 @@ public final class MessageQueue {

    private static final class MatchHandler extends MessageCompare {
        @Override
        public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r,
                long when) {
        public boolean compareMessage(MessageNode n, Handler h, int what, Object object,
                Runnable r, long when) {
            final Message m = n.mMessage;
            if (m.target == h) {
                return true;
            }
@@ -1268,8 +1340,9 @@ public final class MessageQueue {

    private static final class MatchHandlerRunnableAndObjectEquals extends MessageCompare {
        @Override
        public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r,
                long when) {
        public boolean compareMessage(MessageNode n, Handler h, int what, Object object,
                Runnable r, long when) {
            final Message m = n.mMessage;
            if (m.target == h && m.callback == r && (object == null || object.equals(m.obj))) {
                return true;
            }
@@ -1287,8 +1360,9 @@ public final class MessageQueue {

    private static final class MatchHandlerAndObject extends MessageCompare {
        @Override
        public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r,
                long when) {
        public boolean compareMessage(MessageNode n, Handler h, int what, Object object,
                Runnable r, long when) {
            final Message m = n.mMessage;
            if (m.target == h && (object == null || m.obj == object)) {
                return true;
            }
@@ -1305,8 +1379,9 @@ public final class MessageQueue {

    private static final class MatchHandlerAndObjectEquals extends MessageCompare {
        @Override
        public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r,
                long when) {
        public boolean compareMessage(MessageNode n, Handler h, int what, Object object,
                Runnable r, long when) {
            final Message m = n.mMessage;
            if (m.target == h && (object == null || object.equals(m.obj))) {
                return true;
            }
@@ -1324,8 +1399,8 @@ public final class MessageQueue {

    private static final class MatchAllMessages extends MessageCompare {
        @Override
        public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r,
                long when) {
        public boolean compareMessage(MessageNode n, Handler h, int what, Object object,
                Runnable r, long when) {
            return true;
        }
    }
@@ -1336,8 +1411,9 @@ public final class MessageQueue {

    private static final class MatchAllFutureMessages extends MessageCompare {
        @Override
        public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r,
                long when) {
        public boolean compareMessage(MessageNode n, Handler h, int what, Object object,
                Runnable r, long when) {
            final Message m = n.mMessage;
            if (m.when > when) {
                return true;
            }
+99 −0

File changed.

Preview size limit exceeded, changes collapsed.