android 消息机制分析

Handler 机制

Handler 是 android 系统上实现跨线程通信的最广泛使用的方式。


一个线程中可以有几个 Handler

  • 一个线程只能创建一个 Looper,可以有多个 Handler。或者说一个线程只能创建一套完整的 Handler 通信机制。
  • android 系统上所有与 main 线程通信的底层实现都是 handler 机制。

Handler 机制源码分析

从发送消息 Handler#sendMessage(@NonNull Message msg) 到最终的消息处理 Handler#handleMessage(@NonNull Message msg) 形成一个完成的通信过程。

发送消息的线程可以是在 main 线程 或者 子线程。

下面是消息发送的部分源码, 从 Handler#sendMessage(@NonNull Message msg) 发送消息开始分析。

// frameworks/base/core/java/android/os/Handler.java

public class Handler {

    @UnsupportedAppUsage
    final Looper mLooper;    // Looper 对象内包含有 MessageQueue 消息队列。
    final MessageQueue mQueue;

    @Deprecated
    public Handler() {		// 这个构造方法标记了 Deprecated,基本不再使用。
        this(null, false);
    }

   @Deprecated
    public Handler(@Nullable Callback callback) {	// 这个构造方法标记了 Deprecated,基本不再使用。
        this(callback, false);
    }

    /**
     * (1) 这是构造方法 1。
     * 
     * Looper 从调用方传入,与当前 Handler 实例匹配。
     */
    public Handler(@NonNull Looper looper) {   // 创建 Handler 实例最常使用的构方法。
        this(looper, null, false);  // 调用 3 个参数的构造方法 (3)。
    }

    /**
     * (2) 这是构造方法 2。
     */
    public Handler(@NonNull Looper looper, @Nullable Callback callback) {  // 这个构造方法也是被经常使用的构造。
        this(looper, callback, false);  // 调用 3 个参数的构造方法 (3)。
    }

    /**
     * (3) 这是构造方法 3。
     */
    @UnsupportedAppUsage
    public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async) {
        this(looper, callback, async, /* shared= */ false);
    }

    /**
     * (4) 这是构造方法 4。
     */
    /** @hide */
    public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async,
            boolean shared) {
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
        mIsShared = shared;
    }


// ......

	/**
	 * 从这个方法作为 Handler 源码分析的入口。
	 * 
	 * send1 ---> send2
	 */
	public final boolean sendMessage(@NonNull Message msg) {   // 分析入口
        return sendMessageDelayed(msg, 0);
    }

	/**
 	 * send2 ---> send3
  	 */
    public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }

	/**
	 * send3 
	 * 
	 * 调用到这里,将 msg 对象加入到消息队列。
	 */
    public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {
        MessageQueue queue = mQueue;
        if (queue == null) {
            RuntimeException e = new RuntimeException(
                    this + " sendMessageAtTime() called with no mQueue");
            Log.w("Looper", e.getMessage(), e);
            return false;
        }
        return enqueueMessage(queue, msg, uptimeMillis);
    }

    private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
            long uptimeMillis) {
        msg.target = this;
        msg.workSourceUid = ThreadLocalWorkSource.getUid();

        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }

// ......
}
  • 从上面的源码中,构造方法 Handler()Handler(@Nullable Callback callback) 已经被标记 deprecated,不再建议使用,即 Looper 的引用是从外部传入。
  • Looper 中包含有 MessageQueue,从构造方法 4 看得出来,Handler 间接持有 MessageQueue 引用。

接下来重要的实现在于 Looper 和消息循环。


Looper 循环泵

Looper 是一个循环泵,不停地从 MessageQueue 中提取消息,并分发给目标 Handler 进行处理。

上一节 Handler 源码最后的

private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg, long uptimeMillis)

方法实现中调用到 MessageQueue#enqueueMessage(Message msg, long when) 方法,它的声明是

boolean enqueueMessage(Message msg, long when)

接着我们来看下 Looper 的创建和它是如何循环的。


首先需要知道的是,一个线程 Thread 默认是没有消息队列 MessageQueue 的,即不会有消息循环这个机制。但 Android app 进程运行的主线程(main thread)—— 消息循环机制是其重要的组成部分 —— 有 looper 进行消息循环,从消息队列 MessageQueue 取出消息,并分发到目标 Handler 进行处理。


下来分析以下一个线程(Thread)中如何绑定一个消息循环机制。

下面的这段代码表达了:让一个线程具备消息循环的能力。

class LooperThread extends Thread {
    public Handler mHandler;

    public void run() {
        Looper.prepare();

        mHandler = new Handler(Looper.myLooper()) {
            public void handleMessage(Message msg) {
                // process incoming messages here
            }
        };

        Looper.loop();
    }
}
  • 调用 Looper#prepare() 创建消息队列。
  • 调用 Looper#loop() 开始消息循环。

Looper#prepare()

下面看 Looper#prepare() 源码。

public final class Looper {
    @UnsupportedAppUsage
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

    @UnsupportedAppUsage
    final MessageQueue mQueue;
    final Thread mThread;

    /** Initialize the current thread as a looper.
      * This gives you a chance to create handlers that then reference
      * this looper, before actually starting the loop. Be sure to call
      * {@link #loop()} after calling this method, and end it by calling
      * {@link #quit()}.
      */
    public static void prepare() {
        prepare(true);
    }

    private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(quitAllowed));
    }

    private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }

	// ......
}
  • if (sThreadLocal.get() != null) {
        throw new RuntimeException("Only one Looper may be created per thread");
    }
    

    首先,判断 sThreadLocal 中是否已经保存有 Looper 实例,如果已经有了,直接抛出异常。这样做保证了 “一个线程只能有一个 Looper 对象。” 在未找到 Looper 实例的情况下,sTreadLocal.set(new Looper(quitAllowed)) 保存 Looper 实例。

  • private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }
    

    私有的 Looper 构造方法中创建了 MessageQueue,并获取当前线程(Thread)对象。由于构造方法的调用在 sThreadLocal.get() != null 之后,也表达了 “一个线程只能有一个消息队列。”


Looper#loop()
public final class Looper {
    // ......
    
    /**
     * If set, the looper will show a warning log if a message dispatch takes longer than this.
     */
    private long mSlowDispatchThresholdMs;

    /**
     * If set, the looper will show a warning log if a message delivery (actual delivery time -
     * post time) takes longer than this.
     */
    private long mSlowDeliveryThresholdMs;

    /**
     * True if a message delivery takes longer than {@link #mSlowDeliveryThresholdMs}.
     */
    private boolean mSlowDeliveryDetected;

