一、Looper(Native)
序言
简介
在Android P源码分析之Handler(JAVA)篇中,我们分析了Java层的消息循环处理流程,其中Looper扮演着不断从消息队列中取出消息进行分发处理的重要角色.而在Native层中,也存在着相同作用的Looper.
示例
类定义1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22class LocalHandler : public MessageHandler, public LooperCallback{
/* MessageHandler为消息事务处理类, LooperCallback为Fd事务处理类 */
public:
virtual void handleMessage(const Message& message) {
/* 消息事务处理函数,在消费者线程consumerThread中执行 */
printf("tid : %d, receive message : %d\n", gettid(), message.what);
}
virtual int handleEvent(int fd, int events, void* data __unused) {
/* Fd事务处理函数,在消费者线程consumerThread中执行 */
char recvMsg[128] = { 0 };
if (events & Looper::EVENT_INPUT) {
if (read(fd, recvMsg, sizeof(recvMsg) / sizeof(*recvMsg)) < 0) {
printf("tid : %d, read fail, reason : %s\n",gettid(), strerror(errno));
return 0;
}
printf("tid : %d, receive event : %s\n",gettid(), recvMsg);
}
return 1;
}
};
消费者线程执行体1
2
3
4
5
6
7
8
9
10
11void *consumerThread_func(void *arg __unused) {
looper = Looper::prepare(0); /* 创建线程唯一的Looper对象并绑定到消费者线程,见1.1 */
sem_post(&sem); /* 通知生产者线程producerThread Looper就绪 */
while (consumeThreadExit == 0) {
/* 循环处理Looper事务,见1.4 */
looper -> pollOnce(-1);
}
return NULL;
}
生产者线程执行体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
26void *producerThread_func(void *arg __unused) {
char msg[128] = { 0 };
int fd[2];
/* 创建事务处理者handler */
sp<LocalHandler> handler = new LocalHandler();
/* 创建pipe,其中fd[0]为读取端,fd[1]为写入端 */
pipe(fd);
/* 等待消费者线程初始化Looper */
sem_wait(&sem);
printf("tid : %d sem_wait looper prepare success\n",gettid());
/* 发送消息事务Message,唤醒消费者线程consumerThread处理消息事务 */
looper -> sendMessage(handler, Message());
/* 添加Fd事务请求:Fd为pipe读取端fd[0],事务类型为事件可读 */
looper -> addFd(fd[0], 0, Looper::EVENT_INPUT, handler, NULL);
/* 从终端读取字符串,并写到pipe的写入端fd[1]
* 此时pipe的poll状态变为可读,从而唤醒消费者线程consumerThread处理Fd事务
*/
fgets(msg, sizeof(msg) / sizeof(*msg), stdin);
write(fd[1], msg, strlen(msg) + 1);
close(fd[0]);
close(fd[1]);
return NULL;
}
运行结果1
2
3
4tid : 8234 sem_wait looper prepare success /* 生产者线程 */
tid : 8235, receive message : 0 /* 消费者线程处理消息事务 */
Hello World <---终端输入
tid : 8235, receive event : Hello World /* 消费者线程处理Fd事务 */
接下来我们将从消费者线程和生产者线程角度分析示例流程
源码分析
消费者线程
我们首先分析Looper(Native)的初始化函数prepare
1.1 prepare
1 | sp<Looper> Looper::prepare(int opts) { |
1.2 Looper构造函数
1 | Looper::Looper(bool allowNonCallbacks) { |
1.3 rebuildEpollLocked
1 | void Looper::rebuildEpollLocked() { |
小结
1.创建Looper对象并绑定到消费者线程
2.创建eventfd文件描述符mWakeEventFd
3.创建epoll文件描述符mEpollFd,并将mWakeEventFd添加到监听Fd事项中
接下来分析Looper(Native)事务处理函数pollOnce
1.4 pollOnce
1 | int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) { |
1.5 pollInner
1 | int Looper::pollInner(int timeoutMillis) { |
小结
1.消费者线程调用epoll_wait检测是否有事务就绪,如果无事务就绪则会进入休眠,等待事务就绪时唤醒
2.当Fd事项就绪时,消费者线程被唤醒.先处理消息事务MessageEnvelope(handleMessage),最后处理Fd就绪事务Response(handleEvent,返回值为0时epoll将移除对Fd事务请求request的监听)
生产者线程
我们首先分析下发送消息事务sendMessage
2.1 sendMessage
1 | void Looper::sendMessage(const sp<MessageHandler>& handler, const Message& message) { |
2.2 sendMessageAtTime
1 | void Looper::sendMessageAtTime(nsecs_t uptime, const sp<MessageHandler>& handler, |
2.3 wake
1 | void Looper::wake() { |
小结
1.生产者线程构建消息事务messageEnvelope,并入队到消费者线程的消息事务队列mMessageEnvelopes中(分发时间uptime升序排序)
2.如果入队位置为头节点,则调用wake唤醒消费者线程处理事务
接下来分析添加Fd事务请求addfd
2.4 addfd
1 | int Looper::addFd(int fd, int ident, int events, const sp<LooperCallback>& callback, void* data) { |
小结
1.生产者线程构建Fd事务请求request,并入队到消费者线程的Fd事务请求队列mRequests中
2.消费者线程mEpollFd添加fd事项监听
总结


1.消费者线程创建Looper(Native),并调用pollOnce处理事务,当无事务处理时,epoll_wait会让消费者线程进入休眠状态
2.生产者线程传入事务到消费者线程的事务队列中,并唤醒消费者线程进行处理
二、MessageQueue
简介
在Android P源码分析之Handler(JAVA)篇中,我们分析了MessageQueue类的取出消息next流程以及入队消息enqueueMessage流程
以上两个流程中,都有调用Native方法(nativePollOnce和nativeWake),接下来我们将对这两个Native方法进行分析
源码分析
我们首先分析MessageQueue的构造函数
3.1 MessageQueue构造函数
1 | MessageQueue(boolean quitAllowed) { |
3.2 nativeInit
1 | static jlong android_os_MessageQueue_nativeInit(JNIEnv* env, jclass clazz) { |
3.3 NativeMessageQueue构造函数
1 | NativeMessageQueue::NativeMessageQueue() { |
小结
1.MessageQueue(Java)构建了NativeMessageQueue(Native)对象,并记录该对象地址
2.NativeMessageQueue(Native)构建Looper(Native)对象,并绑定到消费者线程
接下来分析MessageQueue取出消息next函数中使用的nativePollOnce方法
3.4 next
1 | Message next() { |
3.5 nativePollOnce
1 | static void android_os_MessageQueue_nativePollOnce(JNIEnv* env, jobject obj, |
小结
1.Looper(Java)启动消息循环,先处理Looper(Native)事务,然后再处理Looper(Java)事务
2.Looper(Native)和Looper(Java)均无事务处理时,消费者线程会进入超时休眠状态,等待事务就绪时唤醒
最后分析入队消息enqueueMessage函数中使用的nativeWake方法
3.6 enqueueMessage
1 | boolean enqueueMessage(Message msg, long when) { |
3.7 nativeWake
1 | static void android_os_MessageQueue_nativeWake(JNIEnv* env, jclass clazz, jlong ptr) { |
小结
生产者线程将消息事务Message(Java)入队到消费者线程的消息队列MessageQueue(Java)中,如果符合唤醒条件则会调用Native方法nativeWake唤醒消费者线程
三、全文总结

本章完