由外到内——剖析Android消息机制

由外到内——剖析Android消息机制

消息机制常常是Android开发中比较核心的一部分,作为Android开发者这部分是一定要掌握的。

前言

由于Android规定在子线程中无法更新UI,而网络请求一般又只能在子线程中进行。这时,当我们请求到网络之后必定要将数据展示在UI上,所以说Android为我们提供了好多好多的方法来更新UI。

1
2
3
4
Activity.runOnUiThread(Runnable)
View.post(Runnable)
View.postDelayed(Runnable, long)
Handler

要了解原理,才能更好地使用Handler,所以说本文将带你走入Android消息机制的世界里。

基本使用

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
public class MainActivity extends AppCompatActivity {
private static final int CODE = 1;
private TextView tv;
private Handler mainHandler;



@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv = findViewById(R.id.tv);
mainHandler = new Handler(getMainLooper()){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if(msg.what == CODE){
tv.setText((String)msg.obj);
}
}
};

new Thread(()->{
try {
Thread.sleep(3000);//模拟网络耗时
Message message = Message.obtain();
message.what = CODE;
message.obj = "子线程用Handler更新UI";
mainHandler.sendMessage(message);
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}

@Override
protected void onDestroy() {
super.onDestroy();
mainHandler.removeCallbacksAndMessages(null);
}
}

代码很简单,无非就是在子线程中将Message发送到主线程中,再利用Handler处理。

源码分析

说起看源码,我大概的步骤是先看构造器,然后再根据我们日常使用的流程进行分析,明白各个类之间的关系。如果有更有效方法,可以传授一下。消息机制,无非就是HandlerLooperMessageQueue之间的关系。

关系

  • Handler:消息处理和接收者
  • Looper:消息调度者
  • MessageQueue:消息存储队列

    构造函数

    首先我们分析三个重要类的构造方法
    Handler构造函数
    构造函数一共有6个,但最重要的是下面这一个,其余构造器均是重载的下面这个构造器。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    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 " + Thread.currentThread()
    + " that has not called Looper.prepare()");
    }
    mQueue = mLooper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
    }

我们可以看到,首先在这里进行判断,如果找到了潜在的内存泄露则会打印一个Log。之后就是获得Handler所在线程的LooperMessageQueue。如果未找到Looper,即没有执行Looper.prepare则会抛出异常。

Looper构造函数
1
2
3
4
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}

Looper的构造函数中对MessageQueue进行了初始化,并且绑定了当前线程。但是值得一提的是这个构造器被private了,意思是不能显式地实例化,所以说我们要寻找在哪里初始化了Looper

Looper.prepare

经过一番寻找,果然在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));
}

这里进行了3件事情

  1. 判断ThreadLocal里是否已经存在Looper,若存在了则抛出异常。TheadLocal在每个线程中只存在一个,一般用来保存每个线程独有的东西。
  2. 初始化Looper。在Looper.prepare中,quitAllowed默认为true。这个quitAllowed会传入MessageQueue的构造器里,作用是判断是否Message可以退出,这里之后会讲。
  3. 将刚刚初始化的Looper保存到当前线程的ThreadLocal中。
MessageQueue构造函数
1
2
3
4
MessageQueue(boolean quitAllowed) {
mQuitAllowed = quitAllowed;
mPtr = nativeInit();
}

MessageQueue的构造函数中,设置了是否允许Message退出,然后调用nativeInit方法初始化native层的nativeMessageQueue,之后再将生成的nativeMessageQueue,通过reinterpret_cast方法将指针转化为long值返回给Framework层保存。

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);
}

消息入队

Handler.sendMessage

Handler发送消息有很多种:

  1. sendMessage
  2. sendMessageDelayed
  3. MessageAtTime
  4. sendMessageAtFrontOfQueue
  5. post(篇幅有限,这个方法逻辑差不多。)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    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);
    }

sendMessagesendMessageDelayed最后都会调用sendMessageAtTime,唯一不同的是发送延时消息时,参数需要传入(当前时间+延时时间)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public boolean sendMessageAtTime(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);
}
public final boolean sendMessageAtFrontOfQueue(Message msg) {
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, 0);
}