    /**
     * Return the Looper object associated with the current thread.  Returns
     * null if the calling thread is not associated with a Looper.
     */
    public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }

    /**
     * Run the message queue in this thread. Be sure to call
     * {@link #quit()} to end the loop.
     */
    @SuppressWarnings({"UnusedTokenOfOriginalCallingIdentity",
            "ClearIdentityCallNotFollowedByTryFinally",
            "ResultOfClearIdentityCallNotStoredInVariable"})
    public static void loop() {
        final Looper me = myLooper();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        if (me.mInLoop) {
            Slog.w(TAG, "Loop again would have the queued messages be executed"
                    + " before this one completed.");
        }

        me.mInLoop = true;

        // Make sure the identity of this thread is that of the local process,
        // and keep track of what that identity token actually is.
        Binder.clearCallingIdentity();
        final long ident = Binder.clearCallingIdentity();

        // Allow overriding a threshold with a system prop. e.g.
        // adb shell 'setprop log.looper.1000.main.slow 1 && stop && start'
        final int thresholdOverride = getThresholdOverride();

        me.mSlowDeliveryDetected = false;

        for (;;) {    // 这里是消息循环的重点。
            if (!loopOnce(me, ident, thresholdOverride)) {
                return;
            }
        }
    }

    /**
     * 下面整个方法定义中最重要的消息的分发,其他都是与 log 和性能监控有关。
     */
    private static boolean loopOnce(final Looper me,
            final long ident, final int thresholdOverride) {
        Message msg = me.mQueue.next(); // might block   ---> 这里也是接下来分析的重点。
        if (msg == null) {   // 在消息队列中没有需要处理的 message,结束消息循环。
            // No message indicates that the message queue is quitting.
            return false;
        }

        // This must be in a local variable, in case a UI event sets the logger
        final Printer logging = me.mLogging;
        if (logging != null) {
            logging.println(">>>>> Dispatching to " + msg.target + " "
                    + msg.callback + ": " + msg.what);
        }
        // Make sure the observer won't change while processing a transaction.
        final Observer observer = sObserver;

        final long traceTag = me.mTraceTag;
        long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
        long slowDeliveryThresholdMs = me.mSlowDeliveryThresholdMs;

        final boolean hasOverride = thresholdOverride >= 0;
        if (hasOverride) {
            slowDispatchThresholdMs = thresholdOverride;
            slowDeliveryThresholdMs = thresholdOverride;
        }
        final boolean logSlowDelivery = (slowDeliveryThresholdMs > 0 || hasOverride)
                && (msg.when > 0);
        final boolean logSlowDispatch = (slowDispatchThresholdMs > 0 || hasOverride);

        final boolean needStartTime = logSlowDelivery || logSlowDispatch;
        final boolean needEndTime = logSlowDispatch;

        if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
            Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
        }

        final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
        final long dispatchEnd;
        Object token = null;
        if (observer != null) {
            token = observer.messageDispatchStarting();
        }
        long origWorkSource = ThreadLocalWorkSource.setUid(msg.workSourceUid);
        try {
            msg.target.dispatchMessage(msg);   // 向目标 Handler 分发 Message 消息。
            if (observer != null) {
                observer.messageDispatched(token, msg);
            }
            dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
        } catch (Exception exception) {
            if (observer != null) {
                observer.dispatchingThrewException(token, msg, exception);
            }
            throw exception;
        } finally {
            ThreadLocalWorkSource.restore(origWorkSource);
            if (traceTag != 0) {
                Trace.traceEnd(traceTag);
            }
        }
        if (logSlowDelivery) {
            if (me.mSlowDeliveryDetected) {
                if ((dispatchStart - msg.when) <= 10) {
                    Slog.w(TAG, "Drained");
                    me.mSlowDeliveryDetected = false;
                }
            } else {
                if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery",
                        msg)) {
                    // Once we write a slow delivery log, suppress until the queue drains.
                    me.mSlowDeliveryDetected = true;
                }
            }
        }
        if (logSlowDispatch) {
            showSlowLog(slowDispatchThresholdMs, dispatchStart, dispatchEnd, "dispatch", msg);
        }

        if (logging != null) {
            logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
        }

        // Make sure that during the course of dispatching the
        // identity of the thread wasn't corrupted.
        final long newIdent = Binder.clearCallingIdentity();
        if (ident != newIdent) {
            Log.wtf(TAG, "Thread identity changed from 0x"
                    + Long.toHexString(ident) + " to 0x"
                    + Long.toHexString(newIdent) + " while dispatching to "
                    + msg.target.getClass().getName() + " "
                    + msg.callback + " what=" + msg.what);
        }

        msg.recycleUnchecked();

        return true;
    }

    // ......
}
  • myLooper() 尝试获取当前线程绑定的 Looper 对象。若没有找到,表明当前线程没有消息队列和 looper 实例。
  • Binder.clearCallingIdentity() 是在处理一个传入的 Binder 调用时,暂时将当前线程的身份(UID 和 PID)重置为本地进程的身份,以便后续操作能以本地进程的身份进行权限检查。
  • Message msg = me.mQueue.next(); 获取这个 Message 成为了接下来分析的重点。

消息 Message

上面 Looper 的循环,执行到 loopOnce 方法内,第一个步骤是从 MessageQueue 中获取 Message 对象。

// Looper.java
private static boolean loopOnce(final Looper me,
    final long ident, final int thresholdOverride) {
    Message msg = me.mQueue.next(); // might block   ---> 这里也是接下来分析的重点。
    if (msg == null) {   // 在消息队列中没有需要处理的 message,结束消息循环。
        // No message indicates that the message queue is quitting.
        return false;
    }
    // ......
}

主要看 MessageQueue 中的实现

  • enqueueMessage(Message msg, long when) 向消息列表加入 Message —— Handler#sendMessage(Message) 最终调用到的位置。
  • next() 获取要处理的消息 —— 消息循环的第一个步骤就是从消息队列获取消息 Message 对象。

MessageQueue 源码分析

先分析消息链表中添加和获取消息对象的源码。

// ./frameworks/base/core/java/android/os/CombinedMessageQueue/MessageQueue.java
public final class MessageQueue {

    @UnsupportedAppUsage
    Message mMessages;		  // 链表的表头。
    private Message mLast;    // 指向链表的表尾。

    private IdleHandler[] mPendingIdleHandlers;

    @UnsupportedAppUsage
    @SuppressWarnings("unused")
    private long mPtr; // used by native code

    private boolean mQuitting;
    // Indicates whether next() is blocked waiting in pollOnce() with a non-zero timeout.
    private boolean mBlocked;
    
    @RavenwoodRedirect
    private native static long nativeInit();
    @UnsupportedAppUsage
    @RavenwoodRedirect
    private native void nativePollOnce(long ptr, int timeoutMillis); /*non-static for callbacks*/
 
    MessageQueue(boolean quitAllowed) {
        mQuitAllowed = quitAllowed;
        mPtr = nativeInit();      // 调用 native 方法初始化 mPtr.
    }

    boolean enqueueMessage(Message msg, long when) {
        if (msg.target == null) {    // 没有 Handler 处理的 Message 不被接收。这里也是判断屏障消息的标志。
            throw new IllegalArgumentException("Message must have a target.");
        }

        synchronized (this) {    // MessageQueue 被写时保证同步。
            if (msg.isInUse()) {    // 判断 Message 是否正被使用。
                throw new IllegalStateException(msg + " This message is already in use.");
            }

            if (mQuitting) {    // enqueueMessage 时,这个值 false。
                IllegalStateException e = new IllegalStateException(
                        msg.target + " sending message to a Handler on a dead thread");
                Log.w(TAG, e.getMessage(), e);
                msg.recycle();
                return false;
            }

            msg.markInUse();    // 标记 Message 对象正在被使用。
            msg.when = when;
            Message p = mMessages;
            boolean needWake;
            if (p == null || when == 0 || when < p.when) {  // 首次添加时,开始组建 Message 链接的数据结构。
                // New head, wake up the event queue if blocked.
                msg.next = p;
                mMessages = msg;
                needWake = mBlocked;  // 如果之前是阻塞状态,则需要唤醒
                if (p == null) {
                    mLast = mMessages;
                }
            } else {
                // Message is to be inserted at tail or middle of queue. Usually we don't have to
                // wake up the event queue unless there is a barrier at the head of the queue and
                // the message is the earliest asynchronous message in the queue.
                needWake = mBlocked && p.target == null && msg.isAsynchronous();

                // For readability, we split this portion of the function into two blocks based on
                // whether tail tracking is enabled. This has a minor implication for the case
                // where tail tracking is disabled. See the comment below.
                if (Flags.messageQueueTailTracking()) {     // 这个判断条件在构建过程中根据配置生成。
                    if (when >= mLast.when) {    // 时间上后传入的 message 对象。
                        needWake = needWake && mAsyncMessageCount == 0;
                        msg.next = null;    // 在链接中新增 message 对象。
                        mLast.next = msg;
                        mLast = msg;
                    } else {
                        // Inserted within the middle of the queue.
                        Message prev;
                        for (;;) {    // 从表头开始后向查询。
                            prev = p;
                            p = p.next;
                            if (p == null || when < p.when) {
                                break;  // 找到链接最后或者找到时间上的比 when 参数大的 Message 对象节点。按时间排队。
                            }
                            if (needWake && p.isAsynchronous()) {
                                needWake = false;
                            }
                        }  // end for
                        if (p == null) {    // 链接中到 tail 一直没找到,直接在 tail 后边添加。
                            /* Inserting at tail of queue */
                            mLast = msg;
                        }
                        msg.next = p; // invariant: p == prev.next
                        prev.next = msg;
                    }
                } else {
                    Message prev;
                    for (;;) {
                        prev = p;
                        p = p.next;
                        if (p == null || when < p.when) {
                            break;
                        }
                        if (needWake && p.isAsynchronous()) {
                            needWake = false;
                        }
                    }
                    msg.next = p; // invariant: p == prev.next
                    prev.next = msg;

                    /*
                     * If this block is executing then we have a build without tail tracking -
                     * specifically: Flags.messageQueueTailTracking() == false. This is determined
                     * at build time so the flag won't change on us during runtime.
                     *
                     * Since we don't want to pepper the code with extra checks, we only check
                     * for tail tracking when we might use mLast. Otherwise, we continue to update
                     * mLast as the tail of the list.
                     *
                     * In this case however we are not maintaining mLast correctly. Since we never
                     * use it, this is fine. However, we run the risk of leaking a reference.
                     * So set mLast to null in this case to avoid any Message leaks. The other
                     * sites will never use the value so we are safe against null pointer derefs.
                     */
                    mLast = null;
                }
            }

            if (msg.isAsynchronous()) {    // 判定并统计异步消息数量。
                mAsyncMessageCount++;
            }

            // We can assume mPtr != 0 because mQuitting is false.
            if (needWake) {
                nativeWake(mPtr);
            }
        }
        return true;
    }


