Android MessageQueue源码分析

Android应用开发中离不开Handler,而Handler实际上最终是将Message交给MessageQueue。MessageQueue是Android消息机制的核心,熟悉MessageQueue能够帮助我们更清楚详细地理解Android的消息机制。这篇文章会介绍MessageQueue消息的插入(enqueueMessage)和读取(next),native层的消息机制,以及IdleHandler和SyncBarrier的逻辑原理。源码是基于6.0。

MessageQueue的next与enqueueMessage方法

MessageQueue enqueueMessage

每次使用Handler发送一个Message的时候,最终会先调用MessageQueue的enqueueMessage方法将Message方法放入到MessageQueue里面。先看Handler的sendMessage方法,其他发送Message的内容也是一样的:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public final boolean sendMessage(Message msg)
{
    return sendMessageDelayed(msg, 0 ); // 调用下面这个方法
}
 
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
    if (delayMillis < 0 ) {
        delayMillis = 0 ;
    }
    return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); // 调用下面方法
}
 
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
    MessageQueue queue = mQueue; //Handler中的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(MessageQueue queue, Message msg, long uptimeMillis) {
    msg.target = this ;
    if (mAsynchronous) {
        msg.setAsynchronous( true );
    }
    return queue.enqueueMessage(msg, uptimeMillis); //调用MessageQueue的enqueueMessage
}

最后会调用Handler的mQueue的enqueueMessage方法,而Handler的mQueue是从哪里来的呢?在Handler的构造函数中设置的,看默认的情况:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public Handler() {
    this ( null , false );
}
public Handler(Callback callback, boolean 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());
        }
    }
 
    mLooper = Looper.myLooper();
    if (mLooper == null ) {
        throw new RuntimeException(
            "Can't create handler inside thread that has not called Looper.prepare()" );
    }
    mQueue = mLooper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
}

无参Handler构造函数对应的是当前调用无参Handler构造函数线程的Looper,Looper是一个ThreadLocal变量,也就是说但是每个线程独有的,每个线程调用了Looper.prepare方法后,就会给当前线程设置一个Looper:

?
1
2
3
4
5
6
7
8
9
10
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));
}

Looper里面包含了一个MessageQueue, 在Handler的构造函数中,会将当前关联的Looper的MessageQueue赋值给Handler的成员变量mQueue,enqueueMessage的时候就是调用该mQueue的enqueueMessage。关于Handler与Looper可以理解为每个Handler会关联一个Looper,每个线程最多只有一个Looper。Looper创建的时候会创建一个MessageQueue,而发送消息的时候,Handler就会通过调用mQueue.enqueueMessage方法将Message放入它关联的Looper的MessageQueue里面。介绍了Handler与Looper,然后继续看看MessageQueue的enqueueMessage方法:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
boolean enqueueMessage(Message msg, long when) {
    if (msg.target == null ) {
        throw new IllegalArgumentException( "Message must have a target." );
    }
    if (msg.isInUse()) {
        throw new IllegalStateException(msg + " This message is already in use." );
    }
 
    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 ;
        }
 
        msg.markInUse();
        msg.when = when;
        Message p = mMessages;
        boolean needWake;
        if (p == null || when == 0 || when < p.when) {
            // New head, wake up the event queue if blocked.
            msg.next = p;
            mMessages = msg;
            needWake = mBlocked;
        } else {
            // 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) {
                    break ;
                }
                if (needWake && p.isAsynchronous()) {
                    needWake = false ;
                }
            }
            msg.next = p; // invariant: p == prev.next
            prev.next = msg;
        }
 
        // We can assume mPtr != 0 because mQuitting is false.
        if (needWake) {
            nativeWake(mPtr);
        }
    }
    return true ;
}

整个enqueueMessage方法的过程就是先持有MessageQueue.this锁,然后将Message放入队列中,放入队列的过程是:
1. 如果队列为空,或者当前处理的时间点为0(when的数值,when表示Message将要执行的时间点),或者当前Message需要处理的时间点先于队列中的首节点,那么就将Message放入队列首部,否则进行第2步。
2. 遍历队列中Message,找到when比当前Message的when大的Message,将Message插入到该Message之前,如果没找到则将Message插入到队列最后。
3. 判断是否需要唤醒,一般是当前队列为空的情况下,next那边会进入睡眠,需要enqueue这边唤醒next函数。后面会详细介绍

执行完后,会释放持有的MessageQueue.this的锁。这样整个enqueueMessage方法算是完了,然后看看读取Message的MessageQueue的next方法。

MessageQueue的next方法

