SwallowJoe的博客

Be a real go-getter,
NEVER SETTLE!

0%

Looper-Android中的消息机制

简述

本文详细分析android的消息机制Looper的底层原理。

以下分析基于Android S.

初学Android的时候, 比较容易遇到如下错误:

1
2
3
4
5
6
7
E AndroidRuntime: FATAL EXCEPTION: 非UI线程
E AndroidRuntime: Process: com.android.demo, PID: 23939
E AndroidRuntime: android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
E AndroidRuntime: at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:9587)
E AndroidRuntime: at android.view.ViewRootImpl.requestLayout(ViewRootImpl.java:1894)
......
E AndroidRuntime: at java.lang.Thread.run(Thread.java:923)

往往是我们在非UI线程更新UI组件导致的。解决的方案也很简单,将更新组件的操作移入UI线程执行即可。此时就需要用到Android中非常基础又非常重要的Handler、Looper、Message这三个类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var uiHandler = UiHandler(Looper.getMainLooper())
val message = uiHandler.obtainMessage(MSG_UPDATE_UI)
message.obj = "我在UI线程中更新UI组件哦!"
uiHandler.sendMessage(message)

companion object {
const val MSG_UPDATE_UI = 0x1
}

inner class UiHandler(looper: Looper) : Handler(looper) {
override fun handleMessage(msg: Message) {
super.handleMessage(msg)
when (msg.what) {
MSG_UPDATE_UI -> {
textview.text = msg.obj as String
}
}
}
}

如上,设置Handler的Looper为MainLooper,然后通过sendMessage将封装数据的Message发送到MainLooper代表的UI线程中处理,就这样切换了线程。接下来我们研究下其中的原理,为什么Looper有main looper, Handler的sendMessage是怎么找到对应线程,然后调用handleMessage的。

或者通过Looper prepare的方式, 其实也是获取主线程的Looper实现的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Keep extends Thread {
public static final int MSG_A = 0x00;
public static final int MSG_B = 0x00;

public Handler handler;

@Override
public void run() {
Looper.prepare();
handler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_A: { /* .... */ } break;
case MSG_B: { /* .... */ } break;
}
}
};
Looper.loop();
}
}

这样我们在需要的时候执行: handler.sendMessage(handler.obtain(MSG_A)) 即可以实现线程交换了, 除了sendMessage,还有如下方式:

Handler

Android系统中大量使用Message来进行跨线程通信,实现交互,设计四个类:Message、Handler、Looper和MessageQueue, 类图如下:

Looper类图

  1. Message: 消息,封装待传递的数据
  2. Handler: 消息辅助类,向消息池(MessageQueue)中存入消息和接收消息进行处理
  3. Looper: 如其名,封装一个不断循环的函数体,不停的从消息池(MessageQueue)中取出合适的消息交给Handler处理
  4. MessageQueue: 消息池,维护了一个由消息组成的链表,该链表按照消息执行的时间顺序排列

我们首先看看UI线程的Looper获取:Looper.getMainLooper()

一. Main Looper的创建

1.1 Looper.getMainLooper

1
2
3
4
5
public static Looper getMainLooper() {
synchronized (Looper.class) {
return sMainLooper;
}
}

返回的就是Looper中静态变量sMainLooper。那么该sMainLooper是何时创建的呢:

1.2 sMainLooper

1
2
3
4
5
6
7
8
9
10
11
public static void prepareMainLooper() {
// 1.2.1 Looper准备工作
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
// 1.2.3 myLooper拿的就是当前线程的Looper.
sMainLooper = myLooper();
}
}

sMainLooper是在Looper.prepareMainLooper被第一次调用时赋值的。而prepareMainLooper是在ActivityThread.main函数中调用的:

1
2
3
4
5
6
7
8
9
// ActivityThread.java
public static void main(String[] args) {
......
Looper.prepareMainLooper();
......
// 1.3 执行loop
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}

在Zygote启动进程时,进程的入口函数是ActivityThread.main,也就是说三方进程启动后第一时间就会调用Looper.prepareMainLooper()设置sMainLooper。

1.2.1 Looper.prepare

1
2
3
4
5
6
7
8
9
10
11
12
public static void prepare() {
prepare(true);
}

// quitAllowed 这个参数表明该Looper是否允许退出
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
// 1.2.2 注意这里创建了一个Looper, 并保存在sThreadLocal中
sThreadLocal.set(new Looper(quitAllowed));
}

quitAllowed 这个参数表明该Looper是否允许退出,自然UI线程(主线程)是不允许退出的,除非被kill或者进程自杀。