    @UnsupportedAppUsage
    Message next() {
        // Return here if the message loop has already quit and been disposed.
        // This can happen if the application tries to restart a looper after quit
        // which is not supported.
        final long ptr = mPtr;    // MessageQueue 构造时完成 mPtr 的初始化。
        if (ptr == 0) {
            return null;
        }

        int pendingIdleHandlerCount = -1; // -1 only during first iteration
        int nextPollTimeoutMillis = 0;
        for (;;) {
            if (nextPollTimeoutMillis != 0) {
                Binder.flushPendingCommands();
            }
            
            // 尝试轮询一次。这个 native 调用,当没有消息的时候,当前线程进入休眠状态,出让 CPU 资源。
            // 实现等待和阻塞的真正实现是 native 代码中的 epoll_wait() 系统调用,等待有事件来唤醒线程继续执行。
            nativePollOnce(ptr, nextPollTimeoutMillis);

            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) {    // 当遇到一个屏障消息(Message target=null)。
                    // Stalled by a barrier.  Find the next asynchronous message in the queue.
                    do { // 铆定当前 target=null 的 message,接着往后遍历,找到第一个 asynchronous=true 的 message 对象作优先处理。
                        prevMsg = msg;
                        msg = msg.next;
                    } while (msg != null && !msg.isAsynchronous());
                }
                if (msg != null) {
                    if (now < msg.when) {
                        // Next message is not ready.  Set a timeout to wake up when it is ready.
                        nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                    } else {
                        // Got a message.
                        mBlocked = false;
                        if (prevMsg != null) {  // 当前消息是 屏障消息 时。
                            prevMsg.next = msg.next;
                            if (prevMsg.next == null) {
                                mLast = prevMsg;
                            }
                        } else {
                            mMessages = msg.next;
                            if (msg.next == null) {  // 当前 message 是最后一个节点。
                                mLast = null;
                            }
                        }
                        msg.next = null;  // 从 message 链表中取出 msg 实例。
                        if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                        msg.markInUse();    // 标记 message 对象正在使用标志位 FLAG_IN_USE.
                        if (msg.isAsynchronous()) {
                            mAsyncMessageCount--;
                        }
                        if (TRACE) {
                            Trace.setCounter("MQ.Delivered", mMessagesDelivered.incrementAndGet());
                        }
                        return msg;
                    }
                } else {
                    // No more messages.
                    nextPollTimeoutMillis = -1;
                }

                // Process the quit message now that all pending messages have been handled.
                if (mQuitting) {
                    dispose();
                    return null;
                }

                // 下面开始处理 IdleHandler 对象。
                // If first time idle, then get the number of idlers to run.
                // Idle handles only run if the queue is empty or if the first message
                // in the queue (possibly a barrier) is due to be handled in the future.
                if (pendingIdleHandlerCount < 0
                        && (mMessages == null || now < mMessages.when)) {
                    pendingIdleHandlerCount = mIdleHandlers.size();
                }
                if (pendingIdleHandlerCount <= 0) {
                    // No idle handlers to run.  Loop and wait some more.
                    mBlocked = true;
                    continue;
                }

                if (mPendingIdleHandlers == null) {
                    mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
                }
                mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
            } // end synchronized (this)

            // Run the idle handlers.
            // We only ever reach this code block during the first iteration.
            for (int i = 0; i < pendingIdleHandlerCount; i++) {
                final IdleHandler idler = mPendingIdleHandlers[i];
                mPendingIdleHandlers[i] = null; // release the reference to the handler

                boolean keep = false;
                try {
                    keep = idler.queueIdle();
                } catch (Throwable t) {
                    Log.wtf(TAG, "IdleHandler threw exception", t);
                }

                if (!keep) {
                    synchronized (this) {
                        mIdleHandlers.remove(idler);
                    }
                }
            }

            // Reset the idle handler count to 0 so we do not run them again.
            pendingIdleHandlerCount = 0;

            // While calling an idle handler, a new message could have been delivered
            // so go back and look again for a pending message without waiting.
            nextPollTimeoutMillis = 0;
        } // end for(;;)
    }

}

// ./frameworks/base/core/jni/android_os_MessageQueue.cpp
static jlong android_os_MessageQueue_nativeInit(JNIEnv* env, jclass clazz) {
    NativeMessageQueue* nativeMessageQueue = new NativeMessageQueue();
    if (!nativeMessageQueue) {
        jniThrowRuntimeException(env, "Unable to allocate native queue");
        return 0;
    }

    nativeMessageQueue->incStrong(env);
    return reinterpret_cast<jlong>(nativeMessageQueue);
}

Message 对象可以有

  1. 同步消息——普通任务消息。
  2. 异步消息——asynchronous 属性 true 的消息。
  3. 屏障消息——发生在系统内主线程上,普通 app 不能使用的消息类型。

我们主要需要了解的是屏障消息。


屏障消息

屏障消息的核心是一个 Handlertargetnull 的特殊 Message 对象,它相当于在消息队列中设置了一个路障。当 LooperMessageQueue.next() 中轮询到这个特殊消息时,会识别出它并非需要分发的普通消息,从而触发屏障逻辑 —— Looper 会暂停处理该屏障之后的所有普通消息,转而去寻找并优先处理异步消息(isAsynchronous=true),直到屏障被显式移除


屏障消息与普通消息的区别

下面的表格清晰展示了屏障消息与普通(同步)消息在关键属性上的差异:

特性普通消息 (同步消息)屏障消息 (同步屏障)
关键标识 target持有目标 Handler 的引用 (target != null)targetnull
主要作用携带任务,交由指定 Handler 处理作为一个“路障”,控制消息队列的调度优先级
处理方式Looper 取出,调用 target.dispatchMessage() 处理不被 Looper 直接处理,触发屏障逻辑后,继续遍历队列
创建方式通过 HandlersendMessage 系列方法通过 MessageQueue.postSyncBarrier() 方法(此方法为 @hide,普通应用无法直接调用)

屏障消息发生的线程和场景

消息屏障机制主要发生在主线程 (UI Thread)

在自定义的线程中,即使自定义创建了消息循环,消息屏障也绝不会自动出现。因为 postSyncBarrier() 方法被标记为 @hide,它专供系统内部使用,且主要由 ViewRootImpl 等系统核心组件调用,以确保 UI 绘制等关键任务的优先级。

开发者无法通过常规手段在你的线程中插入屏障消息。

