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

Commit 125931a3 authored by Shai Barack's avatar Shai Barack
Browse files

Make CombinedMessageQueue pick an implementation per instance

This makes the class play more nicely with testing solutions
such as TestLooper and Robolectric Shadows that use
reflection to drive MessageQueue.

Flag: build.RELEASE_PACKAGE_MESSAGEQUEUE_IMPLEMENTATION
Change-Id: If0aaa8d5e57aad1e7200e8900ca9fc5b35c8e0b5
parent 71448bed
Loading
Loading
Loading
Loading
+26 −31
Original line number Diff line number Diff line
@@ -93,9 +93,7 @@ public final class MessageQueue {
     * system processes and provides a higher level of concurrency and higher enqueue throughput
     * than the legacy implementation.
     */
    private static boolean sUseConcurrent;

    private static boolean sUseConcurrentInitialized = false;
    private boolean mUseConcurrent;

    @RavenwoodRedirect
    private native static long nativeInit();
@@ -112,10 +110,7 @@ public final class MessageQueue {
    private native static void nativeSetFileDescriptorEvents(long ptr, int fd, int events);

    MessageQueue(boolean quitAllowed) {
        if (!sUseConcurrentInitialized) {
            sUseConcurrent = UserHandle.isCore(Process.myUid());
            sUseConcurrentInitialized = true;
        }
        mUseConcurrent = UserHandle.isCore(Process.myUid());
        mQuitAllowed = quitAllowed;
        mPtr = nativeInit();
    }
@@ -158,7 +153,7 @@ public final class MessageQueue {
     * @return True if the looper is idle.
     */
    public boolean isIdle() {
        if (sUseConcurrent) {
        if (mUseConcurrent) {
            final long now = SystemClock.uptimeMillis();

            if (stackHasMessages(null, 0, null, null, now, mMatchDeliverableMessages, false)) {
@@ -208,7 +203,7 @@ public final class MessageQueue {
        if (handler == null) {
            throw new NullPointerException("Can't add a null IdleHandler");
        }
        if (sUseConcurrent) {
        if (mUseConcurrent) {
            synchronized (mIdleHandlersLock) {
                mIdleHandlers.add(handler);
            }
@@ -229,7 +224,7 @@ public final class MessageQueue {
     * @param handler The IdleHandler to be removed.
     */
    public void removeIdleHandler(@NonNull IdleHandler handler) {
        if (sUseConcurrent) {
        if (mUseConcurrent) {
            synchronized (mIdleHandlersLock) {
                mIdleHandlers.remove(handler);
            }
@@ -252,7 +247,7 @@ public final class MessageQueue {
     * @hide
     */
    public boolean isPolling() {
        if (sUseConcurrent) {
        if (mUseConcurrent) {
            // If the loop is quitting then it must not be idling.
            // We can assume mPtr != 0 when sQuitting is false.
            return !((boolean) sQuitting.getVolatile(this)) && nativeIsPolling(mPtr);
@@ -303,7 +298,7 @@ public final class MessageQueue {
            throw new IllegalArgumentException("listener must not be null");
        }

        if (sUseConcurrent) {
        if (mUseConcurrent) {
            synchronized (mFileDescriptorRecordsLock) {
                updateOnFileDescriptorEventListenerLocked(fd, events, listener);
            }
@@ -331,7 +326,7 @@ public final class MessageQueue {
        if (fd == null) {
            throw new IllegalArgumentException("fd must not be null");
        }
        if (sUseConcurrent) {
        if (mUseConcurrent) {
            synchronized (mFileDescriptorRecordsLock) {
                updateOnFileDescriptorEventListenerLocked(fd, 0, null);
            }
@@ -388,7 +383,7 @@ public final class MessageQueue {
        final int oldWatchedEvents;
        final OnFileDescriptorEventListener listener;
        final int seq;
        if (sUseConcurrent) {
        if (mUseConcurrent) {
            synchronized (mFileDescriptorRecordsLock) {
                record = mFileDescriptorRecords.get(fd);
                if (record == null) {
@@ -708,7 +703,7 @@ public final class MessageQueue {

    @UnsupportedAppUsage
    Message next() {
        if (sUseConcurrent) {
        if (mUseConcurrent) {
            return nextConcurrent();
        }

@@ -834,7 +829,7 @@ public final class MessageQueue {
            throw new IllegalStateException("Main thread not allowed to quit.");
        }

        if (sUseConcurrent) {
        if (mUseConcurrent) {
            synchronized (mIdleHandlersLock) {
                if (sQuitting.compareAndSet(this, false, true)) {
                    if (safe) {
@@ -898,7 +893,7 @@ public final class MessageQueue {
    private int postSyncBarrier(long when) {
        // Enqueue a new sync barrier token.
        // We don't need to wake the queue because the purpose of a barrier is to stall it.
        if (sUseConcurrent) {
        if (mUseConcurrent) {
            final int token = mNextBarrierTokenAtomic.getAndIncrement();

            // b/376573804: apps and tests may expect to be able to use reflection
@@ -991,7 +986,7 @@ public final class MessageQueue {
    public void removeSyncBarrier(int token) {
        // Remove a sync barrier token from the queue.
        // If the queue is no longer stalled by a barrier then wake it.
        if (sUseConcurrent) {
        if (mUseConcurrent) {
            boolean removed;
            MessageNode first;
            final MatchBarrierToken matchBarrierToken = new MatchBarrierToken(token);
@@ -1058,7 +1053,7 @@ public final class MessageQueue {
            throw new IllegalArgumentException("Message must have a target.");
        }

        if (sUseConcurrent) {
        if (mUseConcurrent) {
            if (msg.isInUse()) {
                throw new IllegalStateException(msg + " This message is already in use.");
            }
@@ -1187,7 +1182,7 @@ public final class MessageQueue {
        if (h == null) {
            return false;
        }
        if (sUseConcurrent) {
        if (mUseConcurrent) {
            return findOrRemoveMessages(h, what, object, null, 0, mMatchHandlerWhatAndObject,
                    false);
        }
@@ -1219,7 +1214,7 @@ public final class MessageQueue {
        if (h == null) {
            return false;
        }
        if (sUseConcurrent) {
        if (mUseConcurrent) {
            return findOrRemoveMessages(h, what, object, null, 0, mMatchHandlerWhatAndObjectEquals,
                    false);

@@ -1253,7 +1248,7 @@ public final class MessageQueue {
        if (h == null) {
            return false;
        }
        if (sUseConcurrent) {
        if (mUseConcurrent) {
            return findOrRemoveMessages(h, -1, object, r, 0, mMatchHandlerRunnableAndObject,
                    false);
        }
@@ -1285,7 +1280,7 @@ public final class MessageQueue {
        if (h == null) {
            return false;
        }
        if (sUseConcurrent) {
        if (mUseConcurrent) {
            return findOrRemoveMessages(h, -1, null, null, 0, mMatchHandler, false);
        }
        synchronized (this) {
@@ -1304,7 +1299,7 @@ public final class MessageQueue {
        if (h == null) {
            return;
        }
        if (sUseConcurrent) {
        if (mUseConcurrent) {
            findOrRemoveMessages(h, what, object, null, 0, mMatchHandlerWhatAndObject, true);
            return;
        }
@@ -1355,7 +1350,7 @@ public final class MessageQueue {
            return;
        }

        if (sUseConcurrent) {
        if (mUseConcurrent) {
            findOrRemoveMessages(h, what, object, null, 0, mMatchHandlerWhatAndObjectEquals, true);
            return;
        }
@@ -1407,7 +1402,7 @@ public final class MessageQueue {
            return;
        }

        if (sUseConcurrent) {
        if (mUseConcurrent) {
            findOrRemoveMessages(h, -1, object, r, 0, mMatchHandlerRunnableAndObject, true);
            return;
        }
@@ -1470,7 +1465,7 @@ public final class MessageQueue {
            return;
        }

        if (sUseConcurrent) {
        if (mUseConcurrent) {
            findOrRemoveMessages(h, -1, object, r, 0, mMatchHandlerRunnableAndObjectEquals, true);
            return;
        }
@@ -1532,7 +1527,7 @@ public final class MessageQueue {
            return;
        }

        if (sUseConcurrent) {
        if (mUseConcurrent) {
            findOrRemoveMessages(h, -1, object, null, 0, mMatchHandlerAndObject, true);
            return;
        }
@@ -1594,7 +1589,7 @@ public final class MessageQueue {
            return;
        }

        if (sUseConcurrent) {
        if (mUseConcurrent) {
            findOrRemoveMessages(h, -1, object, null, 0, mMatchHandlerAndObjectEquals, true);
            return;
        }
@@ -1742,7 +1737,7 @@ public final class MessageQueue {

    @NeverCompile
    void dump(Printer pw, String prefix, Handler h) {
        if (sUseConcurrent) {
        if (mUseConcurrent) {
            long now = SystemClock.uptimeMillis();
            int n = 0;

@@ -1803,7 +1798,7 @@ public final class MessageQueue {

    @NeverCompile
    void dumpDebug(ProtoOutputStream proto, long fieldId) {
        if (sUseConcurrent) {
        if (mUseConcurrent) {
            final long messageQueueToken = proto.start(fieldId);

            StackNode node = (StackNode) sState.getVolatile(this);
+18 −0
Original line number Diff line number Diff line
@@ -53,6 +53,7 @@ public class TestableLooper {
    private static final Field MESSAGE_QUEUE_MESSAGES_FIELD;
    private static final Field MESSAGE_NEXT_FIELD;
    private static final Field MESSAGE_WHEN_FIELD;
    private static Field MESSAGE_QUEUE_USE_CONCURRENT_FIELD = null;

    private Looper mLooper;
    private MessageQueue mQueue;
@@ -62,6 +63,14 @@ public class TestableLooper {
    private TestLooperManager mQueueWrapper;

    static {
        try {
            MESSAGE_QUEUE_USE_CONCURRENT_FIELD =
                    MessageQueue.class.getDeclaredField("mUseConcurrent");
            MESSAGE_QUEUE_USE_CONCURRENT_FIELD.setAccessible(true);
        } catch (NoSuchFieldException ignored) {
            // Ignore - maybe this is not CombinedMessageQueue?
        }

        try {
            MESSAGE_QUEUE_MESSAGES_FIELD = MessageQueue.class.getDeclaredField("mMessages");
            MESSAGE_QUEUE_MESSAGES_FIELD.setAccessible(true);
@@ -146,6 +155,15 @@ public class TestableLooper {
        mLooper = l;
        mQueue = mLooper.getQueue();
        mHandler = new Handler(mLooper);

        // If we are using CombinedMessageQueue, we need to disable concurrent mode for testing.
        if (MESSAGE_QUEUE_USE_CONCURRENT_FIELD != null) {
            try {
                MESSAGE_QUEUE_USE_CONCURRENT_FIELD.set(mQueue, false);
            } catch (IllegalAccessException e) {
                throw new RuntimeException(e);
            }
        }
    }

    /**
+12 −22
Original line number Diff line number Diff line
@@ -90,20 +90,6 @@ public class TestLooper {
     * and call {@link #dispatchAll()}.
     */
    public TestLooper(Clock clock) {
        Field messageQueueUseConcurrentField = null;
        boolean previousUseConcurrentValue = false;
        try {
            messageQueueUseConcurrentField = MessageQueue.class.getDeclaredField("sUseConcurrent");
            messageQueueUseConcurrentField.setAccessible(true);
            previousUseConcurrentValue = messageQueueUseConcurrentField.getBoolean(null);
            // If we are using CombinedMessageQueue, we need to disable concurrent mode for testing.
            messageQueueUseConcurrentField.set(null, false);
        } catch (NoSuchFieldException e) {
            // Ignore - maybe this is not CombinedMessageQueue?
        } catch (IllegalAccessException e) {
            throw new RuntimeException("Reflection error constructing or accessing looper", e);
        }

        try {
            mLooper = LOOPER_CONSTRUCTOR.newInstance(false);

@@ -114,15 +100,19 @@ public class TestLooper {
            throw new RuntimeException("Reflection error constructing or accessing looper", e);
        }

        mClock = clock;

        if (messageQueueUseConcurrentField != null) {
        // If we are using CombinedMessageQueue, we need to disable concurrent mode for testing.
        try {
                messageQueueUseConcurrentField.set(null, previousUseConcurrentValue);
            Field messageQueueUseConcurrentField =
                    MessageQueue.class.getDeclaredField("mUseConcurrent");
            messageQueueUseConcurrentField.setAccessible(true);
            messageQueueUseConcurrentField.set(mLooper.getQueue(), false);
        } catch (NoSuchFieldException e) {
            // Ignore - maybe this is not CombinedMessageQueue?
        } catch (IllegalAccessException e) {
            throw new RuntimeException("Reflection error constructing or accessing looper", e);
        }
        }

        mClock = clock;
    }

    public Looper getLooper() {