了解更多敦捧,移步Android觸摸事件傳遞機制系列詳解
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
負責(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
進程的啟動而啟動译柏,整個調(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ù)默認值
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
進程中有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)—啟動篇