该机制在系统中的核心应用是确保 UI 绘制 的高优先级。其流程如下:

  1. 设置屏障:当一个 View 请求重绘时,ViewRootImpl.scheduleTraversals() 方法会向主线程的消息队列发送一个同步屏障。
  2. 发送异步绘制任务:紧接着,它将一个 UI 绘制任务包装成异步消息投递到消息队列中。
  3. 优先执行:当 Looper 处理到同步屏障时,会跳过所有普通(同步)消息,优先执行到这个异步的绘制任务 (mTraversalRunnable)。
  4. 移除屏障:在绘制任务执行时,首要操作就是移除同步屏障,以恢复消息队列的正常处理顺序。

这个机制确保了 UI 绘制指令能够迅速被处理,避免被其他用户操作或回调产生的普通消息阻塞,从而防止界面卡顿或掉帧。


屏障的添加与移除

添加与移除消息屏障是系统控制的成对操作,以下是其核心步骤:

  1. 添加屏障 (postSyncBarrier)
    MessageQueue.postSyncBarrier() 方法负责插入屏障消息:
    • 创建特殊消息:从消息池中获取 Message 对象。它设置了 when 时间戳,并用 arg1 字段存储一个唯一的 token,但关键之处在于没有设置 target 字段,使其成为一个屏障。
    • 按时间排序:为了不阻塞已到期的任务,屏障消息会根据其 when 值,被插入到消息队列中所有同时刻或更早的消息之后
    • 返回 token:方法最终会返回一个 int 类型的 token,这就像是移除屏障的“钥匙”,必须被妥善保存
  2. 移除屏障 (removeSyncBarrier)
    使用屏障后必须将其移除,否则队列将被永久阻塞,可能引发ANR。MessageQueue.removeSyncBarrier(int token) 方法负责移除操作:
    • 遍历查找:根据传入的 token,在消息队列中遍历查找 targetnullarg1 值匹配的屏障消息。
    • 从链表移除:找到目标后,将其从链表中移除。
    • 按需唤醒:如果当前有线程因屏障而阻塞,移除屏障后可能需要唤醒该线程,以继续处理被搁置的同步消息。

在接下来去分析 native 层的方法和代码逻辑前,也在查看了 native 层代码并对比了 java 层的代码。我们可以了解到的是,native 层和 java 层各有一套 “消息” 机制

java 层定义c++ 层定义
android.os.MessageQueueandroid_os_MessageQueue.cpp#NativeMessageQueue
android.os.LooperLooper.cpp Looper.h
android.os.MessageLooper.h#Message
android.os.HandlerLooper.h#MessageHandler

消息队列(MessageQueue)

MessageQueue 的核心是一个按 when(执行时间)排序的单向链表。它的实现主要围绕三个关键操作:enqueueMessage(入队)、next(出队)和 quit(退出)。

enqueueMessage 入队的核心就是按时间排序的单向链表插入操作,保证了紧急的消息能优先被处理。

next 核心流程要点

  1. 进入阻塞:调用 nativePollOnce,利用 Linux 的 epoll 机制让线程进入休眠,释放 CPU。
  2. 检查同步屏障:在处理消息前,先检查队首是否为屏障(target == null),若是则优先寻找异步消息。
  3. 检查执行时间:若队首消息的 when 未到,则计算等待时长,继续阻塞。
  4. 返回就绪消息:若 when <= now,则将消息从链表中摘除,返回给 Looper

涉及的文件:

  1. Looper.h system/core/libutils/include/utils/Looper.h
  2. android_os_MessageQueue.cpp frameworks/base/core/jni/android_os_MessageQueue.cpp
  3. Looper.cpp system/core/libutils/Looper.cpp

JNI 方法

打开 MessageQueue.java 文件,会发现在 android.os.MessageQueue 包含有若干个 native 的方法定义。

// frameworks/base/core/java/android/os/LegacyMessageQueue/MessageQueue.java
public final class MessageQueue {
    // ...
	@RavenwoodRedirect
    private native static long nativeInit();
    @RavenwoodRedirect
    private native static void nativeDestroy(long ptr);
    @UnsupportedAppUsage
    @RavenwoodRedirect
    private native void nativePollOnce(long ptr, int timeoutMillis); /*non-static for callbacks*/
    @RavenwoodRedirect
    private native static void nativeWake(long ptr);
    @RavenwoodRedirect
    private native static boolean nativeIsPolling(long ptr);
    @RavenwoodRedirect
    private native static void nativeSetFileDescriptorEvents(long ptr, int fd, int events);
	// ...
}

换言之,消息机制中包含有 JNI 调用,发生在 java 虚拟机栈和 native 栈之间(这是 java 运行时内存模型,不了解的可以自己检索)。

java 层的 MessageQueue 类定义的 native 方法,对应地在 native 层的 android_os_MessageQueue.cpp 文件中实现。

// frameworks/base/core/jni/android_os_MessageQueue.cpp
static const JNINativeMethod gMessageQueueMethods[] = {
    /* name, signature, funcPtr */
    { "nativeInit", "()J", (void*)android_os_MessageQueue_nativeInit },
    { "nativeDestroy", "(J)V", (void*)android_os_MessageQueue_nativeDestroy },
    { "nativePollOnce", "(JI)V", (void*)android_os_MessageQueue_nativePollOnce },
    { "nativeWake", "(J)V", (void*)android_os_MessageQueue_nativeWake },
    { "nativeIsPolling", "(J)Z", (void*)android_os_MessageQueue_nativeIsPolling },
    { "nativeSetFileDescriptorEvents", "(JII)V",
            (void*)android_os_MessageQueue_nativeSetFileDescriptorEvents },
};

上面 gMessageQueueMethods[] 数组定义了 java 层定义的 native 方法与 native 层的实现函数之间的映射关系。

下面代码区放置 native 层定义

// frameworks/base/core/jni/android_os_MessageQueue.cpp
// 匿名结构体定义;全局的静态变量。
static struct {
    jfieldID mPtr;   // native object attached to the DVM MessageQueue
    jmethodID dispatchEvents;
} gMessageQueueClassInfo;

class NativeMessageQueue : public MessageQueue, public LooperCallback {
public:
    NativeMessageQueue();
    virtual ~NativeMessageQueue();

    virtual void raiseException(JNIEnv* env, const char* msg, jthrowable exceptionObj);

    void pollOnce(JNIEnv* env, jobject obj, int timeoutMillis);
    void wake();
    void setFileDescriptorEvents(int fd, int events);

    virtual int handleEvent(int fd, int events, void* data);

    /**
     * A simple proxy that holds a weak reference to a looper callback.
     */
    class WeakLooperCallback : public LooperCallback {
    protected:
        virtual ~WeakLooperCallback();

    public:
        WeakLooperCallback(const wp<LooperCallback>& callback);
        virtual int handleEvent(int fd, int events, void* data);

    private:
        wp<LooperCallback> mCallback;
    };

private:
    JNIEnv* mPollEnv;
    jobject mPollObj;
    jthrowable mExceptionObj;
};

// ----------------------------------------------------------------------------

static const JNINativeMethod gMessageQueueMethods[] = {
    /* name, signature, funcPtr */
    { "nativeInit", "()J", (void*)android_os_MessageQueue_nativeInit },
    { "nativeDestroy", "(J)V", (void*)android_os_MessageQueue_nativeDestroy },
    { "nativePollOnce", "(JI)V", (void*)android_os_MessageQueue_nativePollOnce },
    { "nativeWake", "(J)V", (void*)android_os_MessageQueue_nativeWake },
    { "nativeIsPolling", "(J)Z", (void*)android_os_MessageQueue_nativeIsPolling },
    { "nativeSetFileDescriptorEvents", "(JII)V",
            (void*)android_os_MessageQueue_nativeSetFileDescriptorEvents },
};