这里稍微提一下,sThreadLocal是ThreadLocal类型,实现了线程本地存储区(Thread Local Storage, 简称TLS)。每个线程都有自己私有的存储区域,不同线程之间彼此不能访问对方的TSL区域。简单来说,可以将这里的 sThreadLocal 视为一个Map集合,其中key为Thread, value是Looper, 每次set和get都是获取当前线程对应的Looper

1.2.2 Looper 的创建

1
2
3
4
5
private Looper(boolean quitAllowed) {
// 3.1 MessageQueue创建
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}

简单的创建了一个MessageQueue,并保存创建该Looper的线程。

1.2.3 Looper.myLooper

1
2
3
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}

通过sThreadLocal获取当前线程对应的Looper.

1.3 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
public static void loop() {
// 获取当前线程的Looper
final Looper me = myLooper();
// Looper一定存在某个线程中,线程不一定拥有Looper
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}

// adb shell 'setprop log.looper.1000.main.slow 1 && stop && start'
// 用于修改记录Looper中的Message是否执行慢或者超时的时长
final int thresholdOverride =
SystemProperties.getInt("log.looper."
+ Process.myUid() + "."
+ Thread.currentThread().getName()
+ ".slow", 0);

// 如果有message分发超时,这个变量就会被标记为true
me.mSlowDeliveryDetected = false;

// 这个就是Loop名称的由来,一直循环
for (;;) {
if (!loopOnce(me, ident, thresholdOverride)) {
return;
}
}
}

loop()函数很简单,就一直循环执行loopOnce就可

1.4 Looper.loopOnce

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
private static boolean loopOnce(final Looper me,
final long ident, final int thresholdOverride) {
// 5.1 通过MessageQueue获取下一个Message, 这里稍后分析
Message msg = me.mQueue.next();
if (msg == null) {
// 获取的下一个Message为null,说明该Looper将要退出
return false;
}

// mLogging是Printer的对象,可以通过: looper.setMessageLogging(printer)设置
// 用于打印Looper日志,如下:
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;
// traceTag用于抓取systrace,通过looper.setTraceTag设置
final long traceTag = me.mTraceTag;
// mSlowDispatchThresholdMs和mSlowDeliveryThresholdMs默认都是0
// 可以通过setSlowLogThresholdMs设置
// 比如SystemServer主线程的looper就被分别设置为100ms,200ms
long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
long slowDeliveryThresholdMs = me.mSlowDeliveryThresholdMs;
if (thresholdOverride > 0) {
// thresholdOverride可以通过属性修改:setprop log.looper.1000.main.slow 1
slowDispatchThresholdMs = thresholdOverride;
slowDeliveryThresholdMs = thresholdOverride;
}
final boolean logSlowDelivery = (slowDeliveryThresholdMs > 0) && (msg.when > 0);
final boolean logSlowDispatch = (slowDispatchThresholdMs > 0);

final boolean needStartTime = logSlowDelivery || logSlowDispatch;
final boolean needEndTime = logSlowDispatch;
// 开始抓取trace
if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
}
// 记录Message分发开始的时间
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 {
// 1.4.1 分发message, 这里的target就是Handler
msg.target.dispatchMessage(msg);
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) {
// mSlowDeliveryDetected 表明之前就有消息等待分发超时了
if (me.mSlowDeliveryDetected) {
// message分发时间和该message需要执行的时间相差不超过10ms,说明Message分发及时
// 去掉之前标记的消息分发超时
if ((dispatchStart - msg.when) <= 10) {
Slog.w(TAG, "Drained");
me.mSlowDeliveryDetected = false;
}
} else {
// 这里就是检测Message等待分发是否超过阈值
// 打印的日志如: Looper: Slow delivery took 233ms android.ui h=com.XXX c=null m=31
if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery",
msg)) {
// Once we write a slow delivery log, suppress until the queue drains.
me.mSlowDeliveryDetected = true;
}
}
}
// 消息分发是否超时
// 打印的日志如: Looper: Slow dispatch took 233ms android.ui h=com.XXX c=null m=31
if (logSlowDispatch) {
showSlowLog(slowDispatchThresholdMs, dispatchStart, dispatchEnd, "dispatch", msg);
}

if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
......
// 回收该Message
msg.recycleUnchecked();

return true;
}

