了解更多,移步Android觸摸事件傳遞機(jī)制系列詳解
1 概述
- 當(dāng)用戶觸摸屏幕或者按鍵操作,首次觸發(fā)的是硬件驅(qū)動,驅(qū)動收到事件后,將該相應(yīng)事件寫入到輸入設(shè)備節(jié)點, 這便產(chǎn)生了最原生態(tài)的內(nèi)核事件。
- 接著,輸入系統(tǒng)取出原生態(tài)的事件,經(jīng)過層層封裝后成為
KeyEvent或者MotionEvent; - 最后,交付給相應(yīng)的目標(biāo)窗口(
Window)來消費該輸入事件??梢?,輸入系統(tǒng)在整個過程起到承上啟下的銜接作用。
2 Input模塊的主要組成:
-
Native層的InputReader負(fù)責(zé)從EventHub取出事件并處理,再交給InputDispatcher; -
Native層的InputDispatcher接收來自InputReader的輸入事件,并記錄WMS的窗口信息,用于派發(fā)事件到合適的窗口; - Java層的
InputManagerService跟WMS交互,WMS記錄所有窗口信息,并同步更新到IMS,為InputDispatcher正確派發(fā)事件到ViewRootImpl提供保障;
3 整體框架類圖
InputManagerService作為system_server中的重要服務(wù),繼承于IInputManager.Stub, 作為Binder服務(wù)端,那么Client位于InputManager的內(nèi)部通過IInputManager.Stub.asInterface()獲取Binder代理端,C/S兩端通信的協(xié)議是由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,數(shù)據(jù)類型為QueuedInputListener;通過其內(nèi)部成員變量mInnerListener指向InputDispatcher對象; 這便是InputReader跟InputDispatcher交互的中間樞紐。
4 啟動調(diào)用棧(流程)
IMS服務(wù)是伴隨著system_server進(jìn)程的啟動而啟動,整個調(diào)用過程:
InputManagerService(初始化)
nativeInit
NativeInputManager
EventHub
InputManager
InputDispatcher
Looper
InputReader
QueuedInputListener
InputReaderThread
InputDispatcherThread
IMS.start(啟動)
nativeStart
InputManager.start
InputReaderThread->run
InputDispatcherThread->run
整個過程首先創(chuàng)建如下對象: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 構(gòu)造方法
創(chuàng)建InputManagerService對象--構(gòu)造方法:[-> 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 構(gòu)造方法中調(diào)用nativeInit
[-> com_android_server_input_InputManagerService.cpp]
static jlong nativeInit(JNIEnv* env, jclass /* clazz */, jobject serviceObj, jobject contextObj, jobject messageQueueObj) {
//獲取native消息隊列
sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
...
//創(chuàng)建Native的InputManager【見小節(jié)2.3】
NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
messageQueue->getLooper());
im->incStrong(0);
return reinterpret_cast<jlong>(im); //返回Native對象的指針
}
6.3 nativeInit中創(chuàng)建NativeInputManager
[-> com_android_server_input_InputManagerService.cpp]
NativeInputManager::NativeInputManager(jobject contextObj,
jobject serviceObj, const sp<Looper>& looper) :
mLooper(looper), mInteractive(true) {
JNIEnv* env = jniEnv();
mContextObj = env->NewGlobalRef(contextObj); //上層IMS的context
mServiceObj = env->NewGlobalRef(serviceObj); //上層IMS對象
...
sp<EventHub> eventHub = new EventHub(); // 創(chuàng)建EventHub對象【見小節(jié)2.4】
mInputManager = new InputManager(eventHub, this, this); // 創(chuàng)建InputManager對象
}
6.4 NativeInputManager中創(chuàng)建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);
//創(chuàng)建epoll
mEpollFd = epoll_create(EPOLL_SIZE_HINT);
mINotifyFd = inotify_init();
//此處DEVICE_PATH為"/dev/input",監(jiān)聽該設(shè)備路徑
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); //創(chuàng)建管道
mWakeReadPipeFd = wakeFds[0];
mWakeWritePipeFd = wakeFds[1];
//將pipe的讀和寫都設(shè)置為非阻塞方式
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(監(jiān)聽”/dev/input”),并添加到epoll實例
- 創(chuàng)建非阻塞模式的管道,并添加到epoll;
6.5 NativeInputManager中創(chuàng)建InputManager
[-> InputManager.cpp]
InputManager::InputManager(
const sp<EventHubInterface>& eventHub,
const sp<InputReaderPolicyInterface>& readerPolicy,
const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
//創(chuàng)建InputDispatcher對象
mDispatcher = new InputDispatcher(dispatcherPolicy);
//創(chuàng)建InputReader對象
mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
initialize();
}
InputDispatcher和InputReader的mPolicy成員變量都是指NativeInputManager對象。
6.6 InputManager中創(chuàng)建InputDispatcher
[-> InputDispatcher.cpp]
InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& 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) {
//創(chuàng)建Looper對象
mLooper = new Looper(false);
mKeyRepeatState.lastKeyEntry = NULL;
//獲取分發(fā)超時參數(shù)
policy->getDispatcherConfiguration(&mConfig);
}
該方法主要工作:
- 創(chuàng)建屬于自己線程的
Looper對象; - 超時參數(shù)來自于IMS,參數(shù)默認(rèn)值
keyRepeatTimeout= 500,keyRepeatDelay= 50。
6.7 InputManager中創(chuàng)建InputReader
[-> InputReader.cpp]
InputReader::InputReader(const sp<EventHubInterface>& eventHub,
const sp<InputReaderPolicyInterface>& policy,
const sp<InputListenerInterface>& listener) :
mContext(this), mEventHub(eventHub), mPolicy(policy),
mGlobalMetaState(0), mGeneration(1),
mDisableVirtualKeysTimeout(LLONG_MIN), mNextTimeout(LLONG_MAX),
mConfigurationChangesToRefresh(0) {
// 創(chuàng)建輸入監(jiān)聽對象
mQueuedListener = new QueuedInputListener(listener);
{
AutoMutex _l(mLock);
refreshConfigurationLocked(0);
updateGlobalMetaStateLocked();
}
}
此處mQueuedListener的成員變量mInnerListener便是InputDispatcher對象。 InputManager創(chuàng)建完InputDispatcher和InputReader對象, 接下里便是調(diào)用initialize初始化。
6.8 InputManager中初始化initialize
InputManager創(chuàng)建完InputDispatcher和InputReader對象, 接下里便是調(diào)用initialize初始化。
[-> InputManager.cpp]
void InputManager::initialize() {
//創(chuàng)建線程“InputReader”
mReaderThread = new InputReaderThread(mReader);
//創(chuàng)建線程”InputDispatcher“
mDispatcherThread = new InputDispatcherThread(mDispatcher);
}
InputReaderThread::InputReaderThread(const sp<InputReaderInterface>& reader) :
Thread(/*canCallJava*/ true), mReader(reader) {
}
InputDispatcherThread::InputDispatcherThread(const sp<InputDispatcherInterface>& dispatcher) :
Thread(/*canCallJava*/ true), mDispatcher(dispatcher) {
}
初始化的主要工作就是創(chuàng)建兩個能訪問Java代碼的native線程。
- 創(chuàng)建線程“InputReader”
- 創(chuàng)建線程”InputDispatcher“
整個的InputManagerService對象初始化過程并完成,接下來便是調(diào)用其start方法。
7 IMS.start
[-> InputManagerService.java]
public void start() {
// 啟動native對象[見小節(jié)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中調(diào)用nativeStart
[-> com_android_server_input_InputManagerService.cpp]
static void nativeStart(JNIEnv* env, jclass /* clazz */, jlong ptr) {
//此處ptr記錄的便是NativeInputManager
NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
// [見小節(jié)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 總結(jié)
分層視角:
- Java層
InputManagerService:采用android.display線程處理Message. - JNI的
NativeInputManager:采用android.display線程處理Message,以及創(chuàng)建EventHub。 - Native的
InputManager:創(chuàng)建InputReaderThread和InputDispatcherThread兩個線程
主要功能:
- IMS服務(wù)中的成員變量mPtr記錄Native層的NativeInputManager對象;
- IMS對象的初始化過程的重點在于native初始化,分別創(chuàng)建了以下對象:
NativeInputManager;
EventHub,InputManager;
InputReader,InputDispatcher;
InputReaderThread,InputDispatcherThread - IMS啟動過程的主要功能是啟動以下兩個線程:
InputReader:從EventHub取出事件并處理,再交給InputDispatcher
InputDispatcher:接收來自InputReader的輸入事件,并派發(fā)事件到合適的窗口。
從整個啟動過程,可知有system_server進(jìn)程中有3個線程跟Input輸入系統(tǒng)息息相關(guān),分別是android.display, InputReader,InputDispatcher。
- InputDispatcher線程:屬于
Looper線程,會創(chuàng)建屬于自己的Looper,循環(huán)分發(fā)消息; - InputReader線程:通過
getEvents()調(diào)用EventHub讀取輸入事件,循環(huán)讀取消息; - android.display線程:屬于
Looper線程,用于處理Java層的IMS.InputManagerHandler和JNI層的NativeInputManager中指定的MessageHandler消息;

參考
Android系統(tǒng)源碼分析-事件收集
Android 輸入系統(tǒng)(一)InputManagerService
Input系統(tǒng)—啟動篇