int register_android_os_MessageQueue(JNIEnv* env) {
    int res = RegisterMethodsOrDie(env, "android/os/MessageQueue", gMessageQueueMethods,
                                   NELEM(gMessageQueueMethods));

    jclass clazz = FindClassOrDie(env, "android/os/MessageQueue");
    gMessageQueueClassInfo.mPtr = GetFieldIDOrDie(env, clazz, "mPtr", "J");
    gMessageQueueClassInfo.dispatchEvents = GetMethodIDOrDie(env, clazz, "dispatchEvents", "(II)I");

    return res;
}
  • gMessageQueueClassInfo 全局变量,它的 jfieldID mPtr 字段引用类 MessageQueue 类定义中的字段 long mPtr 定义。

    gMessageQueueClassInfo.mPtr = GetFieldIDOrDie(env, clazz, "mPtr", "J");
    
  • 同理,gMessageQueueClassInfo 的成员变量 jmethodID dispatchEvents 引用 MessageQueue 的方法 dispatchEvents(int fd, int events)

    private int dispatchEvents(int fd, int events)  // MessageQueue.java
    
     gMessageQueueClassInfo.dispatchEvents = GetMethodIDOrDie(env, clazz, "dispatchEvents", "(II)I");
    

nativeInit()

java 层声明的 native 方法 nativeInit 对应的实现是 android_os_MessageQueue_nativeInit ,它在 java 层 MessageQueue 对象创建时被调用。

// frameworks/base/core/java/android/os/LegacyMessageQueue/MessageQueue.java
public final class MessageQueue {
    // ...
    @UnsupportedAppUsage
    @SuppressWarnings("unused")
    private long mPtr; // used by native code

	@RavenwoodRedirect
    private native static long nativeInit();
    
    MessageQueue(boolean quitAllowed) {
        mQuitAllowed = quitAllowed;
        mPtr = nativeInit();    // 在 c++ 层创建 NativeMessageQueue 对象,并返回其内存地址,赋值给 java 层的 mPtr 变量。
    }

    // ...
}

下面具体看下 nativeInit 的实现。

// frameworks/base/core/jni/android_os_MessageQueue.cpp
static jlong android_os_MessageQueue_nativeInit(JNIEnv* env, jclass clazz) {
    NativeMessageQueue* nativeMessageQueue = new NativeMessageQueue();    // 对内存创建 NativeMessageQueue 对象。
    if (!nativeMessageQueue) {
        jniThrowRuntimeException(env, "Unable to allocate native queue");
        return 0;
    }

    nativeMessageQueue->incStrong(env);  // 对象增加一次强引用计数。
    return reinterpret_cast<jlong>(nativeMessageQueue);
}

这个函数的实现中,

  1. 在 c++ 层堆内存中创建 NativeMessageQueue 对象。
  2. 判断是否创建成功,创建失败抛出 java 层异常。
  3. 增加 NativeMessageQueue 对象的强引用计数。
  4. 返回 c++ 层 nativeMessageQueue 对象的地址给 java 层的 mPtr 待用。

具体看下 NativeMessageQueue()构造 内的执行逻辑。

// frameworks/base/core/jni/android_os_MessageQueue.cpp
NativeMessageQueue* nativeMessageQueue = new NativeMessageQueue();  // android_os_MessageQueue_nativeInit()

NativeMessageQueue::NativeMessageQueue() :
        mPollEnv(NULL), mPollObj(NULL), mExceptionObj(NULL) {  // NativeMessageQueue 字段赋 NULL
    mLooper = Looper::getForThread();  // 获取当前线程的 Looper 对象。
    if (mLooper == NULL) {  // 假设上面获取失败,直接创建一个 Looper 对象,并绑定到当前线程。
        mLooper = new Looper(false);  // 创建 Looper实例。看下面的 Looper 构造实现。
        Looper::setForThread(mLooper);
    }
}


// system/core/libutils/include/utils/Looper.h
class Looper : public RefBase {
// ...
private: 
    Mutex mLock;

    android::base::unique_fd mWakeEventFd;  // immutable

    android::base::unique_fd mEpollFd;  // guarded by mLock but only modified on the looper thread
// ...
}


// system/core/libutils/Looper.cpp
thread_local static sp<Looper> gThreadLocalLooper;

Looper::Looper(bool allowNonCallbacks)
    : mAllowNonCallbacks(allowNonCallbacks),
      mSendingMessage(false),
      mPolling(false),
      mEpollRebuildRequired(false),
      mNextRequestSeq(WAKE_EVENT_FD_SEQ + 1),
      mResponseIndex(0),
      mNextMessageUptime(LLONG_MAX) {

    mWakeEventFd.reset(eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC));
    // 判断 fd 函数的返回是否大于 0,若小于 0,则错误返回。
    LOG_ALWAYS_FATAL_IF(mWakeEventFd.get() < 0, "Could not make wake event fd: %s", strerror(errno));

    AutoMutex _l(mLock); 
    rebuildEpollLocked();   // 加锁执行
}

Looper::~Looper() {
}

void Looper::setForThread(const sp<Looper>& looper) {
    gThreadLocalLooper = looper;
}

void Looper::rebuildEpollLocked() {
    // Close old epoll instance if we have one.
    if (mEpollFd >= 0) {
#if DEBUG_CALLBACKS
        ALOGD("%p ~ rebuildEpollLocked - rebuilding epoll set", this);
#endif
        mEpollFd.reset();  // 如果有旧的 epoll 实例 --> 清理资源。
    }

    // Allocate the new epoll instance and register the WakeEventFd.
    mEpollFd.reset(epoll_create1(EPOLL_CLOEXEC));  // 新建 epoll 实例。
    LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance: %s", strerror(errno));
    
    // 新建 epoll 事件 epoll_event 结构体,这个结构体是在内核定义。
    epoll_event wakeEvent = createEpollEvent(EPOLLIN, WAKE_EVENT_FD_SEQ);
    // 将唤醒事件 fd 注册到 epoll 实例,即 epoll 内有事件到达,需要唤醒线程,通过唤醒事件 fd 通知。
    int result = epoll_ctl(mEpollFd.get(), EPOLL_CTL_ADD, mWakeEventFd.get(), &wakeEvent);
    LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake event fd to epoll instance: %s",
                        strerror(errno));

    // 将原来内部的 mRequests 内的事件,注册到新 epoll 实例 mEpollFd 上。
    for (const auto& [seq, request] : mRequests) {
        epoll_event eventItem = createEpollEvent(request.getEpollEvents(), seq);

        int epollResult = epoll_ctl(mEpollFd.get(), EPOLL_CTL_ADD, request.fd, &eventItem);
        if (epollResult < 0) {
            ALOGE("Error adding epoll events for fd %d while rebuilding epoll set: %s",
                  request.fd, strerror(errno));
        }
    }
}

  1. Looper 实例创建时,给各字段赋值。

  2. eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC) 系统调用,创建一个 fd 实例,返回一个非负整数(即文件描述符)。—— 此部分知识来自 AI

    • 参数 0 表示初始化值 —— eventfd 内部维护一个 64 位计数器。
    • EFD_NONBLOCK 设置文件描述符为非阻塞模式。 当对该 fd 进行 read() 操作且计数器为 0 时,不会阻塞线程,而是立即返回 EAGAIN 错误。这对于事件循环至关重要,防止主线程被卡死。
    • EFD_CLOEXEC 设置执行 exec 族函数时自动关闭该 fd。防止子进程继承这个无用的 fd,避免资源泄漏(这是安全编程的标准实践)。
  3. mWakeEventFd.reset(..); 将新建的 fd 实例封装成为 RAII 对象(自动管理对象的生命周期)。mWakeEventFd 声明的类型是

    // system/core/libutils/include/utils/Looper.h
    android::base::unique_fd mWakeEventFd;
    
  4. rebuildEpollLocked() 实现作了几件事情。

    • 假设 mEpollFd 引用有旧的 epoll 实例,进行资源清理。
    • epoll_create1 新建 epoll 实例, createEpollEvent 新建 epoll_event 结构体变量。
    • 将唤醒事件 fd 文件描述符添加到 mEpollFd 实例, epoll_ctl 将 epoll 实例注册到内核。