MessageQueue的next方法是从哪里调用的呢?先看一个线程对Looper的标准用法是:

?
1
2
3
4
5
6
7
8
9
10
11
12
class LoopThread extends Thread{
public Handler mHandler;
     public void run(){
         Looper.prepare();
         mHandler = new Handler() {
               public void handleMessage(Message msg) {
                   // process incoming messages here
               }
           };       
         Looper.loop();
     }
}

prepare方法我们前面已经看过了,就是初始化ThreadLocal变量Looper。loop()方法就是循环读取MessageQueue中Message,然后处理每一个Message。我们看看Looper.loop方法源码:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
public static void loop() {
    final Looper me = myLooper();
    if (me == null ) {
        throw new RuntimeException( "No Looper; Looper.prepare() wasn't called on this thread." );
    }
    final MessageQueue queue = me.mQueue;
 
    // 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();
 
    for (;;) {
        Message msg = queue.next(); // might block 此处就是next方法调用的地方
        if (msg == null ) {
            // No message indicates that the message queue is quitting.
            return ;
        }
 
        // This must be in a local variable, in case a UI event sets the logger
        Printer logging = me.mLogging;
        if (logging != null ) {
            logging.println( ">>>>> Dispatching to " + msg.target + " " +
                    msg.callback + ": " + msg.what);
        }
 
        msg.target.dispatchMessage(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();
    }
}

整个loop函数大概的过程就是先调用MessageQueue.next方法获取一个Message,然后调用Message的target的dispatchMessage方法来处理Message,Message的target就是发送这个Message的Handler。处理的过程是先看Message的callback有没有实现,如果有,则使用调用callback的run方法,如果没有则看Handler的callback是否为空,如果非空,则使用handler的callback的handleMessage方法来处理Message,如果为空,则调用Handler的handleMessage方法处理。

我们主要看next,从注释来看,next方法可能会阻塞,先看next方法的源码:

扫描二维码关注公众号,回复: 873416 查看本文章
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
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;  //mPrt是native层的MessageQueue的指针
    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); // jni函数
 
        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 正常情况下都不会为null,在postBarrier会出现target为null的Message
                // 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;
                    } else {
                        mMessages = msg.next;
                    }
                    msg.next = null ;
                    if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                    msg.markInUse();
                    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++) { //运行idle
            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 ;
    }
}

整个next函数的主要是执行步骤是:

step1: 初始化操作,如果mPtr为null,则直接返回null,设置nextPollTimeoutMillis为0,进入下一步。 step2: 调用nativePollOnce, nativePollOnce有两个参数,第一个为mPtr表示native层MessageQueue的指针,nextPollTimeoutMillis表示超时返回时间,调用这个nativePollOnce会等待wake,如果超过nextPollTimeoutMillis时间,则不管有没有被唤醒都会返回。-1表示一直等待,0表示立刻返回。下一小节单独介绍这个函数。 step3: 获取队列的头Message(msg),如果头Message的target为null,则查找一个异步Message来进行下一步处理。当队列中添加了同步Barrier的时候target会为null。 step4: 判断上一步获取的msg是否为null,为null说明当前队列中没有msg,设置等待时间nextPollTimeoutMillis为-1。实际上是等待enqueueMessage的nativeWake来唤醒,执行step4。如果非null,则下一步 step5: 判断msg的执行时间(when)是否比当前时间(now)的大,如果小,则将msg从队列中移除,并且返回msg,结束。如果大则设置等待时间nextPollTimeoutMillis为(int) Math.min(msg.when - now, Integer.MAX_VALUE),执行时间与当前时间的差与MAX_VALUE的较小值。执行下一步 step6: 判断是否MessageQueue是否已经取消,如果取消的话则返回null,否则下一步 step7: 运行idle Handle,idle表示当前有空闲时间的时候执行,而运行到这一步的时候,表示消息队列处理已经是出于空闲时间了(队列中没有Message,或者头部Message的执行时间(when)在当前时间之后)。如果没有idle,则继续step2,如果有则执行idleHandler的queueIdle方法,我们可以自己添加IdleHandler到MessageQueue里面(addIdleHandler方法),执行完后,回到step2。

需要说的时候,我们平常只是使用Message,但是实际上IdleHandler如果使用的好,应该会达到意想不到的效果,它表示MessageQueue有空闲时间的时候执行一下。然后介绍一下nativePollOnce与nativeWake方法

native层机制

nativePollOnce与nativeWake是两个jni方法,这两个方法jni实现方法在frameworks/base/core/jni/android_os_MessageQueue.cpp。这个是MessageQueue的native层内容。native层的NativeMessageQueue初始化是在nativeInit方法:

?
1
2
3
4
5
6
7
8
9
10
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);
}</jlong>

对应的java层方法是nativeInit,在MessageQueue构造函数的时候调用:

?
1
2
3
4
MessageQueue( boolean quitAllowed) {
    mQuitAllowed = quitAllowed;
    mPtr = nativeInit();
}

而NativeMessageQueue的构造函数是:

?
1
2
3
4
5
6
7
8
NativeMessageQueue::NativeMessageQueue() :
        mPollEnv(NULL), mPollObj(NULL), mExceptionObj(NULL) {
    mLooper = Looper::getForThread();
    if (mLooper == NULL) {
        mLooper = new Looper( false );
        Looper::setForThread(mLooper);
    }
}

创建了一个native层的Looper。Looper的源码在system/core/libutils/Looper.cpp。Looper通过epoll_create创建了一个mEpollFd作为epoll的fd,并且创建了一个mWakeEventFd,用来监听java层的wake,同时可以通过Looper的addFd方法来添加新的fd监听。

nativePollOnce

nativePollOnce是每次调用next方法获取消息的时候调用的:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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);
    mPollObj = NULL;
    mPollEnv = NULL;
 
    if (mExceptionObj) {
        env->Throw(mExceptionObj);
        env->DeleteLocalRef(mExceptionObj);
        mExceptionObj = NULL;
    }
}</nativemessagequeue*>

这个方法的native层方法最终会调用Looper的pollOnce:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
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 != NULL) *outFd = fd;
                if (outEvents != NULL) *outEvents = events;
                if (outData != NULL) *outData = data;
                return ident;
            }
        }
 
        if (result != 0 ) {
# if DEBUG_POLL_AND_WAKE
            ALOGD( "%p ~ pollOnce - returning result %d" , this , result);
#endif
            if (outFd != NULL) *outFd = 0 ;
            if (outEvents != NULL) *outEvents = 0 ;
            if (outData != NULL) *outData = NULL;
            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];
    int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);
 
    // No longer idling.
    mPolling = false ;
 
    // Acquire lock.
    mLock.lock();
 
    // Rebuild epoll set if needed.
    if (mEpollRebuildRequired) {
        mEpollRebuildRequired = false ;
        rebuildEpollLocked();
        goto Done;
    }
 
    // Check for poll error.
    if (eventCount < 0 ) {
        if (errno == EINTR) {
            goto Done;
        }
        ALOGW( "Poll failed with an unexpected error, errno=%d" , errno);
        result = POLL_ERROR;
        goto Done;
    }
 
    // Check for poll timeout.
    if (eventCount == 0 ) {
# if DEBUG_POLL_AND_WAKE
        ALOGD( "%p ~ pollOnce - timeout" , this );
#endif
        result = POLL_TIMEOUT;
        goto Done;
    }
 
    // Handle all events.
# if DEBUG_POLL_AND_WAKE
    ALOGD( "%p ~ pollOnce - handling events from %d fds" , this , eventCount);
#endif
 
    for ( int i = 0 ; i < eventCount; i++) {
        int fd = eventItems[i].data.fd;
        uint32_t epollEvents = eventItems[i].events;
        if (fd == mWakeEventFd) {
            if (epollEvents & EPOLLIN) {
                awoken();
            } else {
                ALOGW( "Ignoring unexpected epoll events 0x%x on wake event fd." , epollEvents);
            }
        } else {
            ssize_t requestIndex = mRequests.indexOfKey(fd);
            if (requestIndex >= 0 ) {
                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;
                pushResponse(events, mRequests.valueAt(requestIndex));
            } else {
                ALOGW( "Ignoring unexpected epoll events 0x%x on fd %d that is "
                        "no longer registered." , epollEvents, fd);
            }
        }
    }