loopOnce函数看起来也很简单,一直从MessageQueue中获取Message并执行Handler.handleMessage函数。除非拿到的message是null时返回false,否则永远返回true。
注意弄清 delivery 和 dispatch 的区别:

  1. delivery: 消息被拿出准备分发的时间与消息期望被执行的时间差
  2. dispatch: 消息处理的总时间,即handle.dispatchMessage的执行时长

Delivery_Dispatch

1.4.1 Handler.dispatchMessage

1
2
3
4
5
6
7
8
9
10
11
12
13
public void dispatchMessage(@NonNull Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
// 执行我们重载的函数了
handleMessage(msg);
}
}

我们知道在Handler.handleMessage这里已经转到Handler对应Looper所在的线程了。这样看起来,线程切换的奥秘都被隐藏在MessageQueue中了。

二. Message

在分析MessageQueue之前,简单看一下Message的设计。

变量 类型 作用
what int 标明消息类别
arg1 int 参数1
arg2 int 参数2
obj Object 消息内容
when long 消息期望触发时间
data Bundle 消息附带内容
target Handler 消息触发执行的Handler
callback Runnable 消息执行的Runnable
next Message 下一个消息, 消息链表结构基础

2.1 消息链表结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@UnsupportedAppUsage
/*package*/ Message next;

/** @hide */
public static final Object sPoolSync = new Object();
private static Message sPool;
private static int sPoolSize = 0;

private static final int MAX_POOL_SIZE = 50;

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

通过维护一个大小为50的Message缓冲池,来缓解Message频繁创建销毁带来的资源损耗,所以在开发过程中尽可能选择使用obtain来创建Message。

三. MessageQueue

既然Message自己就维护了一个链表结构,还需要MessageQueue做什么呢?

3.1 MessageQueue

1
2
3
4
5
MessageQueue(boolean quitAllowed) {
mQuitAllowed = quitAllowed;
// 3.2 通过JNI进入native实例化
mPtr = nativeInit();
}

设置mQuitAllowed, 主线程的Looper不允许退出(调用quit,主动退出)。然后通过JNI进入native层初始化

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

也就是创建了一个NativeMessageQueue的对象。

3.3 NativeMessageQueue

1
2
3
4
5
6
7
8
9
10
11
NativeMessageQueue::NativeMessageQueue() :
mPollEnv(NULL), mPollObj(NULL), mExceptionObj(NULL) {
// 注意这里是native层的Loop了, 同样的也是通过TLS方式存储的
mLooper = Looper::getForThread();
if (mLooper == NULL) {
// 3.4 创建Looper
mLooper = new Looper(false);
// 保存在当前线程的TLS中
Looper::setForThread(mLooper);
}
}

3.4 Looper.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Looper::Looper(bool allowNonCallbacks)
: mAllowNonCallbacks(allowNonCallbacks),
mSendingMessage(false),
mPolling(false),
mEpollRebuildRequired(false),
mNextRequestSeq(0),
mResponseIndex(0),
mNextMessageUptime(LLONG_MAX) {
// eventfd函数会创建一个eventfd, 这里保存在mWakeEventFd中
// EFD_NONBLOCK: 设置FD对象为非阻塞状态
// EFD_CLOEXEC: 调用exec后会自动关闭文件描述符,防止泄漏
mWakeEventFd.reset(eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC));
LOG_ALWAYS_FATAL_IF(mWakeEventFd.get() < 0, "Could not make wake event fd: %s", strerror(errno));

AutoMutex _l(mLock);
// 3.4.1 重建epoll
rebuildEpollLocked();
}

eventfd 是 Linux 的一个系统调用,创建一个文件描述符用于事件通知,自 Linux 2.6.22 以后开始支持。该函数会创建一个 eventfd 对象,用户空间的应用程序可以用这个 eventfd 来实现事件的等待或通知机制,也可以用于内核通知新的事件到用户空间应用程序。

看来初始化该Looper的线程是通过这个eventfd来实现被唤醒的。

3.4.1 Looper.cpp: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
26
27
28
29
30
31
32
33
void Looper::rebuildEpollLocked() {
// 如果原有fd存在,则关闭
if (mEpollFd >= 0) {
mEpollFd.reset();
}

// 创建一个新的epoll实例, 并获取该实例的fd标记
mEpollFd.reset(epoll_create1(EPOLL_CLOEXEC));
LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance: %s", strerror(errno));

struct epoll_event eventItem;
memset(& eventItem, 0, sizeof(epoll_event));
// EPOLLIN 表明fd文件可读
eventItem.events = EPOLLIN;
eventItem.data.fd = mWakeEventFd.get();
// 在epoll实例上注册mWakeEventFd文件描述符,并将EPOLL_CTL_ADD事件关联到mWakeEventFd
int result = epoll_ctl(mEpollFd.get(), EPOLL_CTL_ADD, mWakeEventFd.get(), &eventItem);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake event fd to epoll instance: %s",
strerror(errno));