sendMessageAtTimesendMessageAtFrontOfQueue均会调用enqueueMessage,不同的是sendMessageAtTime传入的时间是uptimeMillis,而sendMessageAtFrontOfQueue传入的是0。顾名思义,后者是想把把消息插在消息队列的比队头。


所以说我们大胆猜测一下,队列会根据uptimeMillis值的不同来插入队列。我们接着往下看。

Handler.enqueueMessage
1
2
3
4
5
6
7
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}

逻辑很简单,这个方法将messagetarget设置为当前的Handler,然后设置是否异步发送该消息,最后调用MessageQueue.enqueueMessage

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
54
boolean enqueueMessage(Message msg, long when) {
if (msg.target == null) {//message没有target咋会知道发送到哪儿?
throw new IllegalArgumentException("Message must have a target.");
}
if (msg.isInUse()) {//使用过的message肯定不能再用吧?
throw new IllegalStateException(msg + " This message is already in use.");
}

synchronized (this) {
if (mQuitting) {//如果Message正在退出,会打印Log并且回收Message
IllegalStateException e = new IllegalStateException(
msg.target + " sending message to a Handler on a dead thread");
Log.w(TAG, e.getMessage(), e);
msg.recycle();//这个方法会把message回收到Message池
return false;
}

msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
//下面是对message进行处理
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;
}

可以看出,MessageQueue使用Message.next保存下一个Message,从而按照时间将所有的Message排序,从而达到入队的效果。同时,此时如果需要唤醒,则调用nativeWake方法来唤醒之前等待的线程。

1
2
3
4
static void android_os_MessageQueue_nativeWake(JNIEnv* env, jclass clazz, jlong ptr) {
NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
nativeMessageQueue->wake();
}

这样,我们就探索完Message是如何进入消息队列的逻辑。

消息分发和处理

在消息机制中,Looper主要作用是用来负责轮训消息、分发消息的。接下来我们分析一个消息是如何分发的。首先我们看Looper.loop方法

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
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;

//...省略一波代码

for (;;) {
Message msg = queue.next(); //取出Message
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}

//...省略一波代码

final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
final long dispatchEnd;
try {
msg.target.dispatchMessage(msg);
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
//省略一波代码target

msg.recycleUnchecked();
}
}

可以看到,通过msg.target将消息分发下去,最后回收了msg。这里的msg.target就是在Handler.enqueueMessage设置的Handler。所以说这里调用的是Handler.dispatchMessage方法

Handler.dispatchMessage
1
2
3
4
5
6
7
8
9
10
11
12
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}

如果该消息的callback不为空,则允许该消息的callback对象的run方法。否则,如果当前Handler.mCallback属性不为空,则mCallback处理该消息,如果msg.callbackHandler.mCallback都为空,则直接利用Handler.handleMessage内部处理该消息,该方法就是handler初始化时,自己写的方法。

借用一下伪代码:

1
2
3
4
5
6
7
8
9
10
11
12
public void dispatchMessage(Message msg) {
if (该消息的callback属性不为空) {
运行该消息的callback对象的run()方法;
} else {
if (当前Handler对象的mCallback属性不为空) {
if (mCallback对象成功处理了消息) {
return;
}
}
Handler内部处理该消息;
}
}

另外,在Looper.loop方法中,消息从消息队列中被取出。似乎我们还没分析消息如何取出来的吧?那我们马上分析一下姗姗来迟的MessageQueue.next

MessageQueue.next
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
Message next() {
final long ptr = mPtr;
if (ptr == 0) {
return null;
}

int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
for (;;) {
//..省略一大波代码

nativePollOnce(ptr, nextPollTimeoutMillis);//使Native的Looper阻塞

synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;

//如果msg不为null,target(目标Handler)不为空
if (msg != null && msg.target == null) {
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 {//到时间就取出message
// 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;
}
//..省略一大波代码
}

//..省略一大波代码
}
}

根据我写的注释我们可以知道,在这个方法里会有一个死循环不断轮训消息,如果没有消息则该循环会被阻塞,如果有消息,该消息会被移出单链表,然后返回该消息。

消息机制流程图

image

Message回收复用

