源码基于 Android S AOSP,源码在线查看地址: cs.android.com/android/pla…
线程间通信在 Android 系统中应用十分广泛,本文是一个系列文章,主要梳理了Android 中 Java、native 层的线程间通信机制。
- Android 消息机制 - Java 层
- Android 消息机制 - Java 层 - MessagePool
- Android 消息机制 - Native 层实现 - 以 InputReader 与 InputDispatcher 间通信为背景
- Android 消息机制 - Java 层依赖 native 层实现 wait
- Android 消息机制 - 总结
前几篇文章中,分析了一下Java层线程间通信Handler,并以一个简单的Handler示例开始,追踪了一下源码,源码分析期间,分析到Java层的Handler需要依赖native层实现wait,我们又分析了一下native层是如何实现wait的
紧接着,以system_server中InputReader与InputDispatcher两个线程为例,分析了Looper是如何实现InputReader唤醒InputDispatcher的。
Content
在Java层体系中,整体流程如下:
- 线程中调用
Looper.prepare()
创建Looper并放在当前线程的ThreadLocal中,初始化MessageQueue - 线程中调用
Looper.loop()
,开启死循环,不断的polling MessageQueue,有消息则取出处理(在message.target.dispatchMessage中处理),无消息则调用native层nativePollOnce实现wait - 创建Handler的时候会从当前线程的ThreadLocal中取出looper,在Looper中拿到MessageQueue
- 调用
Handler.sendMessage()
会将message.target指向当前Handler(即上述message.target.dispatchMessage会到Handler中处理) - 将Message通过
enqueueMessage()
的方式加入到MessageQueue的链表中 - 通过nativeWake的方式唤醒nativePollOnce
nativePollOnce整体流程如下:
- 在Java层构建MessageQueue的过程中,会调用nativeInit创建一个native层的NativeMessageQueue,并返回句柄给java层的MessageQueue
- NativeMessageQueue在构建的过程中会创建native层的Looper
- native层的Looper在构建的过程中会创建好epoll
- 调用nativePollOnce会从NativeMessageQueue调用到native的
Looper.pollInner
Looper.pollInner
内会调用epoll_wait实现等待,等待对端向fd写数据
nativeWake整体流程如下:
- 通过NativeMessageQueue调用到native层的Looper.wake方法
- Looper.wake向fd中写入整数1(写入的什么数据不重要,主要是要唤醒epoll_wait)
- Looper.pollInner中的epoll_wait被唤醒
system_server中InputReader与InputDispatcher的间通信整体流程如下:
- InputManager创建InputReader与InputDispatcher
- 创建InputDispatcher的过程中会在InputDispatcher对象内部创建一个Looper(native)
- 启动InputDispatcher线程
- 构造InputReader的过程中会传入InputDispatcher,将InputDispatcher加入到QueuedInputListener
- 启动InputReader线程
- InputReader线程从EventHub接收到Event后,将Event push_back到QueuedInputListener容器内
- 紧接着InputReader调用QueuedInputListener.flush方法,遍历容器内的Event,调用NotifyArgs.notify方法
- 在NotifyArgs.notify方法内调用InputDispatcher对象(此时并不在InputDispatcher线程内,只是调用InputDispatcher对象)内的notifyKey方法
- InputDispatcher.notifyKey调用InputDispatcher.mLooper.wake方法,唤醒InputDispatcher线程内的dispatchOnce,InputDispatcher线程被唤醒,开始工作。
从上述流程中可以看出,native层整体是依赖于native的Looper类实现的,而NativeMessageQueue只不过的Java层的MessageQueue到native层的Looper的一个过度,在NativeMessageQueue中并没有很重要的逻辑。
另外,在InputDispatcher与InputReader的线程通讯中,InputReader唤醒InputDispatcher是直接通过Looper实现的,并没有经过NativeMessageQueue,进一步验证了NativeMessageQueue只是Java层与native层的一个过度。
在Java层的Handler中,并没有采用Object类中的wait以及notify方法实现等待,而是采用linux中的epoll_wait模型实现,这么做的原因应该是为了执行速度吧,毕竟epoll_wait性能更好一点。