// 对所有mRequests的fd进行重定向, 均关联到新创建的epoll实例上
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.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));
}
}
}

这里主要是创建了一个epoll实例,并将该Looper的mWakeEventFd(即eventfd)关联到该epoll实例上。如果该Looper的mRequests存在Request时,也对所有mRequests的fd进行重定向, 均关联到新创建的epoll实例上。

所以MessageQueue的初始化就是在Native层创建了一个NativeMessageQueue的对象,该对象持有一个Native层的Looper对象。而Native层的Looper里有两个文件描述符:

  1. 通过eventfd创建的mWakeEventFd;
  2. 通过epoll_create1创建的代表epoll实例的mEpollFd。

四. sendMessageAtTime发送消息

现在回到Handler发送消息,假设Handler中的Looper是MainLooper, 现在是在非UI线程,比如bg线程读取网络数据后更新到UI组件上:uiHandler.sendMessageAtTime

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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) {
// 将Message的target设置为自己
msg.target = this;
msg.workSourceUid = ThreadLocalWorkSource.getUid();

// mAsynchronous表明是否异步执行
if (mAsynchronous) {
msg.setAsynchronous(true);
}
// 交给Handler的MessageQueue执行
return queue.enqueueMessage(msg, uptimeMillis);
}

4.1 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
boolean enqueueMessage(Message msg, long when) {
......
synchronized (this) {
......
// 标记该Message正在使用, 避免缓冲池重复使用该Message
msg.markInUse();
// 记录该Message期望执行的时间
msg.when = when;
// mMessages是一个Message对象,代表该MessageQueue队列的头节点
Message p = mMessages;
boolean needWake;

if (p == null || when == 0 || when < p.when) {
// 如果头节点是空的、传入的Message执行时间是0(立刻执行)
// 或者执行时间在头节点消息执行之前,将该Message作为链表新的头节点
msg.next = p;
mMessages = msg;
// mBlocked为false代表Handler所在线程已经拿到合适的Message执行了
needWake = mBlocked;
} else {
// 将Message插入到链表头节点之后
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
// 找到该Message的位置,即其执行时间在链表中的顺序排列位置
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;
}

// 是否需要唤醒, 唤醒什么,当然是Handler的Looper对应线程了!
if (needWake) {
// 进入JNI, 通过epoll唤醒线程
nativeWake(mPtr);
}
}
return true;
}

所以Handler.sendMessage仅仅是将Message插入MessageQueue中Message链表的合适位置,即保持mMessages链表中的Message期望执行时间从小到大排列,等待执行。

4.2 android_os_MessageQueue_nativeWake

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

转到native层的loop执行。

4.3 Looper.cpp:wake

1
2
3
4
5
6
7
8
9
10
11
void Looper::wake() {
uint64_t inc = 1;
// 通过write向该Looper的mWakeEventFd中写入1
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));
}
}
}

到这里,bg线程中uiHandler发送Message的流程就结束了。

五. UI线程处理Message

那么此时我们UI线程在做什么呢? 对了,就是一直在循环执行 Looper中的 loopOnce 函数!

1
2
3
4
5
6
private static boolean loopOnce(final Looper me,
final long ident, final int thresholdOverride) {
// 5.1 通过MessageQueue获取下一个Message
Message msg = me.mQueue.next();
......
}

5.1 MessageQueue.next

1
2
3
4
5
6
7
8
9
10
11
Message next() {
......
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
for (;;) {
......
// 5.2 转到Native中执行,获取下一次poll的时间
nativePollOnce(ptr, nextPollTimeoutMillis);
......
}
}

直接转到native层执行pollOnce.

5.2 android_os_MessageQueue_nativePollOnce

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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;
// 还是用到Native层的Looper
mLooper->pollOnce(timeoutMillis);
mPollObj = NULL;
mPollEnv = NULL;

if (mExceptionObj) {
env->Throw(mExceptionObj);
env->DeleteLocalRef(mExceptionObj);
mExceptionObj = NULL;
}
}

5.3 Looper.cpp: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
inline int pollOnce(int timeoutMillis) {
return pollOnce(timeoutMillis, nullptr, nullptr, nullptr);
}