到此,nativeInit 函数的执行逻辑就差不多分析结束了。

loop()

nativeInit() 执行完成后

  1. 新建消息机制需要的 java 层和 native 层的 looper, message queue 等对象。
  2. looper 绑定到了当前的线程。

紧接着,消息队列需要进入一个无限循环,等待消息到来的状态。

我们以主线程启动为例,查看它在启动是准备消息队列的源码。

public final class ActivityThread extends ClientTransactionHandler
        implements ActivityThreadInternal {
    // ...

    public static void main(String[] args) {
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
        // ...
        // Call per-process mainline module initialization.
        initializeMainlineModules();

        Looper.prepareMainLooper();  // 主线程启动,初始化消息机制。
        // ...

        // End of event ActivityThreadMain.
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        Looper.loop();  // 开始消息循环,也是这段主要分析的方法。

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

// ...
}

下来看下 loop() 的定义。

// frameworks/base/core/java/android/os/Looper.java
/**
 * Poll and deliver single message, return true if the outer loop should continue.
 */
private static boolean loopOnce(final Looper me,
        final long ident, final int thresholdOverride) {
    Message msg = me.mQueue.next(); // 这里是关键,从 java 层的消息队列去获取消息。
    if (msg == null) {
        // No message indicates that the message queue is quitting.
        return false;
    }

    // 因为关键关注消息的发送,获取和处理,因此这里的代码不完整贴出。
    // ...

    return true;
}


/**
 * Run the message queue in this thread. Be sure to call
 * {@link #quit()} to end the loop.
 */
public static void loop() {  // 消息队列循环入口。
    final Looper me = myLooper();  // 获取当前线程上的 looper。
    if (me == null) {
        throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
    }
    if (me.mInLoop) {
        Slog.w(TAG, "Loop again would have the queued messages be executed"
                + " before this one completed.");
    }

    me.mInLoop = true;

    // ...

    for (;;) {  // 执行一个无限循环。
        if (!loopOnce(me, ident, thresholdOverride)) {  //  loopOnce 方法的执行是单词的获取消息。
            return;
        }
    }
}


// frameworks/base/core/java/android/os/LegacyMessageQueue/MessageQueue.java
// 从 Looper#loopOnce 中调用 next() 方法,试图获取消息。
@UnsupportedAppUsage
Message next() {
    // Return here if the message loop has already quit and been disposed.
    // This can happen if the application tries to restart a looper after quit
    // which is not supported.
    final long ptr = mPtr;
    if (ptr == 0) {
        return null;
    }

    int pendingIdleHandlerCount = -1; // -1 only during first iteration
    int nextPollTimeoutMillis = 0;
    for (;;) {  // 进入到消息的无限循环。
        if (nextPollTimeoutMillis != 0) {
            Binder.flushPendingCommands();
        }

        nativePollOnce(ptr, nextPollTimeoutMillis);  // 调用到 native 层方法 nativePollOnce()。这里可能发生阻塞。

        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) {
                    // Next message is not ready.  Set a timeout to wake up when it is ready.
                    nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                } else {
                    // Got a message.
                    mBlocked = false;
                    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;
                    if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                    msg.markInUse();
                    if (msg.isAsynchronous()) {
                        mAsyncMessageCount--;
                    }
                    if (TRACE) {
                        Trace.setCounter("MQ.Delivered", mMessagesDelivered.incrementAndGet());
                    }
                    return msg;
                }
            } else {
                // No more messages.
                nextPollTimeoutMillis = -1;
            }

            // Process the quit message now that all pending messages have been handled.
            if (mQuitting) {
                dispose();
                return null;
            }

            // If first time idle, then get the number of idlers to run.
            // Idle handles only run if the queue is empty or if the first message
            // in the queue (possibly a barrier) is due to be handled in the future.
            if (pendingIdleHandlerCount < 0
                    && (mMessages == null || now < mMessages.when)) {
                pendingIdleHandlerCount = mIdleHandlers.size();
            }
            if (pendingIdleHandlerCount <= 0) {
                // No idle handlers to run.  Loop and wait some more.
                mBlocked = true;
                continue;
            }

            if (mPendingIdleHandlers == null) {
                mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
            }
            mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
        }

        // Run the idle handlers.
        // We only ever reach this code block during the first iteration.
        for (int i = 0; i < pendingIdleHandlerCount; i++) {
            final IdleHandler idler = mPendingIdleHandlers[i];
            mPendingIdleHandlers[i] = null; // release the reference to the handler

            boolean keep = false;
            try {
                keep = idler.queueIdle();
            } catch (Throwable t) {
                Log.wtf(TAG, "IdleHandler threw exception", t);
            }

            if (!keep) {
                synchronized (this) {
                    mIdleHandlers.remove(idler);
                }
            }
        }

        // Reset the idle handler count to 0 so we do not run them again.
        pendingIdleHandlerCount = 0;

        // While calling an idle handler, a new message could have been delivered
        // so go back and look again for a pending message without waiting.
        nextPollTimeoutMillis = 0;
    }  // end for
}

// frameworks/base/core/jni/android_os_MessageQueue.cpp
NativeMessageQueue::NativeMessageQueue() :
        mPollEnv(NULL), mPollObj(NULL), mExceptionObj(NULL) {  // NativeMessageQueue 字段赋 NULL
    mLooper = Looper::getForThread();  // 获取当前线程的 Looper 对象。
    if (mLooper == NULL) {  // 假设上面获取失败,直接创建一个 Looper 对象,并绑定到当前线程。
        mLooper = new Looper(false);  // 创建 Looper实例。看下面的 Looper 构造实现。
        Looper::setForThread(mLooper);
    }
}

static void android_os_MessageQueue_nativePollOnce(JNIEnv* env, jobject obj,
        jlong ptr, jint timeoutMillis) {
    NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
    nativeMessageQueue->pollOnce(env, obj, timeoutMillis);
}

void NativeMessageQueue::pollOnce(JNIEnv* env, jobject pollObj, int timeoutMillis) {
    mPollEnv = env;
    mPollObj = pollObj;
    mLooper->pollOnce(timeoutMillis);  // 调用到 looper 的 pollOnce 方法。
    mPollObj = NULL;
    mPollEnv = NULL;

    if (mExceptionObj) {
        env->Throw(mExceptionObj);
        env->DeleteLocalRef(mExceptionObj);
        mExceptionObj = NULL;
    }
}
// system/core/libutils/include/utils/Looper.h, system/core/libutils/Looper.cpp
int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
    int result = 0;
    for (;;) {
        while (mResponseIndex < mResponses.size()) {
            const Response& response = mResponses.itemAt(mResponseIndex++);
            int ident = response.request.ident;
            if (ident >= 0) {
                int fd = response.request.fd;
                int events = response.events;
                void* data = response.request.data;
#if DEBUG_POLL_AND_WAKE
                ALOGD("%p ~ pollOnce - returning signalled identifier %d: "
                        "fd=%d, events=0x%x, data=%p",
                        this, ident, fd, events, data);
#endif
                if (outFd != nullptr) *outFd = fd;
                if (outEvents != nullptr) *outEvents = events;
                if (outData != nullptr) *outData = data;
                return ident;
            }
        }

        if (result != 0) {
#if DEBUG_POLL_AND_WAKE
            ALOGD("%p ~ pollOnce - returning result %d", this, result);
#endif
            if (outFd != nullptr) *outFd = 0;
            if (outEvents != nullptr) *outEvents = 0;
            if (outData != nullptr) *outData = nullptr;
            return result;
        }

        result = pollInner(timeoutMillis);
    }
}