Done: ;
 
    // Invoke pending message callbacks.
    mNextMessageUptime = LLONG_MAX;
    while (mMessageEnvelopes.size() != 0 ) {
        nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
        const MessageEnvelope& messageEnvelope = mMessageEnvelopes.itemAt( 0 );
        if (messageEnvelope.uptime <= now) {
            // Remove the envelope from the list.
            // We keep a strong reference to the handler until the call to handleMessage
            // finishes.  Then we drop it so that the handler can be deleted *before*
            // we reacquire our lock.
            { // obtain handler
                sp<messagehandler> handler = messageEnvelope.handler;
                Message message = messageEnvelope.message;
                mMessageEnvelopes.removeAt( 0 );
                mSendingMessage = true ;
                mLock.unlock();
 
# if DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKS
                ALOGD( "%p ~ pollOnce - sending message: handler=%p, what=%d" ,
                        this , handler.get(), message.what);
#endif
                handler->handleMessage(message);
            } // release handler
 
            mLock.lock();
            mSendingMessage = false ;
            result = POLL_CALLBACK;
        } else {
            // The last message left at the head of the queue determines the next wakeup time.
            mNextMessageUptime = messageEnvelope.uptime;
            break ;
        }
    }
 
    // Release lock.
    mLock.unlock();
 
    // Invoke all response callbacks.
    for (size_t i = 0 ; i < mResponses.size(); i++) {
        Response& response = mResponses.editItemAt(i);
        if (response.request.ident == POLL_CALLBACK) {
            int fd = response.request.fd;
            int events = response.events;
            void * data = response.request.data;
# if DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKS
            ALOGD( "%p ~ pollOnce - invoking fd event callback %p: fd=%d, events=0x%x, data=%p" ,
                    this , response.request.callback.get(), fd, events, data);
#endif
            // Invoke the callback.  Note that the file descriptor may be closed by
            // the callback (and potentially even reused) before the function returns so
            // we need to be a little careful when removing the file descriptor afterwards.
            int callbackResult = response.request.callback->handleEvent(fd, events, data);
            if (callbackResult == 0 ) {
                removeFd(fd, response.request.seq);
            }
 
            // Clear the callback reference in the response structure promptly because we
            // will not clear the response vector itself until the next poll.
            response.request.callback.clear();
            result = POLL_CALLBACK;
        }
    }
    return result;
}</messagehandler>

这个方法超长,但实际上Looper的pollOnce方法主要有5步:

调用epoll_wait方法等待所监听的fd的写入,其方法原型如下:
?
1
int epoll_wait( int epfd, struct epoll_event * events, intmaxevents, int timeout)

调用的方法参数为:

?
1
int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);

eventItems里面就包含了mWakeEvent和通过addFd添加fd时加入的Event。该方法会阻塞,当timeoutMillis(对应java层的nextPollTimeoutMillis)到了时间,该方法会返回,或者eventItems有事件来了,该方法会返回。返回之后就是干下一件事
2. 判断有没有event,因为可能是timeoutMillis到了返回的,如果没有直接进行4.
3. 读取eventItems的内容,如果eventItem的fd是mWakeEventFd,则调用awoken方法,读取Looper.wake写入的内容,如果是其他的fd,则使用pushResponse来读取,并且将内容放入Response当中。
4. 处理NativeMessageQueue的消息,这些消息是native层的消息
5. 处理pushResponse写入的内容。

里面主要是干了三件事处理wakeEventFd的输入内容,其他fd的输入内容,以及NativeMessageQueue里面的Message。

nativeWake

实际上最后就是调用了Looper的wake方法:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//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();
}
 
//Looper.cpp
void Looper::wake() {
# if DEBUG_POLL_AND_WAKE
    ALOGD( "%p ~ wake" , this );
#endif
 
    uint64_t inc = 1 ;
    ssize_t nWrite = TEMP_FAILURE_RETRY(write(mWakeEventFd, &inc, sizeof(uint64_t)));
    if (nWrite != sizeof(uint64_t)) {
        if (errno != EAGAIN) {
            ALOGW( "Could not write wake signal, errno=%d" , errno);
        }
    }
}</nativemessagequeue*>

这样native层的消息队列就算是完了。

SyncBarrier

我们在next方法里面看到有这么一段代码

?
1
2
3
4
5
6
7
if (msg != null && msg.target == null ) { //target 正常情况下都不会为null,在postBarrier会出现target为null的Message
                // Stalled by a barrier.  Find the next asynchronous message in the queue.
                do {
                    prevMsg = msg;
                    msg = msg.next;
                } while (msg != null && !msg.isAsynchronous());
            }

什么时候msg.target会为null呢?有sync barrier消息的时候,实际上msg.target为null表示sync barrier(同步消息屏障)。MessageQueue有一个postSyncBarrier方法:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public int postSyncBarrier() {
    return postSyncBarrier(SystemClock.uptimeMillis());
}
 