在注释中,我们发现Google推荐用Message.obtain方法来获得一个Message而不是new一个Message。所以我们这里探索一下是为什么呢?

Message.obtain
1
2
3
4
5
6
7
8
9
10
11
12
13
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
m.flags = 0; // clear in-use flag
sPoolSize--;
return m;
}
}
return new Message();
}

显而易见,这里将运用了类似于对象池的东西,不过实现方法确实单链表。当sPool不为空,则说明该单链表上还有回收的Message可以复用。否则则创建一个新的Message。我们在之前的源码里看见了Message.recycle方法,这个方法用于在回收Message前进行一系列检查,真实调用的是Message.recycleUnchecked

Message.recycleUnchecked
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
void recycleUnchecked() {
// Mark the message as in use while it remains in the recycled object pool.
// Clear out all other details.
flags = FLAG_IN_USE;
what = 0;
arg1 = 0;
arg2 = 0;
obj = null;
replyTo = null;
sendingUid = -1;
when = 0;
target = null;
callback = null;
data = null;

synchronized (sPoolSync) {
if (sPoolSize < MAX_POOL_SIZE) {
next = sPool;
sPool = this;
sPoolSize++;
}
}
}

在这里清空Message的所有属性,并且将其放入对象池中。



这就是Message如何复用的过程。

Native层浅析

native层的逻辑与framework层大致相同,不过实现方法略有不同。值得一提的是,native层中NativeMessageQueue已经被弱化掉了,大部分逻辑都放在NativeLooper中处理。
image

Native层初始化

在上面,我们提到了MessageQueue的构造函数中同时Native层也要初始化MessageQueue,前面也提到,这里的MessageQueue指针将会被转化成long值保存在framework的MessageQueue中。

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);
}

在MessageQueue中同样也和Framework层一样,初始化了一个Native层的Looper,同时把Looper保存在当前线程中。

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构造函数如下:

1
2
3
4
5
6
7
8
9
10
11
12
Looper::Looper(bool allowNonCallbacks) :
mAllowNonCallbacks(allowNonCallbacks), mSendingMessage(false),
mPolling(false), mEpollFd(-1), mEpollRebuildRequired(false),
mNextRequestSeq(0), mResponseIndex(0), mNextMessageUptime(LLONG_MAX) {

mWakeEventFd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
LOG_ALWAYS_FATAL_IF(mWakeEventFd < 0, "Could not make wake event fd: %s",
strerror(errno));

AutoMutex _l(mLock);
rebuildEpollLocked();
}

这里创建了mWakeEventFd,与之前5.0利用管道的mWakeWritePipeFdmWakeReadPipeFd实现读取/写入不一样,eventfd是等待/响应。同时这里有一个很重要的方法rebuildEpollLocked

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
void Looper::rebuildEpollLocked() {
//...
mEpollFd = epoll_create(EPOLL_SIZE_HINT);
LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance: %s", strerror(errno));

struct epoll_event eventItem;
memset(& eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union
eventItem.events = EPOLLIN;
eventItem.data.fd = mWakeEventFd;
int result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeEventFd, & eventItem);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake event fd to epoll instance: %s",
strerror(errno));

for (size_t i = 0; i < mRequests.size(); i++) {
const Request& request = mRequests.valueAt(i);
struct epoll_event eventItem;
request.initEventItem(&eventItem);

int epollResult = epoll_ctl(mEpollFd, 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));
}
}
}

rebuildEpollLocked方法中,通过epoll_create创建了一个epoll专用的文件描述符,参数中的EPOLL_SIZE_HINTmEpollFd最大可监听的文件描述符数。之后调用epoll_ctl方法对mWakeEventFd的Epoll事件进行监听,mWakeEventFd如果有事件可读,就会唤醒当前正在等待的线程。

Epoll是什么?

刚刚提到了Epoll,可能没有了解的人根本不知道Epoll是什么东西。当framework层Looper.loop的时候,会用MessageQueue.next来取出消息。而next方法中是一个暴力死循环,Android当然没这么傻,不可能一直循环,所以说在循环里又调用了nativePollOnce(ptr, nextPollTimeoutMillis)方法,这里就是消息队列阻塞的关键,也是Epoll的主要作用。