int Looper::pollInner(int timeoutMillis) {
#if DEBUG_POLL_AND_WAKE
    ALOGD("%p ~ pollOnce - waiting: timeoutMillis=%d", this, timeoutMillis);
#endif

    // Adjust the timeout based on when the next message is due.
    if (timeoutMillis != 0 && mNextMessageUptime != LLONG_MAX) {
        nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
        int messageTimeoutMillis = toMillisecondTimeoutDelay(now, mNextMessageUptime);
        if (messageTimeoutMillis >= 0
                && (timeoutMillis < 0 || messageTimeoutMillis < timeoutMillis)) {
            timeoutMillis = messageTimeoutMillis;
        }
#if DEBUG_POLL_AND_WAKE
        ALOGD("%p ~ pollOnce - next message in %" PRId64 "ns, adjusted timeout: timeoutMillis=%d",
                this, mNextMessageUptime - now, timeoutMillis);
#endif
    }

    // Poll.
    int result = POLL_WAKE;
    mResponses.clear();
    mResponseIndex = 0;

    // We are about to idle.
    mPolling = true;

    struct epoll_event eventItems[EPOLL_MAX_EVENTS];
    // 调用 epoll_wait 使得线程进入休眠。
    int eventCount = epoll_wait(mEpollFd.get(), eventItems, EPOLL_MAX_EVENTS, timeoutMillis);

    // No longer idling.
    mPolling = false;

    // Acquire lock.
    mLock.lock();

    // ...  执行后续操作。
    return result;
}

java 层开始 loop() —> 调用到 native 层的 nativePollOnce() 函数。

nativePollOnce() —— loop() 无限循环,线程阻塞

这个函数定义在 frameworks/base/core/jni/android_os_MessageQueue.cpp 文件中,函数签名 android_os_MessageQueue_nativePollOnce(JNIEnv* env, jobject obj, jlong ptr, jint timeoutMillis)。 在函数内部的步骤比较简单。

  1. mPtr 传入的值(对应参数 ptr)强制转换成 native 层的 NativeMessageQueue 结构体类型。

  2. 调用 NativeMessageQueue 的方法 pollOnce

  3. nativePollOnce() —> 调用 Looper.cpp 内的 pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) 方法。

  4. LooperpollOnce 实现内也进入到无限循环。

  5. 当程序执行到 Looper::pollInner(int timeoutMillis) 内的 epoll_wait 函数

    // system/core/libutils/Looper.cpp
    struct epoll_event eventItems[EPOLL_MAX_EVENTS];
    int eventCount = epoll_wait(mEpollFd.get(), eventItems, EPOLL_MAX_EVENTS, timeoutMillis);
    

    如果 fd 中没有消息时,线程进入睡眠状态。当有消息时,epoll_wait 在这里返回。

nativeWake() —— 有消息时,线程被唤醒

Handler 发送消息进入消息队列。当 Java 层的 sendMessage(Message) 执行到 MessageQueue#enqueueMessage(Message, long)

// frameworks/base/core/java/android/os/Handler.java
// 执行入口。
public final boolean sendMessage(@NonNull Message msg) {
    return sendMessageDelayed(msg, 0);
}

// 多个调用后,将消息放入到消息队列
private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
        long uptimeMillis) {
    msg.target = this;
    msg.workSourceUid = ThreadLocalWorkSource.getUid();

    if (mAsynchronous) {
        msg.setAsynchronous(true);
    }
    return queue.enqueueMessage(msg, uptimeMillis);
}

// frameworks/base/core/java/android/os/LegacyMessageQueue/MessageQueue.java
boolean enqueueMessage(Message msg, long when) {
    if (msg.target == null) {
        throw new IllegalArgumentException("Message must have a target.");
    }

    synchronized(this) {
		// 将消息放入到消息队列 ...
        
        // We can assume mPtr != 0 because mQuitting is false.
        if (needWake) {
            nativeWake(mPtr);
        }
    }
    return true;
}

有了消息后,调用 nativeWake(mPtr) 执行 native 代码。

// frameworks/base/core/jni/android_os_MessageQueue.cpp
static void android_os_MessageQueue_nativeWake(JNIEnv* env, jclass clazz, jlong ptr) {
    NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
    nativeMessageQueue->wake();
}

void NativeMessageQueue::wake() {
    mLooper->wake();
}

// system/core/libutils/Looper.cpp
void Looper::wake() {
#if DEBUG_POLL_AND_WAKE
    ALOGD("%p ~ wake", this);
#endif

    uint64_t inc = 1;
    // 写 eventfd 文件。
    ssize_t nWrite = TEMP_FAILURE_RETRY(write(mWakeEventFd.get(), &inc, sizeof(uint64_t)));
    if (nWrite != sizeof(uint64_t)) {
        if (errno != EAGAIN) {
            LOG_ALWAYS_FATAL("Could not write wake signal to fd %d (returned %zd): %s",
                             mWakeEventFd.get(), nWrite, strerror(errno));
        }
    }
}

  • 系统调用 write() 将值 1 写入到 eventfd 文件。它的定义在 bionic/libc/include/unistd.h 路径中。
// bionic/libc/include/unistd.h
/**
 * [read(2)](https://man7.org/linux/man-pages/man2/read.2.html) reads
 * up to `__count` bytes from file descriptor `__fd` into `__buf`.
 *
 * Note: `__buf` is not normally nullable, but may be null in the
 * special case of a zero-length read(), which while not generally
 * useful may be meaningful to some device drivers.
 *
 * Returns the number of bytes read on success, and returns -1 and sets `errno` on failure.
 */
ssize_t read(int __fd, void* __BIONIC_COMPLICATED_NULLNESS __buf, size_t __count);

/**
 * [write(2)](https://man7.org/linux/man-pages/man2/write.2.html) writes
 * up to `__count` bytes to file descriptor `__fd` from `__buf`.
 *
 * Note: `__buf` is not normally nullable, but may be null in the
 * special case of a zero-length write(), which while not generally
 * useful may be meaningful to some device drivers.
 *
 * Returns the number of bytes written on success, and returns -1 and sets `errno` on failure.
 */
ssize_t write(int __fd, const void* __BIONIC_COMPLICATED_NULLNESS __buf, size_t __count);
  • 当有 epoll 事件消息值写入 eventfd 文件,在线程睡眠位置的 epoll_wait() 处,程序调用处返回。

在返回后,在函数 Looper::pollOnce 中返回后会调用到

// system/core/libutils/Looper.cpp
int Looper::pollInner(int timeoutMillis) {

    // ...
    int eventCount = epoll_wait(mEpollFd.get(), eventItems, EPOLL_MAX_EVENTS, timeoutMillis);

    // ...
    for (int i = 0; i < eventCount; i++) {
        const SequenceNumber seq = eventItems[i].data.u64;
        uint32_t epollEvents = eventItems[i].events;
        if (seq == WAKE_EVENT_FD_SEQ) {
            if (epollEvents & EPOLLIN) {
                awoken();  // epoll 事件写入。
            } else {
                ALOGW("Ignoring unexpected epoll events 0x%x on wake event fd.", epollEvents);
            }
        } else {
            const auto& request_it = mRequests.find(seq);
            if (request_it != mRequests.end()) {
                const auto& request = request_it->second;
                int events = 0;
                if (epollEvents & EPOLLIN) events |= EVENT_INPUT;
                if (epollEvents & EPOLLOUT) events |= EVENT_OUTPUT;
                if (epollEvents & EPOLLERR) events |= EVENT_ERROR;
                if (epollEvents & EPOLLHUP) events |= EVENT_HANGUP;
                mResponses.push({.seq = seq, .events = events, .request = request});
            } else {
                ALOGW("Ignoring unexpected epoll events 0x%x for sequence number %" PRIu64
                      " that is no longer registered.",
                      epollEvents, seq);
            }
        }
    }
    
    // ...
    return result;
}

void Looper::awoken() {
#if DEBUG_POLL_AND_WAKE
    ALOGD("%p ~ awoken", this);
#endif

    uint64_t counter;
    TEMP_FAILURE_RETRY(read(mWakeEventFd.get(), &counter, sizeof(uint64_t)));
}
  • 读取到 eventfd 文件中的值,继续后续的处理。

nativeDestroy(long ptr)

还以主线程为例

