MessageQueue.java源码分析

 前一篇文章Looper.java分析中已经提到mq实际上初始化nativeInit的是一个c的实例NativeMessageQueue,并将其指针reinterpret_cast(nativeMessageQueue)保存在mPtr中

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

可以看到mPtr在java层中完全没有逻辑处理,用且仅用于回传给native层的这几个函数

    private native static void nativeDestroy(long ptr);
    private native void nativePollOnce(long ptr, int timeoutMillis); /*non-static for callbacks*/
    private native static void nativeWake(long ptr);
    private native static boolean nativeIsPolling(long ptr);
    private native static void nativeSetFileDescriptorEvents(long ptr, int fd, int events);

通常使用Handler中发送消息使用的sendMsg等等方法调用的enqueueMessage

    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this; //msg的target设置自己,方便回调
        if (mAsynchronous) {
            msg.setAsynchronous(true); //注意这里根据Handler的构造属性设置同步属性
			//缺省handler构造的async是false,也就是说入列的是同步消息
        }
        return queue.enqueueMessage(msg, uptimeMillis); //实际是代理调用MessageQueue的enqueueMessage
    }

这里的入列函数是MessageQueue的核心函数之一

    boolean enqueueMessage(Message msg, long when) {
        if (msg.target == null) {//msg的target就是用于回调的handler,enqueueMessage是暴露给用户的Api,如果不能回调(就无意义了)所以抛异常
            throw new IllegalArgumentException("Message must have a target.");//但target不是不可以为空,那是给系统用的,系统会把生成target
//为空的message作为SyncBarrier,这个屏障做什么用呢? 用作需要垂直同步时 优先刷新UI
        }
        if (msg.isInUse()) {
            throw new IllegalStateException(msg + " This message is already in use.");
        }

        synchronized (this) {
            if (mQuitting) { //状态受quit(boolean safe)函数控制,若已经退出Looper的线程,不再处理msg,并打印日志
                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(); //标记msg的标志位FLAG_IN_USE
            msg.when = when;
            Message p = mMessages;
            boolean needWake;
            if (p == null || when == 0 || when < p.when) { //如果当前队列中没有Message 或者when比原来即将执行的mMessages还要早,那把msg做链表头
                // New head, wake up the event queue if blocked.
                msg.next = p;
                mMessages = msg;
                needWake = mBlocked; //该标志位标志队列中没有马上执行的msg且没有idleHandler
            } else { //当插入的不是头部时,需要考虑的是这个头部如果是个屏障barrier,而插入的msg是实际上异步消息中最新需要处理的那个,
                //就需要调用epoll的唤醒了
                // Inserted within the middle of the 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();
                Message prev;
                for (;;) {
                    prev = p;
                    p = p.next;
                    if (p == null || when < p.when) { //从头部开始遍历每个处理时间在插入msg之前的
                        break;
                    }
                    if (needWake && p.isAsynchronous()) { //如果有处理时间在插入msg之前,并且也是异步的消息,那就老实等着吧
                        needWake = false;
                    }
                }
                msg.next = p; // invariant: p == prev.next //按照when升序插在链表合适的位置
                prev.next = msg;
            }

            // We can assume mPtr != 0 because mQuitting is false.
            if (needWake) {
                nativeWake(mPtr);
            }
        }
        return true;
    }
Message中有asynchronous属性,这里有大量的使用——可以跨过SyncBarrier! 源码注释定义这个属性:
Sets whether the message is asynchronous, meaning that it is not subject to {@link Looper} synchronization barriers.
Certain operations, such as view invalidation, may introduce synchronization barriers into the {@link Looper}'s message queue to prevent subsequent messages from being delivered until some condition is met.  In the case of view invalidation, messages which are posted after a call to {@link android.view.View#invalidate} are suspended by means of a synchronization barrier until the next frame is ready to be drawn.  The synchronization barrier ensures that the invalidation request is completely handled before resuming.
Asynchronous messages are exempt from synchronization barriers.  They typically represent interrupts, input events, and other signals that must be handled independently even while other work has been suspended.
Note that asynchronous messages may be delivered out of order with respect to synchronous messages although they are always delivered in order among themselves.
If the relative order of these messages matters then they probably should not be asynchronous in the first place.  Use with caution.

设置消息是否是异步的,这意味着它不受Looper同步障碍的限制。(异步的正常执行,同步的被阻碍)
某些操作,如视图的失效,可能会在Looper的消息队列中引入同步屏障,以防止后续消息被传递,直到满足某些条件为止。在视图失效的情况下,在调用View#invalidate后发布的消息会被挂起(通过同步屏障),直到下一个帧准备就绪为止。同步障碍确保在恢复之前完全处理无效请求。
异步消息可以免除同步障碍。它们通常表示中断、输入事件和其他必须独立处理的信号,甚至在其他工作被暂停的情况下。
注意,异步消息可能会在同步消息中被发送,尽管它们总是以顺序传递。
如果这些消息的相对顺序很重要,那么它们在一开始就不应该是异步的。谨慎使用

所以当插入异步msg时,需要要唤醒,
我们知道视图的解析、测量、布局是直接控制在ViewRootImpl中的。这个机制保证了scheduleTraversal之后,停止处理同步消息,只会处理异步消息,保证用户体验,减少ANR。

    void scheduleTraversals() {
        if (!mTraversalScheduled) {
            mTraversalScheduled = true;
            mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
            mChoreographer.postCallback(
                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
            if (!mUnbufferedInputDispatch) {
                scheduleConsumeBatchedInput();
            }
            notifyRendererOfFramePending();
            pokeDrawLockIfNeeded();
        }
    }

    void unscheduleTraversals() {
        if (mTraversalScheduled) {
            mTraversalScheduled = false;
            mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
            mChoreographer.removeCallbacks(
                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
        }
    }

    void doTraversal() {
        if (mTraversalScheduled) {
            mTraversalScheduled = false;
            mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);

            if (mProfile) {
                Debug.startMethodTracing("ViewAncestor");
            }

            performTraversals();

            if (mProfile) {
                Debug.stopMethodTracing();
                mProfile = false;
            }
        }
    }

实际上MessageQueue的源码一直在变化的,2.3才加入了native层的Message,在4.0.1还没有SyncBarrier,4.1才开始加入SyncBarrier的,而且MessageQueue没有postSyncBarrier方法,只有enqueueSyncBarrier方法,Looper里面有个postSyncBarrier方法。
注意到MessageQueue中的postSyncBarrier中的返回值是一个int类型的token,相对应的removeSyncBarrier的入参就是这个token。这意味着post和remove是相对应的每个调用者值能控制自己的屏障。
我们可以看到Handler总共7个重载的构造函数,其中有3个暴露boolean async的构造均被@hide了,源码不希望api可以随意的插入优先级很高的消息。

回到上一篇文章中提到的核心方法next():

    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. 这里判空是looper退出失败后重启的一个异常处理
        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); //利用epoll等候指定时间

            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) { //如果是target为空的SyncBarrier则找第一个异步消息
                    // Stalled 拖延 by a barrier.  Find the next asynchronous message in the queue.
                    do {
                        prevMsg = msg; //循环找出next,保留前一位,便于恢复链表结构
                        msg = msg.next;
                    } while (msg != null && !msg.isAsynchronous());
                }
                if (msg != null) {
                    if (now < msg.when) { //如果不是马上执行的msg 则计算下一次唤醒时间
                        // 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; //有马上执行的消息 标记为false
                        if (prevMsg != null) {
                            prevMsg.next = msg.next; //有barrier的恢复链表结构,头还是barrier
                        } else {
                            mMessages = msg.next; //否则取出头部,头部的next做头
                        }
                        msg.next = null;
                        if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                        msg.markInUse();//标记inUse
                        return msg;
                    }
                } else {
                    // No more messages.
                    nextPollTimeoutMillis = -1; //原生pollIn函数中传入-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; //没有idleHandler时,该次循环结束 彻底进入阻塞 带着nextPollTimeMillis进入下次循环
                    continue;
                }

                if (mPendingIdleHandlers == null) { //待处理IdleHandlers最大为4
                    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(); //返回为false的将被移除 
                } 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; //处理过handler之后 为确保处理期间没有消息传入,不进入epoll
        }
    }

