了解更多,移步Android触摸事件传递机制系列详解
1 概述
- 当用户触摸屏幕或者按键操作,首次触发的是硬件驱动,驱动收到事件后,将该相应事件写入到输入设备节点, 这便产生了最原生态的内核事件。
- 接着,输入系统取出原生态的事件,经过层层封装后成为
KeyEvent
或者MotionEvent
; - 最后,交付给相应的目标窗口(
Window
)来消费该输入事件。可见,输入系统在整个过程起到承上启下的衔接作用。
2 Input
模块的主要组成:
-
Native
层的InputReader
负责从EventHub
取出事件并处理,再交给InputDispatcher
; -
Native
层的InputDispatcher
接收来自InputReader
的输入事件,并记录WMS的窗口信息,用于派发事件到合适的窗口; - Java层的
InputManagerService
跟WMS交互,WMS记录所有窗口信息,并同步更新到IMS,为InputDispatcher
正确派发事件到ViewRootImpl
提供保障;
3 整体框架类图
InputManagerService
作为system_server
中的重要服务,继承于IInputManager.Stub
, 作为Binder
服务端,那么Client
位于InputManager
的内部通过IInputManager.Stub.asInterface()
获取Binder
代理端,C/S两端通信的协议是由IInputManager.aidl
来定义的。
图解:
-
InputManagerService
位于Java
层的InputManagerService.java
文件;
a. 其成员mPtr
指向Native
层的NativeInputManager
对象; -
NativeInputManager
位于Native
层的com_android_server_input_InputManagerService.cpp
文件;
a. 其成员mServiceObj
指向Java
层的IMS
对象;
b. 其成员mLooper
是指“android.display”线程的Looper
; -
InputManager
位于libinputflinger
中的InputManager.cpp文件;
a.InputDispatcher
和InputReader
的成员变量mPolicy
都是指NativeInputManager
对象;
b.InputReader
的成员mQueuedListener
,数据类型为QueuedInputListener
;通过其内部成员变量mInnerListener
指向InputDispatcher
对象; 这便是InputReader
跟InputDispatcher
交互的中间枢纽。
4 启动调用栈(流程)
IMS服务是伴随着system_server
进程的启动而启动,整个调用过程:
InputManagerService(初始化)
nativeInit
NativeInputManager
EventHub
InputManager
InputDispatcher
Looper
InputReader
QueuedInputListener
InputReaderThread
InputDispatcherThread
IMS.start(启动)
nativeStart
InputManager.start
InputReaderThread->run
InputDispatcherThread->run
整个过程首先创建如下对象:NativeInputManager
,EventHub
,InputManager
, InputDispatcher
,InputReader
,InputReaderThread
,InputDispatcherThread
。 接着便是启动两个工作线程InputReader
,InputDispatcher
。
5 IMS启动过程
private void startOtherServices() {
//1. 初始化IMS对象
inputManager = new InputManagerService(context);
ServiceManager.addService(Context.INPUT_SERVICE, inputManager);
...
//将InputMonitor对象保持到IMS对象
inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
//2
inputManager.start();
}
通过上述代码接下,分InputManagerService初始化和InputManagerService的启动来写。
6 InputManagerService初始化
6.1 构造方法
创建InputManagerService对象--构造方法:[-> InputManagerService.java]
public InputManagerService(Context context) {
this.mContext = context;
// 运行在线程"android.display"
this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());
...
//初始化native对象
mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
LocalServices.addService(InputManagerInternal.class, new LocalService());
}
6.2 构造方法中调用nativeInit
[-> com_android_server_input_InputManagerService.cpp]
static jlong nativeInit(JNIEnv* env, jclass /* clazz */, jobject serviceObj, jobject contextObj, jobject messageQueueObj) {
//获取native消息队列
sp messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
...
//创建Native的InputManager【见小节2.3】
NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
messageQueue->getLooper());
im->incStrong(0);
return reinterpret_cast(im); //返回Native对象的指针
}
6.3 nativeInit中创建NativeInputManager
[-> com_android_server_input_InputManagerService.cpp]
NativeInputManager::NativeInputManager(jobject contextObj,
jobject serviceObj, const sp& looper) :
mLooper(looper), mInteractive(true) {
JNIEnv* env = jniEnv();
mContextObj = env->NewGlobalRef(contextObj); //上层IMS的context
mServiceObj = env->NewGlobalRef(serviceObj); //上层IMS对象
...
sp eventHub = new EventHub(); // 创建EventHub对象【见小节2.4】
mInputManager = new InputManager(eventHub, this, this); // 创建InputManager对象
}
6.4 NativeInputManager中创建EventHub
[-> EventHub.cpp]
EventHub::EventHub(void) :
mBuiltInKeyboardId(NO_BUILT_IN_KEYBOARD), mNextDeviceId(1), mControllerNumbers(),
mOpeningDevices(0), mClosingDevices(0),
mNeedToSendFinishedDeviceScan(false),
mNeedToReopenDevices(false), mNeedToScanDevices(true),
mPendingEventCount(0), mPendingEventIndex(0), mPendingINotify(false) {
acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
//创建epoll
mEpollFd = epoll_create(EPOLL_SIZE_HINT);
mINotifyFd = inotify_init();
//此处DEVICE_PATH为"/dev/input",监听该设备路径
int result = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE);
struct epoll_event eventItem;
memset(&eventItem, 0, sizeof(eventItem));
eventItem.events = EPOLLIN;
eventItem.data.u32 = EPOLL_ID_INOTIFY;
//添加INotify到epoll实例
result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem);
int wakeFds[2];
result = pipe(wakeFds); //创建管道
mWakeReadPipeFd = wakeFds[0];
mWakeWritePipeFd = wakeFds[1];
//将pipe的读和写都设置为非阻塞方式
result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);
result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK);
eventItem.data.u32 = EPOLL_ID_WAKE;
//添加管道的读端到epoll实例
result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, &eventItem);
...
}
该方法主要功能:
- 初始化INotify(监听”/dev/input”),并添加到epoll实例
- 创建非阻塞模式的管道,并添加到epoll;
6.5 NativeInputManager中创建InputManager
[-> InputManager.cpp]
InputManager::InputManager(
const sp& eventHub,
const sp& readerPolicy,
const sp& dispatcherPolicy) {
//创建InputDispatcher对象
mDispatcher = new InputDispatcher(dispatcherPolicy);
//创建InputReader对象
mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
initialize();
}
InputDispatcher
和InputReader
的mPolicy
成员变量都是指NativeInputManager
对象。
6.6 InputManager中创建InputDispatcher
[-> InputDispatcher.cpp]
InputDispatcher::InputDispatcher(const sp& policy) :
mPolicy(policy),
mPendingEvent(NULL), mLastDropReason(DROP_REASON_NOT_DROPPED),
mAppSwitchSawKeyDown(false), mAppSwitchDueTime(LONG_LONG_MAX),
mNextUnblockedEvent(NULL),
mDispatchEnabled(false), mDispatchFrozen(false), mInputFilterEnabled(false),
mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE) {
//创建Looper对象
mLooper = new Looper(false);
mKeyRepeatState.lastKeyEntry = NULL;
//获取分发超时参数
policy->getDispatcherConfiguration(&mConfig);
}
该方法主要工作:
- 创建属于自己线程的
Looper
对象; - 超时参数来自于IMS,参数默认值
keyRepeatTimeout
= 500,keyRepeatDelay
= 50。
6.7 InputManager中创建InputReader
[-> InputReader.cpp]
InputReader::InputReader(const sp& eventHub,
const sp& policy,
const sp& listener) :
mContext(this), mEventHub(eventHub), mPolicy(policy),
mGlobalMetaState(0), mGeneration(1),
mDisableVirtualKeysTimeout(LLONG_MIN), mNextTimeout(LLONG_MAX),
mConfigurationChangesToRefresh(0) {
// 创建输入监听对象
mQueuedListener = new QueuedInputListener(listener);
{
AutoMutex _l(mLock);
refreshConfigurationLocked(0);
updateGlobalMetaStateLocked();
}
}
此处mQueuedListener
的成员变量mInnerListener
便是InputDispatcher
对象。 InputManager
创建完InputDispatcher
和InputReader
对象, 接下里便是调用initialize初始化。
6.8 InputManager中初始化initialize
InputManager创建完InputDispatcher和InputReader对象, 接下里便是调用initialize初始化。
[-> InputManager.cpp]
void InputManager::initialize() {
//创建线程“InputReader”
mReaderThread = new InputReaderThread(mReader);
//创建线程”InputDispatcher“
mDispatcherThread = new InputDispatcherThread(mDispatcher);
}
InputReaderThread::InputReaderThread(const sp& reader) :
Thread(/*canCallJava*/ true), mReader(reader) {
}
InputDispatcherThread::InputDispatcherThread(const sp& dispatcher) :
Thread(/*canCallJava*/ true), mDispatcher(dispatcher) {
}
初始化的主要工作就是创建两个能访问Java代码的native线程。
- 创建线程“InputReader”
- 创建线程”InputDispatcher“
整个的InputManagerService对象初始化过程并完成,接下来便是调用其start方法。
7 IMS.start
[-> InputManagerService.java]
public void start() {
// 启动native对象[见小节2.10]
nativeStart(mPtr);
Watchdog.getInstance().addMonitor(this);
//注册触摸点速度和是否显示功能的观察者
registerPointerSpeedSettingObserver();
registerShowTouchesSettingObserver();
mContext.registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
updatePointerSpeedFromSettings();
updateShowTouchesFromSettings();
}
}, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mHandler);
updatePointerSpeedFromSettings(); //更新触摸点的速度
updateShowTouchesFromSettings(); //是否在屏幕上显示触摸点
}
7.1 start中调用nativeStart
[-> com_android_server_input_InputManagerService.cpp]
static void nativeStart(JNIEnv* env, jclass /* clazz */, jlong ptr) {
//此处ptr记录的便是NativeInputManager
NativeInputManager* im = reinterpret_cast(ptr);
// [见小节7.2]
status_t result = im->getInputManager()->start();
...
}
7.2 InputManager.start
[InputManager.cpp]
status_t InputManager::start() {
result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);
result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);
...
return OK;
}
该方法的主要功能是启动两个线程:
- 启动线程“InputReader”
- 启动线程”InputDispatcher“
8 总结
分层视角:
- Java层
InputManagerService
:采用android.display
线程处理Message
. - JNI的
NativeInputManager
:采用android.display
线程处理Message
,以及创建EventHub
。 - Native的
InputManager
:创建InputReaderThread
和InputDispatcherThread
两个线程
主要功能:
- IMS服务中的成员变量mPtr记录Native层的NativeInputManager对象;
- IMS对象的初始化过程的重点在于native初始化,分别创建了以下对象:
NativeInputManager
;
EventHub
,InputManager
;
InputReader
,InputDispatcher
;
InputReaderThread
,InputDispatcherThread
- IMS启动过程的主要功能是启动以下两个线程:
InputReader
:从EventHub
取出事件并处理,再交给InputDispatcher
InputDispatcher
:接收来自InputReader
的输入事件,并派发事件到合适的窗口。
从整个启动过程,可知有system_server
进程中有3个线程跟Input输入系统息息相关,分别是android.display
, InputReader
,InputDispatcher
。
- InputDispatcher线程:属于
Looper
线程,会创建属于自己的Looper
,循环分发消息; - InputReader线程:通过
getEvents()
调用EventHub
读取输入事件,循环读取消息; - android.display线程:属于
Looper
线程,用于处理Java层的IMS.InputManagerHandler
和JNI层的NativeInputManager
中指定的MessageHandler
消息;
参考
Android系统源码分析-事件收集
Android 输入系统(一)InputManagerService
Input系统—启动篇