// frameworks/base/core/java/android/app/ActivityThread.java
public final class ActivityThread extends ClientTransactionHandler
        implements ActivityThreadInternal {
    // ...

    public static void main(String[] args) {
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
        // ...

        Looper.prepareMainLooper();  // 主线程启动,初始化消息机制。
        // ...

        // End of event ActivityThreadMain.
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        Looper.loop();  // 开始消息循环,也是这段主要分析的方法。

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

// ...
}

// frameworks/base/core/java/android/os/Looper.java
public final class Looper {
    private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(quitAllowed));
    }

    /**
     * Initialize the current thread as a looper, marking it as an
     * application's main looper. See also: {@link #prepare()}
     *
     * @deprecated The main looper for your application is created by the Android environment,
     *   so you should never need to call this function yourself.
     */
    @Deprecated
    public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }

    private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);  // 主线程的 MesasgeQueue 构造时传入的 false 值。
        mThread = Thread.currentThread();
    }
}

// frameworks/base/core/java/android/os/LegacyMessageQueue/MessageQueue.java
public final class MessageQueue {
    MessageQueue(boolean quitAllowed) {
        mQuitAllowed = quitAllowed;
        mPtr = nativeInit();
    }

    @UnsupportedAppUsage
    Message next() {
		// ..
        for (;;) {
        	if (nextPollTimeoutMillis != 0) {
                Binder.flushPendingCommands();
            }

            nativePollOnce(ptr, nextPollTimeoutMillis);

            synchronized (this) {
                // Try to retrieve the next message.  Return if found.
                final long now = SystemClock.uptimeMillis();
                Message prevMsg = null;
                Message msg = mMessages;
                // 屏障消息处理和普通消息处理 ...
                // Process the quit message now that all pending messages have been handled.
                if (mQuitting) {
                    dispose();
                    return null;
                }

                // ...
                
            }
        } // end for
    }

    boolean enqueueMessage(Message msg, long when) {
        if (msg.target == null) {
            throw new IllegalArgumentException("Message must have a target.");
        }

        synchronized (this) {
            // ...
            if (mQuitting) {
                IllegalStateException e = new IllegalStateException(
                        msg.target + " sending message to a Handler on a dead thread");
                Log.w(TAG, e.getMessage(), e);
                msg.recycle();
                return false;
            }

            // ...
        }
    }
    
    void quit(boolean safe) {
        if (!mQuitAllowed) {
            throw new IllegalStateException("Main thread not allowed to quit.");
        }

        synchronized (this) {
            if (mQuitting) {
                return;
            }
            mQuitting = true;

            if (safe) {
                removeAllFutureMessagesLocked();
            } else {
                removeAllMessagesLocked();
            }

            // We can assume mPtr != 0 because mQuitting was previously false.
            nativeWake(mPtr);
        }
    }
    
    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.
        synchronized (this) {
            // ....

            // If the loop is quitting then it is already awake.
            // We can assume mPtr != 0 when mQuitting is false.
            if (needWake && !mQuitting) {
                nativeWake(mPtr);
            }
        }
    }


    @Override
    protected void finalize() throws Throwable {
        try {
            dispose();
        } finally {
            super.finalize();
        }
    }
    
    // Disposes of the underlying message queue.
    // Must only be called on the looper thread or the finalizer.
    private void dispose() {
        if (mPtr != 0) {
            nativeDestroy(mPtr);  // 将 NativeMessageQueue 的地址传入。
            mPtr = 0;
        }
    }
}
  • mQuitAllowed —— 是否允许退出
    1. 创建 Looper 对象时,调用了 prepare(false),进而最终 new Looper(quitAllowed),这里的参数 quiAllowedfalse 值。
    2. MessageQueue 构造函数 mQuitAllowed (是否允许退出)赋值 false
      • quit(boolean safe) 首先判断 mQuitAllowed
      • 结论:主线程不能退出消息机制(自线程中的 mQuitAllowed 值是 false)。
  • mQuitting —— 正在退出的状态
    1. mQuitting 值的修改在 quit(boolean safe) 中修改,标记正在退出。
    2. MessageQueue.next() 无限循环中,判断 mQuitting 值,如果是 true 则退出循环。
    3. enqueueMessage(Message, long) 判断 mQuitting,当正处在退出状态下,禁止新消息进入消息队列。
    4. removeSyncBarrier(int) 判断 mQutting 值,当正在退出时,不需要唤醒线程。

上面分析的是消息队列退出,或者是否允许退出消息循环的处理情况,下面细节分析下退出的方法 dispose()

方法定义比较简单,当 mPtr 值不为0 值,传入 nativeDestroy(long) 方法。

// frameworks/base/core/jni/android_os_MessageQueue.cpp
static void android_os_MessageQueue_nativeDestroy(JNIEnv* env, jclass clazz, jlong ptr) {
    NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
    nativeMessageQueue->decStrong(env);
}

调用 NativeMessageQueuedecStrong() 方法进行引用计数计算。

native 层的 NativeMessageQueue 基于引用计数的方式创建和销毁。

android_os_MessageQueue_nativeDestroy 调用 decStrong()android_os_MessageQueue_nativeInit 调用的 incStrong,这两个定义来自 RefBase.h

// system/core/libutils/include/utils/RefBase.h  --->  函数定义
class RefBase
{
public:
            void            incStrong(const void* id) const;
            void            incStrongRequireStrong(const void* id) const;
            void            decStrong(const void* id) const;
    
            void            forceIncStrong(const void* id) const;

            //! DEBUGGING ONLY: Get current strong ref count.
            int32_t         getStrongCount() const;

    // ....
}

// system/core/libutils/binder/RefBase.cpp  --->  函数实现
void RefBase::incStrong(const void* id) const
{
    weakref_impl* const refs = mRefs;
    refs->incWeak(id);

    refs->addStrongRef(id);
    const int32_t c = refs->mStrong.fetch_add(1, std::memory_order_relaxed);
    ALOG_ASSERT(c > 0, "incStrong() called on %p after last strong ref", refs);
#if PRINT_REFS
    ALOGD("incStrong of %p from %p: cnt=%d\n", this, id, c);
#endif
    if (c != INITIAL_STRONG_VALUE)  {
        return;
    }

    check_not_on_stack(this);

    int32_t old __unused = refs->mStrong.fetch_sub(INITIAL_STRONG_VALUE, std::memory_order_relaxed);
    // A decStrong() must still happen after us.
    ALOG_ASSERT(old > INITIAL_STRONG_VALUE, "0x%x too small", old);
    refs->mBase->onFirstRef();
}

void RefBase::decStrong(const void* id) const
{
    weakref_impl* const refs = mRefs;
    refs->removeStrongRef(id);
    const int32_t c = refs->mStrong.fetch_sub(1, std::memory_order_release);
#if PRINT_REFS
    ALOGD("decStrong of %p from %p: cnt=%d\n", this, id, c);
#endif
    LOG_ALWAYS_FATAL_IF(BAD_STRONG(c), "decStrong() called on %p too many times",
            refs);
    if (c == 1) {
        std::atomic_thread_fence(std::memory_order_acquire);
        refs->mBase->onLastStrongRef(id);
        int32_t flags = refs->mFlags.load(std::memory_order_relaxed);
        if ((flags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
            delete this;
            // The destructor does not delete refs in this case.
        }
    }
    // Note that even with only strong reference operations, the thread
    // deallocating this may not be the same as the thread deallocating refs.
    // That's OK: all accesses to this happen before its deletion here,
    // and all accesses to refs happen before its deletion in the final decWeak.
    // The destructor can safely access mRefs because either it's deleting
    // mRefs itself, or it's running entirely before the final mWeak decrement.
    //
    // Since we're doing atomic loads of `flags`, the static analyzer assumes
    // they can change between `delete this;` and `refs->decWeak(id);`. This is
    // not the case. The analyzer may become more okay with this patten when
    // https://bugs.llvm.org/show_bug.cgi?id=34365 gets resolved. NOLINTNEXTLINE
    refs->decWeak(id);
}

至此,android Handler 消息机制的基本分析结束。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Zen@sz

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值