关于IdleHandler的使用场景可参考你知道android的MessageQueue.IdleHandler吗?
另外一个值得关注的方法是暴露给native层调用的dispatchEvents
由android_os_MessageQueue.cpp的int NativeMessageQueue::handleEvent(int fd, int looperEvents, void* data) 调用

// Called from native code.
    private int dispatchEvents(int fd, int events) {
        // Get the file descriptor record and any state that might change.
        final FileDescriptorRecord record;
        final int oldWatchedEvents;
        final OnFileDescriptorEventListener listener;
        final int seq;
        synchronized (this) {
            record = mFileDescriptorRecords.get(fd);
            if (record == null) {
                return 0; // spurious, no listener registered
            }

            oldWatchedEvents = record.mEvents;
            events &= oldWatchedEvents; // filter events based on current watched set
            if (events == 0) {
                return oldWatchedEvents; // spurious, watched events changed
            }

            listener = record.mListener;
            seq = record.mSeq;
        }

        // Invoke the listener outside of the lock.
        int newWatchedEvents = listener.onFileDescriptorEvents(
                record.mDescriptor, events);
        if (newWatchedEvents != 0) {
            newWatchedEvents |= OnFileDescriptorEventListener.EVENT_ERROR;
        }

        // Update the file descriptor record if the listener changed the set of
        // events to watch and the listener itself hasn't been updated since.
        if (newWatchedEvents != oldWatchedEvents) {
            synchronized (this) {
                int index = mFileDescriptorRecords.indexOfKey(fd);
                if (index >= 0 && mFileDescriptorRecords.valueAt(index) == record
                        && record.mSeq == seq) {
                    record.mEvents = newWatchedEvents;
                    if (newWatchedEvents == 0) {
                        mFileDescriptorRecords.removeAt(index);
                    }
                }
            }
        }

        // Return the new set of events to watch for native code to take care of.
        return newWatchedEvents;
    }



你可能感兴趣的:(Android源码分析)