回到正题,传统的阻塞型I/O,一个线程只能处理一个一个的IO流,就像5.0版本一样利用mWakeWritePipeFdmWakeReadPipeFd实现读写。而如果想要一个线程处理多个流,就得采用非阻塞、轮训的I/O,这样就出现了select(无差别轮询)epoll(事件轮询)这两种方法。而Epoll(类似于Event poll,即事件轮询)是基于事件的,不会无差别轮询,性能会有提高。



所以说我们看看刚才的rebuildEpollLocked方法中干了什么事情:

1
2
3
4
mEpollFd = epoll_create(EPOLL_SIZE_HINT);
eventItem.events = EPOLLIN;
eventItem.data.fd = mWakeEventFd;
int result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeEventFd, & eventItem);

  1. 创建mEpollFd代理
  2. epoll_event中设置mWakeEventFd
  3. 然后监听mWakeEventFd中的Epoll事件

这就是EPOLLIN事件所做的事情。

所以说,native层主要负责的是消息的调度,何时阻塞线程、何时唤醒线程、避免不停地空循环,避免性能消耗过大。

Native层消息发送

Handler发送消息的时候,会调用MessageQueue.enqueueMessage方法。在这个方法里,如果线程阻塞,又会调用nativeWake来唤醒线程。我们接下来看看nativeWake方法的实现

1
2
3
4
static void android_os_MessageQueue_nativeWake(JNIEnv* env, jclass clazz, jlong ptr) {
NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
nativeMessageQueue->wake();
}

通过ptr(就是framework层保存的long值)来拿到NativeMessageQueue,实际上是调用的wake方法

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

最后调用了Looper的wake方法

1
2
3
4
5
6
7
8
9
 void Looper::wake() {
//...
uint64_t inc = 1;
ssize_t nWrite = TEMP_FAILURE_RETRY(write(mWakeEventFd, &inc, sizeof(uint64_t)));
if (nWrite != sizeof(uint64_t)) {
//...
}
//...
}。

这里通过TEMP_FAILURE_RETRY这个宏定义,不断往mWakeEventFd里面写一个无用的事件,直到framework层MessageQueue.next被唤醒。

native层消息接收

前面我们提到在MessageQueue.next方法中,会调用一个native方法nativePollOnce(ptr, nextPollTimeoutMillis)来阻塞线程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Message next() {
//..省略一大波代码
int nextPollTimeoutMillis = 0;
for (;;) {
//..省略一大波代码

nativePollOnce(ptr, nextPollTimeoutMillis);//使Native的Looper阻塞

synchronized (this) {
//..省略一大波代码
}

//..省略一大波代码
}
}

我们看看它的具体实现:

1
2
3
4
5
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);
}

同样是调用的NativeMessageQueuepollOnce方法

1
2
3
4
5
6
7
8
9
10
11
12
13
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;
}
}

和之前的wake一样,这里同样最终调用了LooperpollOnce方法,所以说,native层的MessageQueue实际上已经被弱化了许多,大多数操作都在Looper中进行:

1
2
3
4
5
6
7
8
9
10
11
12
int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
int result = 0;
for (;;) {
while (mResponseIndex < mResponses.size()) {
//...省略一波代码
}

//...省略一波代码

result = pollInner(timeoutMillis);
}
}

pollOnce中又是一个死循环,就类似于MessageQueue.next方法一样,最终会调用pollInner(timeoutMillis)方法,这里就是最终的调用。

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
int Looper::pollInner(int timeoutMillis) {
//...
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();

//...省略一大波代码
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();//通过awoken唤醒线程
} else {
ALOGW("Ignoring unexpected epoll events 0x%x on wake event fd.", epollEvents);
}
} else {
//...
}
}


// Release lock.
mLock.unlock();
//...
return result;
}

这里可以看到,利用epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis)方法获取到事件到个数。如果个数为0,就继续阻塞。如果不为0,则会遍历每一个事件,如果有mWakeEventFd并且是EPOLLIN事件,就会通过awoken方法真正地唤醒线程。

framework与native关系图

image

最后

最后附上native层代码:

NativeMessageQueue

Looper


欢迎大家来和我交流。Android学习之路还很漫长。

0%