int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
int result = 0;
for (;;) {
// 当前mResponses还是空的,mResponseIndex为0
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 (outFd != nullptr) *outFd = fd;
if (outEvents != nullptr) *outEvents = events;
if (outData != nullptr) *outData = data;
return ident;
}
}
// result为0, 表明poll超时
if (result != 0) {
if (outFd != nullptr) *outFd = 0;
if (outEvents != nullptr) *outEvents = 0;
if (outData != nullptr) *outData = nullptr;
return result;
}
// 先执行这里
result = pollInner(timeoutMillis);
}
}

5.4 Looper.cpp:pollInner

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
int Looper::pollInner(int timeoutMillis) {
......
// Poll.
int result = POLL_WAKE;
mResponses.clear();
mResponseIndex = 0;
// 标记正在poll
mPolling = true;

// EPOLL_MAX_EVENTS默认是16
struct epoll_event eventItems[EPOLL_MAX_EVENTS];
// 通过epoll_wait监听mEpollFd文件描述符等待被唤醒, 注意这里timeoutMillis是0
// 也就是说当mEpollFd没有事件时,立刻返回超时 0
int eventCount = epoll_wait(mEpollFd.get(), eventItems, EPOLL_MAX_EVENTS, timeoutMillis);
......

// poll超时,在执行一次Looper.pollOnce的循环
if (eventCount == 0) {
result = POLL_TIMEOUT;
goto Done;
}

// epoll中存在事件
for (int i = 0; i < eventCount; i++) {
int fd = eventItems[i].data.fd;
uint32_t epollEvents = eventItems[i].events;
// 当epoll中事件描述符是当前Looper的mWakeEventFd时, 说明有线程通过write向该fd写入值
if (fd == mWakeEventFd.get()) {
if (epollEvents & EPOLLIN) {
// 5.5 执行被唤醒后的处理
awoken();
} else {
ALOGW("Ignoring unexpected epoll events 0x%x on wake event fd.", epollEvents);
}
}
......
}
Done: ;

......
return result;
}

int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);

等待事件的产生,类似于select()调用。参数events用来从内核得到事件的集合,maxevents告之内核这个events有多大,参数timeout是超时时间(毫秒,0会立即返回,-1将不确定,也有说法说是永久阻塞)。该函数返回需要处理的事件数目,如返回0表示已超时。如果返回–1,则表示出现错误。

  1. epfd是 epoll的描述符。
  2. events则是分配好的 epoll_event结构体数组,epoll将会把发生的事件复制到 events数组中
  3. maxevents表示本次可以返回的最大事件数目,通常 maxevents参数与预分配的events数组的大小是相等的。
  4. timeout表示在没有检测到事件发生时最多等待的时间(单位为毫秒),如果 timeout为0,则表示 epoll_wait在 rdllist链表中为空,立刻返回,不会等待。

5.5 Looper.cpp:awoken

1
2
3
4
void Looper::awoken() {
uint64_t counter;
TEMP_FAILURE_RETRY(read(mWakeEventFd.get(), &counter, sizeof(uint64_t)));
}

读取mWakeEventFd中的值,也就是之前bg线程通过write写入的1. 然后回到Looper.cpp:pollOnce返回1.

这样UI线程就从epoll_wait阻塞状态(或者一直执行Looper.cpp:pollOnce函数的状态)退出,之后回到java层的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
Message next() {
......
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
for (;;) {
......
// 5.2 转到Native中执行,获取下一次poll的时间
nativePollOnce(ptr, nextPollTimeoutMillis);

synchronized (this) {
// 记录当前系统时间
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
......
// 尝试找到抵达执行时间的Message
if (msg != null) {
if (now < msg.when) {
// 如果头节点Message的执行时间尚未到来,那么下一次epoll_wait的等待时间就是
// 该message执行时间和当前时间的差值
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// 找到可执行的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();
// 打破循环,返回该Message,回到Looper.loopOnce中
// 即执行 [1.4.1] Handler.dispatchMessage
return msg;
}
} else {
// No more messages.
nextPollTimeoutMillis = -1;
}
......
}
}
}

自此,Android的线程切换就结束了。

六. 小结

通过上述分析,画一张图来展示一次Message的执行:

Message Handle

6.1 Epoll机制

关于Eopll推荐大家阅读这篇文: Epoll本质 https://zhuanlan.zhihu.com/p/63179839

  1. cpu running
  1. Ui Thread: epoll_wait
  1. Bg Thread: write fd
  1. Ui Thread: read

欢迎关注我的其它发布渠道