[M0]Android Native层Looper详解
2015-07-19 11:24
701 查看
原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。/article/8794749.html
代码版本
http://androidxref.com/6.0.1_r10/xref/system/core/include/utils/Looper.h
http://androidxref.com/6.0.1_r10/xref/system/core/libutils/Looper.cpp
在sendMessage()时,需要指定MessageHandler, 根据Message 和 MessageHandler创建MessageEnvelope 。然后将MessageEnvelope 添加到Looper的消息队列 mMessageEnvelopes 中。
Native Looper除了处理Message之外,还可以监听指定的文件描述符。
- 通过addFd() 添加要监听的fd到epoll的监听队列中,并将传进来的fd,ident,callback,data 封装成Request 对象,然后加入到Looper 的mRequests 中。
- 当该fd有事件发生时,epoll_wait()会返回epoll event,然后从mRequests中找到对应的request对象,并加上返回的epoll event 类型(EPOLLIN、EPOLLOUT…)封装成Response对象,加入到mResponses 中。
- 然后在需要处理Responses的时候,从mResponses遍历取出Response进行处理。
addFd() 的具体使用介绍请参考 Android Native Looper机制 - 监听文件描述符
直接调用Looper 构造函数:
调用Looper的静态函数 prepare() :如果线程已经有对应的Looper,则直接返回,否则才会创建新的Looper。
Looper的构造函数里主要做两件事情:
- 调用eventfd(0, EFD_NONBLOCK)返回mWakeEventFd,用于唤醒epoll_wait()
- 调用rebuildEpollLocked() 创建epoll 文件描述符,并将mWakeEventFd加入到epoll监听队列中
当需要唤醒Looper时,调用wake(), 会往mWakeEventFd中write 1
epoll_wait() 则会返回。然后调用awoken() ,
发送消息的函数有如下三个,但最终都是调用sendMessageAtTime() 来实现的。
来看一下sendMessageAtTime()函数的具体实现:
首先根据uptime在mMessageEnvelopes遍历,找到合适的位置,并将message 封装成MessageEnvlope,插入找到的位置上。
然后决定是否要唤醒Looper:
如果Looper此时正在派发message,则不需要wakeup Looper。因为这一次looper处理完消息之后,会重新估算下一次epoll_wait() 的wakeup时间。
如果是插在消息队列的头部,则需要立即wakeup Looper。
Looper提供了接口:pollOnce()
如果Looper中没有任何要处理的event/message,则会阻塞在epoll_wait() 等待事件到来。
调用流程:pollOnce() ->pollInner()->epoll_wait()
epoll_wait()其有三种情况会返回,返回值eventCount为上来的epoll event数量。
- 出现错误返回, eventCount < 0;
- timeout返回,eventCount = 0,表明监听的文件描述符中都没有事件发生,将直接进行native message的处理;
- 监听的文件描述符中有事件发生导致的返回,eventCount > 0; 有eventCount 数量的epoll event 上来。
然后调用pollInner(), pollInner() 调用 epoll_wait() 阻塞等待。这里会处理消息队列 mMessageEnvelopes 的Message,和 mResponses中ident 为POLL_CALLBACK的事件。
pollInner() 中只处理了mResponses中ident 为POLL_CALLBACK的事件,其他ident >= 0的事件,则在这时处理,处理完返回ident,以便caller 知道是否需要继续处理。
mNextMessageUptime 是 消息队列 mMessageEnvelopes 中最近一个即将要被处理的message的时间点。
所以需要根据mNextMessageUptime 与 调用者传下来的timeoutMillis 比较计算出一个最小的timeout,这将决定epoll_wait() 可能会阻塞多久才会返回。
epoll_wait()
处理epoll_wait() 返回的epoll events.
判断epoll event 是哪个fd上发生的事件
如果是mWakeEventFd,则执行awoken(). awoken() 只是将数据read出来,然后继续往下处理了。其目的也就是使epoll_wait() 从阻塞中返回。
如果是通过Looper.addFd() 接口加入到epoll监听队列的fd,并不是立马处理,而是先push到mResponses,后面再处理。
处理消息队列 mMessageEnvelopes 中的Message.
如果还没有到处理时间,就更新一下mNextMessageUptime
处理刚才放入mResponses中的 事件.
只处理ident 为POLL_CALLBACK的事件。其他事件在pollOnce中处理
- native层通过 sendMessage() 存放在mMessageEnvelopes中的MessageEnvelope。
- 通过 addFd() 加入epoll监听队列的fd,并且其对应的callback不为null的。
- 剩下的就是加入epoll监听列表的fd,但是没有指定callback,但是可以通过返回事件的ident来require caller进行处理的。
他们被处理的顺序如同以上描述顺序。
原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。/article/8794749.html
前言
我们知道Java 层的Looper 的消息队列在没有消息处理的时候,会wait在MessageQueue.next() 函数里,对于MessageQueue.next() 函数是如何实现的wait,却是一知半解。而且Android Framework部分有很多在Native层使用Looper 监听文件描述符的用法,比如InputDispatcher等,了解Android Native 层Looper的实现,可以对整个Android系统的消息循环机制有更深入的理解。代码版本
http://androidxref.com/6.0.1_r10/xref/system/core/include/utils/Looper.h
http://androidxref.com/6.0.1_r10/xref/system/core/libutils/Looper.cpp
Looper接口说明
Function | Desription |
---|---|
Looper(bool allowNonCallbacks); | Looper 构造函数 |
static sp< Looper> prepare(int opts); | 如果该线程没有绑定Looper,才创建Looper,否则直接返回。 |
int pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData); | 轮询,等待事件发生 |
void wake(); | 唤醒Looper |
void sendMessage(const sp< MessageHandler>& handler, const Message& message); | 发送消息 |
int addFd(int fd, int ident, int events, Looper_callbackFunc callback, void* data); | 添加要监听的文件描述符fd |
Class Diagram
Looper 类图如下:在sendMessage()时,需要指定MessageHandler, 根据Message 和 MessageHandler创建MessageEnvelope 。然后将MessageEnvelope 添加到Looper的消息队列 mMessageEnvelopes 中。
Native Looper除了处理Message之外,还可以监听指定的文件描述符。
- 通过addFd() 添加要监听的fd到epoll的监听队列中,并将传进来的fd,ident,callback,data 封装成Request 对象,然后加入到Looper 的mRequests 中。
- 当该fd有事件发生时,epoll_wait()会返回epoll event,然后从mRequests中找到对应的request对象,并加上返回的epoll event 类型(EPOLLIN、EPOLLOUT…)封装成Response对象,加入到mResponses 中。
- 然后在需要处理Responses的时候,从mResponses遍历取出Response进行处理。
addFd() 的具体使用介绍请参考 Android Native Looper机制 - 监听文件描述符
int addFd(int fd, int ident, int events, Looper_callbackFunc callback, void* data); int addFd(int fd, int ident, int events, const sp<LooperCallback>& callback, void* data);
Create Looper
Looper提供两种方式创建Looper:直接调用Looper 构造函数:
Looper(bool allowNonCallbacks);
调用Looper的静态函数 prepare() :如果线程已经有对应的Looper,则直接返回,否则才会创建新的Looper。
static sp<Looper> prepare(int opts);
Looper的构造函数里主要做两件事情:
- 调用eventfd(0, EFD_NONBLOCK)返回mWakeEventFd,用于唤醒epoll_wait()
- 调用rebuildEpollLocked() 创建epoll 文件描述符,并将mWakeEventFd加入到epoll监听队列中
mEpollFd = epoll_create(EPOLL_SIZE_HINT); 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);
关于mWakeEventFd
关于eventfd也是linux新增的一个API,用于线程之间的通信。之前版本中是通过pipe,得到read&write fd:来实现的wakeup looper功能。当需要唤醒Looper时,调用wake(), 会往mWakeEventFd中write 1
void Looper::wake() { ... uint64_t inc = 1; ssize_t nWrite = TEMP_FAILURE_RETRY(write(mWakeEventFd, &inc, sizeof(uint64_t)));
epoll_wait() 则会返回。然后调用awoken() ,
void Looper::awoken() { ... uint64_t counter; TEMP_FAILURE_RETRY(read(mWakeEventFd, &counter, sizeof(uint64_t)));
Send Message
发送消息是指将消息插入到消息队列 mMessageEnvelopes。mMessageEnvelopes 里面的是根据时间顺序排列存放MessageEnvlope:下标越小,越早被处理。发送消息的函数有如下三个,但最终都是调用sendMessageAtTime() 来实现的。
void sendMessage(const sp<MessageHandler>& handler, const Message& message); void sendMessageDelayed(nsecs_t uptimeDelay, const sp<MessageHandler>& handler, const Message& message); void sendMessageAtTime(nsecs_t uptime, const sp<MessageHandler>& handler, const Message& message);
来看一下sendMessageAtTime()函数的具体实现:
首先根据uptime在mMessageEnvelopes遍历,找到合适的位置,并将message 封装成MessageEnvlope,插入找到的位置上。
然后决定是否要唤醒Looper:
如果Looper此时正在派发message,则不需要wakeup Looper。因为这一次looper处理完消息之后,会重新估算下一次epoll_wait() 的wakeup时间。
如果是插在消息队列的头部,则需要立即wakeup Looper。
Poll Looper
要让Looper运行起来才能处理消息。Looper提供了接口:pollOnce()
int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData);
如果Looper中没有任何要处理的event/message,则会阻塞在epoll_wait() 等待事件到来。
调用流程:pollOnce() ->pollInner()->epoll_wait()
struct epoll_event eventItems[EPOLL_MAX_EVENTS]; int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);
epoll_wait()其有三种情况会返回,返回值eventCount为上来的epoll event数量。
- 出现错误返回, eventCount < 0;
- timeout返回,eventCount = 0,表明监听的文件描述符中都没有事件发生,将直接进行native message的处理;
- 监听的文件描述符中有事件发生导致的返回,eventCount > 0; 有eventCount 数量的epoll event 上来。
Dispatch Message
Message/Event 都是在pollOnce() 和 pollInner() 中派发处理的。pollOnce()
主要是 先处理mResponses中 还没有被处理的事件:加入epoll监听列表的fd,但是没有指定callback,但是可以通过返回事件的ident来require caller进行处理的。然后调用pollInner(), pollInner() 调用 epoll_wait() 阻塞等待。这里会处理消息队列 mMessageEnvelopes 的Message,和 mResponses中ident 为POLL_CALLBACK的事件。
pollInner() 中只处理了mResponses中ident 为POLL_CALLBACK的事件,其他ident >= 0的事件,则在这时处理,处理完返回ident,以便caller 知道是否需要继续处理。
pollInner():
调整timeout:Adjust the timeout based on when the next message is due.mNextMessageUptime 是 消息队列 mMessageEnvelopes 中最近一个即将要被处理的message的时间点。
所以需要根据mNextMessageUptime 与 调用者传下来的timeoutMillis 比较计算出一个最小的timeout,这将决定epoll_wait() 可能会阻塞多久才会返回。
epoll_wait()
处理epoll_wait() 返回的epoll events.
判断epoll event 是哪个fd上发生的事件
如果是mWakeEventFd,则执行awoken(). awoken() 只是将数据read出来,然后继续往下处理了。其目的也就是使epoll_wait() 从阻塞中返回。
如果是通过Looper.addFd() 接口加入到epoll监听队列的fd,并不是立马处理,而是先push到mResponses,后面再处理。
处理消息队列 mMessageEnvelopes 中的Message.
如果还没有到处理时间,就更新一下mNextMessageUptime
处理刚才放入mResponses中的 事件.
只处理ident 为POLL_CALLBACK的事件。其他事件在pollOnce中处理
小结
主要针对三部分的事件进行派发处理:- native层通过 sendMessage() 存放在mMessageEnvelopes中的MessageEnvelope。
- 通过 addFd() 加入epoll监听队列的fd,并且其对应的callback不为null的。
- 剩下的就是加入epoll监听列表的fd,但是没有指定callback,但是可以通过返回事件的ident来require caller进行处理的。
他们被处理的顺序如同以上描述顺序。
总结
关于Android Native 层的Looper的实现就介绍到这里了。如有不清楚的地方,欢迎留言。原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。/article/8794749.html
相关文章推荐
- Android onClick 按钮单击事件 四种常用写法
- android下拉刷新之PullToRefreshListView(二)
- Asynctask使用小结
- Android Studio使用技巧
- android自定义button样式
- Android 四大组件学习之Activity三
- Android 之 ServiceManager与服务管理
- Android binder driver 分析
- Android 四大组件学习之Activity二
- Android中handler的使用及原理---学习笔记
- Android中handler的使用及原理---学习笔记
- Day04-SmartImageView
- MPAndroidChart开源图表库之折线图
- Android View深入学习(三),View的绘制(Draw)过程
- Android中实现版本更新(一)使用第三方sdk更新
- Android之——AsyncTask和Handler对比
- android中ProgressBar和ListView
- Android Binder- 一次完整的通信过程
- Android 四大组件学习之Activity一
- Android Graphics - Architecture