private int postSyncBarrier( long when) {
    // Enqueue a new sync barrier token.
    // We don't need to wake the queue because the purpose of a barrier is to stall it.
    synchronized ( this ) {
        final int token = mNextBarrierToken++;
        final Message msg = Message.obtain();
        msg.markInUse();
        msg.when = when;
        msg.arg1 = token;
 
        Message prev = null ;
        Message p = mMessages;
        if (when != 0 ) {
            while (p != null && p.when <= when) {
                prev = p;
                p = p.next;
            }
        }
        if (prev != null ) { // invariant: p == prev.next
            msg.next = p;
            prev.next = msg;
        } else {
            msg.next = p;
            mMessages = msg;
        }
        return token;
    }
}

对应有removeSyncBarrier方法:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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 ) {
        Message prev = null ;
        Message p = mMessages;
        while (p != null && (p.target != null || p.arg1 != token)) {
            prev = p;
            p = p.next;
        }
        if (p == null ) {
            throw new IllegalStateException( "The specified message queue synchronization "
                    + " barrier token has not been posted or has already been removed." );
        }
        final boolean needWake;
        if (prev != null ) {
            prev.next = p.next;
            needWake = false ;
        } else {
            mMessages = p.next;
            needWake = mMessages == null || mMessages.target != null ;
        }
        p.recycleUnchecked();
 
        // If the loop is quitting then it is already awake.
        // We can assume mPtr != 0 when mQuitting is false.
        if (needWake && !mQuitting) {
            nativeWake(mPtr);  // 需要唤醒,因为队首元素是SyncBarrier,队列中有消息但是没有异步消息的时候,next方法同样会阻塞等待。
        }
    }
}

看next方法的源码,每次消息队列中有barrier的时候,next会寻找队列中的异步消息来处理。如果没有异步消息,设置nextPollTimeoutMillis = -1,进入阻塞等待新消息的到来。异步消息主要是系统发送的,而系统中的异步消息主要有触摸事件,按键事件的消息。系统中调用postSyncBarrier和removeSyncBarrier主要实在ViewRootImpl的scheduleTraversals和unscheduleTraversals,以及doTraversals方法中。从源码可以猜到每次调用postSyncBarrier后都会调用removeSyncBarrier,不然同步消息就没法执行了(看next源码理解这一点)。可以看一下scheduleTraversal方法:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//ViewRootImpl.java
void scheduleTraversals() {
    if (!mTraversalScheduled) {
        mTraversalScheduled = true ;
        mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
        mChoreographer.postCallback(
                Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null );
        if (!mUnbufferedInputDispatch) {
            scheduleConsumeBatchedInput();
        }
        notifyRendererOfFramePending();
        pokeDrawLockIfNeeded();
    }
}

实际上MessageQueue的源码一直在变化的,2.3才加入了native层的Message,在4.0.1还没有SyncBarrier,4.1才开始加入SyncBarrier的,而且MessageQueue没有postSyncBarrier方法,只有enqueueSyncBarrier方法,Looper里面有个postSyncBarrier方法。

SyncBarrier的意义

前面介绍了一下每个版本的特点,我想介绍一种SyncBarrier的意义,我们介绍了使用SyncBarrier主要是ViewRootImpl中的scheduleTraversal的时候,那是跟UI事件相关的,像派发消息会通过发送Message发到主线程:

?
1
2
3
4
5
6
7
8
public void dispatchInputEvent(InputEvent event, InputEventReceiver receiver) {
    SomeArgs args = SomeArgs.obtain();
    args.arg1 = event;
    args.arg2 = receiver;
    Message msg = mHandler.obtainMessage(MSG_DISPATCH_INPUT_EVENT, args);
    msg.setAsynchronous( true );
    mHandler.sendMessage(msg);
}

注意它这里就是使用的异步Message,使用了msg.setAsyncronous(true)。 而SyncBarrier有什么用处呢?我们刚刚介绍的时候,当消息队列的第一个Message的target的时候,表示它是一个SyncBarrier,它会阻拦同步消息,而选择队列中第一个异步消息处理,如果没有则会阻塞。这表示什么呢?这是表示第一个Message是SyncBarrier的时候,会只处理异步消息。而我们前面介绍了InputEvent的时候,它就是异步消息,在有SyncBarrier的时候就会被优先处理。所以在调用了scheduleTraversal的时候,就会只处理触摸事件这些消息了,保证用户体验。保证了触摸事件及时处理,实际上这也能减少ANR。如果这个时候MessageQueue中有很多Message,也能够及时处理那些触摸事件的Message了。

总结

MessageQueue是Android消息消息机制的内部核心,理解好MessageQueue更能理解好Android应用层的消息逻辑。另外MessageQueue的代码一直在不断地变化,对照不同版本的代码,真的能领略代码改变时的目的,从演变中学习。

猜你喜欢

转载自blog.csdn.net/u013749540/article/details/79403851