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

Commit 36323100 authored by Thomas Stuart's avatar Thomas Stuart Committed by Android (Google) Code Review
Browse files

Merge "Revert "Allow for replaceable clock within Looper""

parents 1afa5451 bc7b8b4b
Loading
Loading
Loading
Loading
+24 −54
Original line number Diff line number Diff line
@@ -182,7 +182,7 @@ public class Handler {
     *
     * Asynchronous messages represent interrupts or events that do not require global ordering
     * with respect to synchronous messages.  Asynchronous messages are not subject to
     * the synchronization barriers introduced by {@link MessageQueue#postSyncBarrier()}.
     * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
     *
     * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
     * each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
@@ -203,7 +203,7 @@ public class Handler {
     *
     * Asynchronous messages represent interrupts or events that do not require global ordering
     * with respect to synchronous messages.  Asynchronous messages are not subject to
     * the synchronization barriers introduced by {@link MessageQueue#postSyncBarrier()}.
     * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
     *
     * @param callback The callback interface in which to handle messages, or null.
     * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
@@ -212,17 +212,25 @@ public class Handler {
     * @hide
     */
    public Handler(@Nullable Callback callback, boolean async) {
        this(getThreadLooper(), callback, async);
        if (FIND_POTENTIAL_LEAKS) {
            final Class<? extends Handler> klass = getClass();
            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                    (klass.getModifiers() & Modifier.STATIC) == 0) {
                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                    klass.getCanonicalName());
            }
        }

    private static Looper getThreadLooper() {
        final Looper looper = Looper.myLooper();
        if (looper == null) {
        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread " + Thread.currentThread()
                        + " that has not called Looper.prepare()");
        }
        return looper;
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
        mIsShared = false;
    }

    /**
@@ -249,44 +257,14 @@ public class Handler {
        this(looper, callback, async, /* shared= */ false);
    }

    /**
     * Use the provided {@link Looper} instead of the default one and take a callback
     * interface in which to handle messages.  Also set whether the handler
     * should be asynchronous.
     *
     * Handlers are synchronous by default unless this constructor is used to make
     * one that is strictly asynchronous.
     *
     * Asynchronous messages represent interrupts or events that do not require global ordering
     * with respect to synchronous messages.  Asynchronous messages are not subject to
     * the synchronization barriers introduced by conditions such as display vsync.
     *
     * @param looper   The looper, must not be null.
     * @param callback The callback interface in which to handle messages, or null.
     * @param async    If true, the handler calls {@link Message#setAsynchronous(boolean)} for
     *                 each {@link Message} that is sent to it or {@link Runnable} that is posted to
     *                 it.
     * @param shared   Whether this Handler might be used by more than one client. A shared Handler
     *                 applies some extra policy, such as disallowing the removal of all messages,
     *                 in order to avoid one client affecting another's messages.
     * @hide
     */
    /** @hide */
    public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async,
            boolean shared) {
        if (FIND_POTENTIAL_LEAKS) {
            final Class<? extends Handler> klass = getClass();
            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass())
                    && (klass.getModifiers() & Modifier.STATIC) == 0) {
                Log.w(TAG, "The following Handler class should be static or leaks might occur: "
                        + klass.getCanonicalName());
            }
        }
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
        mIsShared = shared;
        mClock = looper.getClock();
    }

    /**
@@ -724,14 +702,7 @@ public class Handler {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        // mClock should theoretically never be null, but some tests create a mock handler that
        // instantiates an instance where all members are null. Ideally we'd fix these tests to
        // not rely on this but there are quite a lot at this point, so it's easier to just keep
        // the existing behavior.
        if (mClock == null) {
            return false;
        }
        return sendMessageAtTime(msg, mClock.uptimeMillis() + delayMillis);
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }

    /**
@@ -924,7 +895,7 @@ public class Handler {
    }

    public final void dump(@NonNull Printer pw, @NonNull String prefix) {
        pw.println(prefix + this + " @ " + mClock.uptimeMillis());
        pw.println(prefix + this + " @ " + SystemClock.uptimeMillis());
        if (mLooper == null) {
            pw.println(prefix + "looper uninitialized");
        } else {
@@ -936,7 +907,7 @@ public class Handler {
     * @hide
     */
    public final void dumpMine(@NonNull Printer pw, @NonNull String prefix) {
        pw.println(prefix + this + " @ " + mClock.uptimeMillis());
        pw.println(prefix + this + " @ " + SystemClock.uptimeMillis());
        if (mLooper == null) {
            pw.println(prefix + "looper uninitialized");
        } else {
@@ -993,7 +964,6 @@ public class Handler {
    @UnsupportedAppUsage
    final Callback mCallback;
    final boolean mAsynchronous;
    final MessageQueue.Clock mClock;
    @UnsupportedAppUsage
    IMessenger mMessenger;

@@ -1027,9 +997,9 @@ public class Handler {

            synchronized (this) {
                if (timeout > 0) {
                    final long expirationTime = handler.mClock.uptimeMillis() + timeout;
                    final long expirationTime = SystemClock.uptimeMillis() + timeout;
                    while (!mDone) {
                        long delay = expirationTime - handler.mClock.uptimeMillis();
                        long delay = expirationTime - SystemClock.uptimeMillis();
                        if (delay <= 0) {
                            return false; // timeout
                        }
+4 −22
Original line number Diff line number Diff line
@@ -24,8 +24,6 @@ import android.util.Printer;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;

import java.util.Objects;

/**
  * Class used to run a message loop for a thread.  Threads by default do
  * not have a message loop associated with them; to create one, call
@@ -71,7 +69,7 @@ public final class Looper {

    // sThreadLocal.get() will return null unless you've called prepare().
    @UnsupportedAppUsage
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<>();
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
    @UnsupportedAppUsage
    private static Looper sMainLooper;  // guarded by Looper.class
    private static Observer sObserver;
@@ -79,7 +77,6 @@ public final class Looper {
    @UnsupportedAppUsage
    final MessageQueue mQueue;
    final Thread mThread;
    final MessageQueue.Clock mClock;
    private boolean mInLoop;

    @UnsupportedAppUsage
@@ -194,7 +191,7 @@ public final class Looper {
            Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
        }

        final long dispatchStart = needStartTime ? me.mClock.uptimeMillis() : 0;
        final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
        final long dispatchEnd;
        Object token = null;
        if (observer != null) {
@@ -206,7 +203,7 @@ public final class Looper {
            if (observer != null) {
                observer.messageDispatched(token, msg);
            }
            dispatchEnd = needEndTime ? me.mClock.uptimeMillis() : 0;
            dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
        } catch (Exception exception) {
            if (observer != null) {
                observer.dispatchingThrewException(token, msg, exception);
@@ -328,13 +325,8 @@ public final class Looper {
    }

    private Looper(boolean quitAllowed) {
        this(quitAllowed, SystemClock::uptimeMillis);
    }

    private Looper(boolean quitAllowed, @NonNull MessageQueue.Clock clock) {
        mQueue = new MessageQueue(quitAllowed, Objects.requireNonNull(clock));
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
        mClock = clock;
    }

    /**
@@ -426,16 +418,6 @@ public final class Looper {
        return mQueue;
    }

    /**
     * Gets the looper's clock.
     *
     * @return The looper's clock
     * @hide
     */
    public @NonNull MessageQueue.Clock getClock() {
        return mClock;
    }

    /**
     * Dumps the state of the looper for debugging purposes.
     *
+42 −24
Original line number Diff line number Diff line
@@ -19,7 +19,6 @@ package android.os;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.TestApi;
import android.annotation.UptimeMillisLong;
import android.compat.annotation.UnsupportedAppUsage;
import android.util.Log;
import android.util.Printer;
@@ -30,7 +29,6 @@ import java.io.FileDescriptor;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Objects;

/**
 * Low-level class holding the list of messages to be dispatched by a
@@ -56,7 +54,6 @@ public final class MessageQueue {
    Message mMessages;
    @UnsupportedAppUsage
    private final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<IdleHandler>();
    private final Clock mClock;
    private SparseArray<FileDescriptorRecord> mFileDescriptorRecords;
    private IdleHandler[] mPendingIdleHandlers;
    private boolean mQuitting;
@@ -77,10 +74,9 @@ public final class MessageQueue {
    private native static boolean nativeIsPolling(long ptr);
    private native static void nativeSetFileDescriptorEvents(long ptr, int fd, int events);

    MessageQueue(boolean quitAllowed, @NonNull Clock clock) {
    MessageQueue(boolean quitAllowed) {
        mQuitAllowed = quitAllowed;
        mPtr = nativeInit();
        mClock = Objects.requireNonNull(clock);
    }

    @Override
@@ -110,7 +106,7 @@ public final class MessageQueue {
     */
    public boolean isIdle() {
        synchronized (this) {
            final long now = mClock.uptimeMillis();
            final long now = SystemClock.uptimeMillis();
            return mMessages == null || now < mMessages.when;
        }
    }
@@ -340,7 +336,7 @@ public final class MessageQueue {

            synchronized (this) {
                // Try to retrieve the next message.  Return if found.
                final long now = mClock.uptimeMillis();
                final long now = SystemClock.uptimeMillis();
                Message prevMsg = null;
                Message msg = mMessages;
                if (msg != null && msg.target == null) {
@@ -474,7 +470,7 @@ public final class MessageQueue {
    @UnsupportedAppUsage
    @TestApi
    public int postSyncBarrier() {
        return postSyncBarrier(mClock.uptimeMillis());
        return postSyncBarrier(SystemClock.uptimeMillis());
    }

    private int postSyncBarrier(long when) {
@@ -776,6 +772,41 @@ public final class MessageQueue {
        }
    }

    void removeEqualMessages(Handler h, Runnable r, Object object) {
        if (h == null || r == null) {
            return;
        }

        synchronized (this) {
            Message p = mMessages;

            // Remove all messages at front.
            while (p != null && p.target == h && p.callback == r
                   && (object == null || object.equals(p.obj))) {
                Message n = p.next;
                mMessages = n;
                p.recycleUnchecked();
                p = n;
            }

            // Remove all messages after front.
            while (p != null) {
                Message n = p.next;
                if (n != null) {
                    if (n.target == h && n.callback == r
                        && (object == null || object.equals(n.obj))) {
                        Message nn = n.next;
                        n.recycleUnchecked();
                        p.next = nn;
                        continue;
                    }
                }
                p = n;
            }
        }
    }


    void removeCallbacksAndMessages(Handler h, Object object) {
        if (h == null) {
            return;
@@ -853,7 +884,7 @@ public final class MessageQueue {
    }

    private void removeAllFutureMessagesLocked() {
        final long now = mClock.uptimeMillis();
        final long now = SystemClock.uptimeMillis();
        Message p = mMessages;
        if (p != null) {
            if (p.when > now) {
@@ -882,7 +913,7 @@ public final class MessageQueue {

    void dump(Printer pw, String prefix, Handler h) {
        synchronized (this) {
            long now = mClock.uptimeMillis();
            long now = SystemClock.uptimeMillis();
            int n = 0;
            for (Message msg = mMessages; msg != null; msg = msg.next) {
                if (h == null || h == msg.target) {
@@ -911,7 +942,7 @@ public final class MessageQueue {
     * Callback interface for discovering when a thread is going to block
     * waiting for more messages.
     */
    public interface IdleHandler {
    public static interface IdleHandler {
        /**
         * Called when the message queue has run out of messages and will now
         * wait for more.  Return true to keep your idle handler active, false
@@ -1010,17 +1041,4 @@ public final class MessageQueue {
            mListener = listener;
        }
    }

    /**
     * Time supplier for MessageQueue and the things that interact with it (e.g. {@link Looper}).
     *
     * Intentionally replaceable for testing.
     *
     * @hide
     */
    public interface Clock {
        /** @see SystemClock#uptimeMillis */
        @UptimeMillisLong
        long uptimeMillis();
    }
}
+9 −6
Original line number Diff line number Diff line
@@ -48,14 +48,13 @@ public class TestLooper {
    private static final Method MESSAGE_MARK_IN_USE_METHOD;
    private static final String TAG = "TestLooper";

    private final MessageQueue.Clock mClock;
    private final Clock mClock;

    private AutoDispatchThread mAutoDispatchThread;

    static {
        try {
            LOOPER_CONSTRUCTOR = Looper.class.getDeclaredConstructor(Boolean.TYPE,
                    MessageQueue.Clock.class);
            LOOPER_CONSTRUCTOR = Looper.class.getDeclaredConstructor(Boolean.TYPE);
            LOOPER_CONSTRUCTOR.setAccessible(true);
            THREAD_LOCAL_LOOPER_FIELD = Looper.class.getDeclaredField("sThreadLocal");
            THREAD_LOCAL_LOOPER_FIELD.setAccessible(true);
@@ -84,15 +83,15 @@ public class TestLooper {
     * thread.
     *
     * Messages are dispatched when their {@link Message#when} is before or at {@link
     * MessageQueue.Clock#uptimeMillis()}.
     * Clock#uptimeMillis()}.
     * Use a custom clock with care. When using an offsettable clock like {@link
     * com.android.server.testutils.OffsettableClock} be sure not to double offset messages by
     * offsetting the clock and calling {@link #moveTimeForward(long)}. Instead, offset the clock
     * and call {@link #dispatchAll()}.
     */
    public TestLooper(MessageQueue.Clock clock) {
    public TestLooper(Clock clock) {
        try {
            mLooper = LOOPER_CONSTRUCTOR.newInstance(false, clock);
            mLooper = LOOPER_CONSTRUCTOR.newInstance(false);

            ThreadLocal<Looper> threadLocalLooper = (ThreadLocal<Looper>) THREAD_LOCAL_LOOPER_FIELD
                    .get(null);
@@ -225,6 +224,10 @@ public class TestLooper {
        return count;
    }

    public interface Clock {
        long uptimeMillis();
    }

    /**
     * Thread used to dispatch messages when the main thread is blocked waiting for a response.
     */