原計劃 input 輸入事件的學習分為兩節(jié)內(nèi)容學習并記錄述召,經(jīng)學習發(fā)現(xiàn)并遠不止這些內(nèi)容,所以決定重新寫 input 輸入事件番外篇,如需參考,請閱讀 input 輸入事件番外篇甚负;造成的不便,深表抱歉。
1. InputManagerService的啟動:安卓系統(tǒng)服務的啟動都是在 SystemServer 這個進程中梭域,我們可以在main()方法調用的 new SystemServer().run() 中找打如下代碼:
inputManager = new InputManagerService(context); // 構建InputManagerService對象斑举,見1.1
wm = WindowManagerService.main(context, inputManager,
mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
!mFirstBoot, mOnlyCore);
ServiceManager.addService(Context.WINDOW_SERVICE, wm);
ServiceManager.addService(Context.INPUT_SERVICE, inputManager);
mActivityManagerService.setWindowManager(wm);
inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
inputManager.start(); // 執(zhí)行start()方法,見1.2
1.1 InputManagerService 的構造函數(shù):
// InputManagerService.java中:構造函數(shù)
public InputManagerService(Context context) {
this.mContext = context;
this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());
mUseDevInputEventForAudioJack =
context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
// native方法病涨,com_android_server_input_InputManagerService.cpp中
mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
LocalServices.addService(InputManagerInternal.class, new LocalService());
}
我們在看看這個native方法:frameworks/base/services/core/jni目錄中
// native方法懂昂,com_android_server_input_InputManagerService.cpp
static jlong nativeInit(JNIEnv* env, jclass clazz,
jobject serviceObj, jobject contextObj, jobject messageQueueObj) {
// MessageQueue的指針
sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
if (messageQueue == NULL) {
jniThrowRuntimeException(env, "MessageQueue is not initialized.");
return 0;
}
// 就是這個對象
NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
messageQueue->getLooper());
im->incStrong(0);
return reinterpret_cast<jlong>(im);
}
// native方法,com_android_server_input_InputManagerService.cpp
NativeInputManager::NativeInputManager(jobject contextObj,
jobject serviceObj, const sp<Looper>& looper) :
mLooper(looper), mInteractive(true) {
// ...
sp<EventHub> eventHub = new EventHub();
mInputManager = new InputManager(eventHub, this, this);
}
上面的代碼中創(chuàng)建了一個 NativeInputManager 對象没宾,并且把這個對象返回了保存在 InputManagerService的 mPtr 中;然后再看看 new InputManager(eventHub, this, this):
// InputManager.cpp中:
InputManager::InputManager(
const sp<EventHubInterface>& eventHub,
const sp<InputReaderPolicyInterface>& readerPolicy,
const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
mDispatcher = new InputDispatcher(dispatcherPolicy);
// 傳入mDispatcher:讀到的信號沸柔,肯定是要通過 mDispatcher 回調的
mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
initialize();
}
// InputManager.cpp中:
void InputManager::initialize() {
mReaderThread = new InputReaderThread(mReader);
mDispatcherThread = new InputDispatcherThread(mDispatcher);
}
到這里循衰,我們就獲取到和輸入事件相關的幾個關鍵類:EventHub、InputReader褐澎、InputDispatcher会钝;另外 InputReaderThread 和 InputDispatcherThread 就是兩條處理線程;
1.2 執(zhí)行start()方法:inputManager.start();
public void start() {
Slog.i(TAG, "Starting input manager");
nativeStart(mPtr); // native 方法:關鍵代碼
// Add ourself to the Watchdog monitors.
Watchdog.getInstance().addMonitor(this);
registerPointerSpeedSettingObserver();
registerShowTouchesSettingObserver();
// 接收ACTION_USER_SWITCHED工三,這是關于多用戶切換的操作
mContext.registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
updatePointerSpeedFromSettings();
updateShowTouchesFromSettings();
}
}, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mHandler);
updatePointerSpeedFromSettings();
updateShowTouchesFromSettings();
}
com_android_server_input_InputManagerService.cpp 中的 nativeStart(mPtr) 方法:
// com_android_server_input_InputManagerService.cpp 中:
static void nativeStart(JNIEnv* env, jclass clazz, jlong ptr) {
NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
status_t result = im->getInputManager()->start(); // InputManager 的 start() 方法
if (result) {
jniThrowRuntimeException(env, "Input manager could not be started.");
}
}
// InputManager.cpp中:
status_t InputManager::start() {
status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);
if (result) {
ALOGE("Could not start InputDispatcher thread due to error %d.", result);
return result;
}
result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);
if (result) {
ALOGE("Could not start InputReader thread due to error %d.", result);
mDispatcherThread->requestExit();
return result;
}
return OK;
}
小結:nativeStart(mPtr) 方法就是把創(chuàng)建好的 c++ 對象 InputManager 傳入迁酸,然后調用 InputManager 的start() 方法,而在 InputManager::start() 中也很簡單俭正,啟動上面的兩條處理線程(mReaderThread 和mDispatcherThread)奸鬓;
2. InputReader 與 InputReaderThread:InputReaderThread繼承自C++的Thread類,Thread類封裝了pthread線程工具掸读,提供了與Java層Thread類相似的API串远。C++的Thread類提供了一個名為threadLoop()的純虛函數(shù),當線程開始運行后儿惫,將會在內(nèi)建的線程循環(huán)中不斷地調用threadLoop()澡罚,直到此函數(shù)返回false,則退出線程循環(huán)肾请,從而結束線程留搔。
InputReaderThread僅僅重寫了threadLoop()函數(shù):
// InputReader.cpp 中:
bool InputReaderThread::threadLoop() {
mReader->loopOnce();
return true;
}
// InputReader.cpp 中:
void InputReader::loopOnce() {
// ... 省略
// 見 注釋
size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
// ...
if (count) {
processEventsLocked(mEventBuffer, count); // 我們只關注 input 事件的輸入,見 2.1
}
// ...
}
注釋:這里涉及到EventHub铛铁,我們就在這里開始研究一下EventHub了:
(1)EventHub的構造函數(shù):
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);
/*(1)使用epoll_create()函數(shù)創(chuàng)建一個epoll對象**隔显。EPOLL_SIZE_HINT指定最大監(jiān)聽個數(shù)為8
這個epoll對象將用來監(jiān)聽設備節(jié)點是否有數(shù)據(jù)可讀(有無事件)***/
mEpollFd = epoll_create(EPOLL_SIZE_HINT);
//(2)創(chuàng)建一個inotify對象**。這個inotify對象將被用來監(jiān)聽設備節(jié)點的增刪事件
mINotifyFd = inotify_init();
// 將存儲設備節(jié)點的路徑/dev/input作為監(jiān)聽對象添加到inotify對象中避归。當此文件夾下的設備節(jié)點
int result = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE);
/*(3)接下來將mINotifyFd作為epoll的一個監(jiān)控對象荣月。當inotify事件到來時,epoll_wait()將
立刻返回梳毙,EventHub便可從mINotifyFd中讀取設備節(jié)點的增刪信息哺窄,并作相應處理 */
struct epoll_event eventItem;
memset(&eventItem, 0, sizeof(eventItem));
eventItem.events = EPOLLIN; // 監(jiān)聽mINotifyFd可讀
// 注意這里并沒有使用fd字段,而使用了自定義的值EPOLL_ID_INOTIFY
eventItem.data.u32 = EPOLL_ID_INOTIFY;
// 將對mINotifyFd的監(jiān)聽注冊到epoll對象中
result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem);
/* 在構造函數(shù)剩余的代碼中,EventHub創(chuàng)建了一個名為wakeFds的匿名管道萌业,并將管道讀取端
的描述符的可讀事件注冊到epoll對象中坷襟。因為InputReader在執(zhí)行getEvents()時會因無事件而
導致其線程阻塞在epoll_wait()的調用里,然而有時希望能夠立刻喚醒InputReader線程使其處
理一些請求生年。此時只需向wakeFds管道的寫入端寫入任意數(shù)據(jù)婴程,此時讀取端有數(shù)據(jù)可讀,使得
epoll_wait()得以返回抱婉,從而達到喚醒InputReader線程的目的*/
// ...
}
(2)getEvents():
InputReaderThread的線程循環(huán)為Reader子系統(tǒng)提供了運轉的動力档叔,EventHub的工作也是由它驅動的。
InputReader::loopOnce()函數(shù)調用EventHub::getEvents()函數(shù)獲取事件列表蒸绩,所以這個getEvents()是EventHub運行的動力所在衙四,幾乎包含了EventHub的所有工作事項。
// 那么先看看對事件的封裝:RawEvent
struct RawEvent {
nsecs_t when; /* 發(fā)生事件時的時間戳 */
int32_t deviceId; /* 產(chǎn)生事件的設備Id患亿,它是由EventHub自行分配的传蹈,InputReader
以根據(jù)它從EventHub中獲取此設備的詳細信息 */
int32_t type; /* 事件的類型 */
int32_t code; /* 事件代碼 */
int32_t value; /* 事件值 */
};
// getEvent():
size_t EventHub::getEvents(int timeoutMillis,RawEvent* buffer, size_t bufferSize) {
/* event指針指向了在buffer下一個可用于存儲事件的RawEvent結構體。每存儲一個事件步藕,
event指針都回向后偏移一個元素 */
RawEvent* event = buffer;
/*capacity記錄了buffer中剩余的元素數(shù)量惦界。當capacity為0時,表示buffer已滿咙冗,此時需要停
繼續(xù)處理新事件沾歪,并將已處理的事件返回給調用者 */
size_t capacity = bufferSize;
/* 接下來的循環(huán)是getEvents()函數(shù)的主體。在這個循環(huán)中乞娄,會先將可用事件放入到buffer中并返回瞬逊。
如果沒有可用事件,則進入epoll_wait()等待事件的到來仪或,epoll_wait()返回后會重新循環(huán)將可用
將新事件放入buffer */
for (;;){
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
/* **(1)首先進行與設備相關的工作确镊。**某些情況下,如EventHub創(chuàng)建后第一次執(zhí)行getEvents()函數(shù)
時范删,需要掃描/dev/input文件夾下的所有設備節(jié)點并將這些設備打開蕾域。另外,當設備節(jié)點的發(fā)生增
動作生時到旦,會將設備事件存入到buffer中 */
// ...
/* **(2)處理未被InputReader取走的輸入事件與設備事件旨巷。**epoll_wait()所取出的epoll_event
存儲在mPendingEventItems中,mPendingEventCount指定了mPendingEventItems數(shù)組
所存儲的事件個數(shù)添忘。而mPendingEventIndex指定尚未處理的epoll_event的索引 */
while (mPendingEventIndex < mPendingEventCount) {
const struct epoll_event & eventItem = mPendingEventItems[mPendingEventIndex++];
/* 在這里分析每一個epoll_event采呐,如果是表示設備節(jié)點可讀,則讀取原始事件并放置到buffer
中搁骑。如果是表示mINotifyFd可讀斧吐,則設置mPendingINotify為true又固,當InputReader
將現(xiàn)有的輸入事件都取出后讀取mINotifyFd中的事件,并進行相應的設備加載與卸載操作煤率。
另外仰冠,如果此epoll_event表示wakeFds的讀取端有數(shù)據(jù)可讀,則設置awake標志為true蝶糯,
無論此次getEvents()調用有無取到事件洋只,都不會再次進行epoll_wait()進行事件等待 */
// ...
}
//(3)如果mINotifyFd有數(shù)據(jù)可讀,說明設備節(jié)點發(fā)生了增刪操作
if(mPendingINotify && mPendingEventIndex >= mPendingEventCount) {
/* 讀取mINotifyFd中的事件昼捍,同時對輸入設備進行相應的加載與卸載操作识虚。這個操作必須當
InputReader將現(xiàn)有輸入事件讀取并處理完畢后才能進行,因為現(xiàn)有的輸入事件可能來自需要
被卸載的輸入設備妒茬,InputReader處理這些事件依賴于對應的設備信息 */
// ...
deviceChanged= true;
}
// 設備節(jié)點增刪操作發(fā)生時舷礼,則重新執(zhí)行循環(huán)體,以便將設備變化的事件放入buffer中
if(deviceChanged) {
continue;
}
// 如果此次getEvents()調用成功獲取了一些事件郊闯,或者要求喚醒InputReader,則退出循環(huán)并
// 結束getEvents()的調用蛛株,使InputReader可以立刻對事件進行處理
if(event != buffer || awoken) {
break;
}
/*(4)如果此次getEvents()調用沒能獲取事件团赁,說明mPendingEventItems中沒有事件可用,
于是執(zhí)行epoll_wait()函數(shù)等待新的事件到來谨履,將結果存儲到mPendingEventItems里欢摄,并重
置mPendingEventIndex為0 */
mPendingEventIndex = 0;
// ...
intpollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS,timeoutMillis);
// ...
mPendingEventCount= size_t(pollResult);
// 從epoll_wait()中得到新的事件后,重新循環(huán)笋粟,對新事件進行處理
}
// 返回本次getEvents()調用所讀取的事件數(shù)量
return event - buffer;
}
2.1 上面getEvents()返回了mEventBuffer之后怀挠,初步的處理:
void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {
for (const RawEvent* rawEvent = rawEvents; count;) { // 遍歷獲取到的event數(shù)組
int32_t type = rawEvent->type;
size_t batchSize = 1;
// 如果是常規(guī)的event事件,F(xiàn)IRST_SYNTHETIC_EVENT = DEVICE_ADDED (0x10000000)
if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) {
int32_t deviceId = rawEvent->deviceId;
while (batchSize < count) {
if (rawEvent[batchSize].type >= EventHubInterface::FIRST_SYNTHETIC_EVENT
|| rawEvent[batchSize].deviceId != deviceId) {
break;
}
batchSize += 1;
}
/* 把這次獲取到的event數(shù)組中屬于同一批次的害捕,進一步處理绿淋,判定條件就是:常規(guī)event以
及是屬于同一設備 */
processEventsForDeviceLocked(deviceId, rawEvent, batchSize); // 見 2.3
} else {
// 這里就是3種特殊的 event 類型,例如有時候打開設備的時候會有這個 ADD 事件
switch (rawEvent->type) {
case EventHubInterface::DEVICE_ADDED:
addDeviceLocked(rawEvent->when, rawEvent->deviceId); // 見 2.2
break;
case EventHubInterface::DEVICE_REMOVED:
removeDeviceLocked(rawEvent->when, rawEvent->deviceId);
break;
case EventHubInterface::FINISHED_DEVICE_SCAN:
handleConfigurationChangedLocked(rawEvent->when);
break;
default:
ALOG_ASSERT(false); // can't happen
break;
}
}
// 如果再上面沒有處理完event數(shù)組中的成員尝盼,那么依次繼續(xù)
count -= batchSize;
rawEvent += batchSize;
}
}
2.2 添加設備:addDeviceLocked(rawEvent->when, rawEvent->deviceId)吞滞;
在EventHub中提到將事件封裝成 RawEvent結構體,其中的 type 就是事件的類型盾沫,通過上面的代碼可以知道一共有四種類型裁赠,接下來挑選 DEVICE_ADDED 事件看看。
void InputReader::addDeviceLocked(nsecs_t when, int32_t deviceId) {
ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
if (deviceIndex >= 0) {
return;
}
// 這里取之前在EventHub中解析出來的設備相關參數(shù)
InputDeviceIdentifier identifier = mEventHub->getDeviceIdentifier(deviceId);
// 在open設備時 初始化赴精,代表類型
// open設備調用的方法:EventHub::openDeviceLocked(const charchar *devicePath)
uint32_t classes = mEventHub->getDeviceClasses(deviceId);
int32_t controllerNumber = mEventHub->getDeviceControllerNumber(deviceId);
// 這里又創(chuàng)建一個 InputDervice佩捞,會根據(jù)classes選擇對應的事件處理mapper與當前的設備綁定
InputDevice* device = createDeviceLocked(deviceId, controllerNumber, identifier, classes);
device->configure(when, &mConfig, 0);
device->reset(when);
mDevices.add(deviceId, device); // 添加這個 InputDevice
bumpGenerationLocked();
}
2.3 常規(guī) event 的處理:
// InputReader.cpp 中 processEventsForDeviceLocked() 方法:
void InputReader::processEventsForDeviceLocked(int32_t deviceId,
const RawEvent* rawEvents, size_t count) {
ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
if (deviceIndex < 0) {
return;
}
// 這里根據(jù)id 取出上面添加進去的inputdevice
InputDevice* device = mDevices.valueAt(deviceIndex);
if (device->isIgnored()) {
return;
}
device->process(rawEvents, count); // 這里調用了一個process的函數(shù)
}
// InputReader.cpp 中 process() 方法:
void InputDevice::process(const RawEvent* rawEvents, size_t count) {
// 這里有個map個數(shù),在create時 會根據(jù)classes類型去匹配處理map蕾哟,一般都是匹配一個
size_t numMappers = mMappers.size();
// 遍歷事件數(shù)組一忱,依次去處理
for (const RawEvent* rawEvent = rawEvents; count--; rawEvent++) {
if (mDropUntilNextSync) {
if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
mDropUntilNextSync = false;
} else {
ALOGD("Dropped input event while waiting for next input sync.");
}
} else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_DROPPED) {
ALOGI("Detected input event buffer overrun for device %s.", getName().string());
mDropUntilNextSync = true;
reset(rawEvent->when);
} else {
for (size_t i = 0; i < numMappers; i++) {
InputMapper* mapper = mMappers[i];
// 調用處理 mapper的process 函數(shù)莲蜘,開始分發(fā)流程,見 3.1
mapper->process(rawEvent);
}
}
}
}
3. input事件分發(fā):mapper->process(rawEvent)
在 2.2 中提到 createDeviceLocked() 這個方法給device添加綁定Mapper的掀潮,如下代碼所示菇夸。
InputDevice* InputReader::createDeviceLocked(int32_t deviceId, int32_t controllerNumber,
const InputDeviceIdentifier& identifier, uint32_t classes) {
InputDevice* device = new InputDevice(&mContext, deviceId, bumpGenerationLocked(),
controllerNumber, identifier, classes);
// External devices.
if (classes & INPUT_DEVICE_CLASS_EXTERNAL) {
device->setExternal(true);
}
// ...
// Touchscreens and touchpad devices.
if (classes & INPUT_DEVICE_CLASS_TOUCH_MT) {
device->addMapper(new MultiTouchInputMapper(device));
} else if (classes & INPUT_DEVICE_CLASS_TOUCH) {
device->addMapper(new SingleTouchInputMapper(device));
}
return device;
}
3.1 分發(fā)前的處理:
我們就以SingleTouchInputMapper為例
void SingleTouchInputMapper::process(const RawEvent* rawEvent) {
TouchInputMapper::process(rawEvent); // 調用父類的process
mSingleTouchMotionAccumulator.process(rawEvent);
}
void TouchInputMapper::process(const RawEvent* rawEvent) {
mCursorButtonAccumulator.process(rawEvent);
mCursorScrollAccumulator.process(rawEvent);
mTouchButtonAccumulator.process(rawEvent);
if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
sync(rawEvent->when);
}
}
/**
以下語句均是將輸入事件信息轉存至類成員變量中:
mCursorButtonAccumulator.process(rawEvent);
mCursorScrollAccumulator.process(rawEvent);
mTouchButtonAccumulator.process(rawEvent);
mSingleTouchMotionAccumulator.process(rawEvent);
**/
輸入事件分發(fā)的關鍵在 TouchInputMapper::sync() 方法中:這個同步函數(shù)比較長,下面是簡化后的代碼仪吧,我們之關注一下事件的分發(fā)就行了庄新;
void TouchInputMapper::sync(nsecs_t when) {
// Sync button state.
mCurrentButtonState = mTouchButtonAccumulator.getButtonState()
| mCursorButtonAccumulator.getButtonState();
// Sync scroll state.
mCurrentRawVScroll = mCursorScrollAccumulator.getRelativeVWheel();
mCurrentRawHScroll = mCursorScrollAccumulator.getRelativeHWheel();
mCursorScrollAccumulator.finishSync();
// Sync touch state.
bool havePointerIds = true;
mCurrentRawPointerData.clear();
/*調用子類的syncTouch,這里是 SingleTouchMotionAccumulator的syncTouch()薯鼠,
更新ABS 坐標值,我這里是把數(shù)據(jù)存入到mCurrentRawPointerData中供下面cook */
syncTouch(when, &havePointerIds);
// Reset state that we will compute below.
mCurrentFingerIdBits.clear();
mCurrentStylusIdBits.clear();
mCurrentMouseIdBits.clear();
mCurrentCookedPointerData.clear(); // 先清除一下
if (mDeviceMode == DEVICE_MODE_DISABLED) {
// Drop all input if the device is disabled.
mCurrentRawPointerData.clear();
mCurrentButtonState = 0;
} else {
if (mDeviceMode == DEVICE_MODE_POINTER) {
PointerUsage pointerUsage = mPointerUsage;
dispatchPointerUsage(when, policyFlags, pointerUsage);
} else {
if (mDeviceMode == DEVICE_MODE_DIRECT
&& mConfig.showTouches && mPointerController != NULL) {
mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_SPOT);
mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
mPointerController->setButtonState(mCurrentButtonState);
mPointerController->setSpots(mCurrentCookedPointerData.pointerCoords,
mCurrentCookedPointerData.idToIndex,
mCurrentCookedPointerData.touchingIdBits);
}
// 分發(fā)事件择诈,這里的三個方法最終都回調用 dispatchMotion()
//
dispatchHoverExit(when, policyFlags);
dispatchTouches(when, policyFlags);
dispatchHoverEnterAndMove(when, policyFlags);
}
// 之后的代碼是一些數(shù)據(jù)保存之類的操作
// ...
}
// ...
mCurrentRawVScroll = 0;
mCurrentRawHScroll = 0;
}
dispatchMotion():
void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source,
int32_t action, int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags,
const PointerProperties* properties, const PointerCoords* coords,
const uint32_t* idToIndex, BitSet32 idBits,
int32_t changedId, float xPrecision, float yPrecision, nsecs_t downTime) {
// ...
NotifyMotionArgs args(when, getDeviceId(), source, policyFlags,
action, flags, metaState, buttonState, edgeFlags,
mViewport.displayId, pointerCount, pointerProperties, pointerCoords,
xPrecision, yPrecision, downTime);
// 這里的 getListener() 就是我們之前提到的 傳入mDispatcher作為回調,只是做了進一步封裝出皇;
getListener()->notifyMotion(&args);
}
3.2 InputDispatcher 和 InputDispatcherThread:分發(fā)輸入事件
InputDispatcherThread 和之前的 InputReaderThread 一樣羞芍,先看看 threadLoop()方法;
// threadLoop() 方法:
bool InputDispatcherThread::threadLoop() {
mDispatcher->dispatchOnce();
return true;
}
// dispatchOnce() 方法:
void InputDispatcher::dispatchOnce() {
nsecs_t nextWakeupTime = LONG_LONG_MAX;
{
AutoMutex _l(mLock);
mDispatcherIsAliveCondition.broadcast();
// 第一次進來時mCommandQueue是空郊艘,能進入此分支荷科;
· // 然后在 dispatchOnceInnerLocked() 方法中 return;
// 最終在 mLooper->pollOnce(timeoutMillis) 休眠等待纱注;
if (!haveCommandsLocked()) { // 為空則開始處理事件
dispatchOnceInnerLocked(&nextWakeupTime);
}
// Run all pending commands if there are any.
// If any commands were run then force the next poll to wake up immediately.
if (runCommandsLockedInterruptible()) {
nextWakeupTime = LONG_LONG_MIN;
}
} // release lock
// Wait for callback or timeout or wake. (make sure we round up, not down)
nsecs_t currentTime = now();
int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime);
// looper進入休眠等待畏浆,wake() 方法喚醒(向fd中寫入數(shù)據(jù)就會喚醒);
mLooper->pollOnce(timeoutMillis);
}
上面的 dispatcherOnce() 方法在第一次進入時狞贱,會進入休眠狀態(tài)刻获,那么輸入事件的時候是如何調用的呢?這就是我們 3.1 中的 getListener()->notifyMotion(&args)瞎嬉,也就是Dispatcher的 notifyMotion() 方法:
void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) {
if (!validateMotionEvent(args->action, args->pointerCount, args->pointerProperties)) {
return; // 校驗MotionEvent的參數(shù)
}
// ...
bool needWake;
{ // acquire lock
mLock.lock();
if (shouldSendMotionToInputFilterLocked(args)) {
mLock.unlock();
MotionEvent event;
event.initialize(args->deviceId, args->source, args->action, args->flags,
args->edgeFlags, args->metaState, args->buttonState, 0, 0,
args->xPrecision, args->yPrecision,
args->downTime, args->eventTime,
args->pointerCount, args->pointerProperties, args->pointerCoords);
policyFlags |= POLICY_FLAG_FILTERED;
if (!mPolicy->filterInputEvent(&event, policyFlags)) {
return; // event was consumed by the filter
}
mLock.lock();
}
// Just enqueue a new motion event.
// 解析成一個新的MotionEntry:newEntry
MotionEntry* newEntry = new MotionEntry(args->eventTime,
args->deviceId, args->source, policyFlags,
args->action, args->flags, args->metaState, args->buttonState,
args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime,
args->displayId,
args->pointerCount, args->pointerProperties, args->pointerCoords, 0, 0);
needWake = enqueueInboundEventLocked(newEntry); //加入隊列
mLock.unlock();
} // release lock
if (needWake) {
mLooper->wake(); // 如果需要喚醒InputDispatcher線程, 則調用Looper的喚醒方法
}
}
加入輸入事件隊列:enqueueInboundEventLocked(EventEntry* entry) 方法
bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {
bool needWake = mInboundQueue.isEmpty(); // 如果隊列為空 , 則需要喚醒
mInboundQueue.enqueueAtTail(entry); // 插入到mInboundQueue隊列尾部
// ...
return needWake;
}
InputDispatcherThread::threadLoop() 會一直執(zhí)行mDispatcher->dispatchOnce() 方法蝎毡,喚醒 looper后,在dispatchOnce() 方法中繼續(xù)調用 dispatchOnceInnerLocked(&nextWakeupTime)來處理輸入事件氧枣,下面是這個方法的代碼:
void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
nsecs_t currentTime = now();
// 判斷事件分發(fā)是否允許沐兵,也就是在未開機、IMS未成功啟動便监、關機等狀態(tài)下是不可用的痒筒,默認值是false
if (!mDispatchEnabled) {
resetKeyRepeatLocked(); //重置重復按鍵次數(shù)
}
//判斷分發(fā)線程是否被凍結,是否可以配發(fā)茬贵,默認值是false
if (mDispatchFrozen) {
return;
}
//判斷此處是不是正在切換應用簿透,以便在home和endcall按鍵到來時,及時丟棄之前的事件解藻,而直接響應特殊鍵
bool isAppSwitchDue = mAppSwitchDueTime <= currentTime;
if (mAppSwitchDueTime < *nextWakeupTime) {
*nextWakeupTime = mAppSwitchDueTime;
}
// Ready to start a new event.
//mPendingEvent是即將要被配發(fā)的事件老充,派發(fā)完成置為null,此處是判斷是否正在配發(fā)事件
if (! mPendingEvent) {
if (mInboundQueue.isEmpty()) { // 如果Event隊列為空的話
if (isAppSwitchDue) {
// The inbound queue is empty so the app switch key we were waiting
// for will never arrive. Stop waiting for it.
resetPendingAppSwitchLocked(false);
isAppSwitchDue = false;
}
// Synthesize a key repeat if appropriate.
if (mKeyRepeatState.lastKeyEntry) {
if (currentTime >= mKeyRepeatState.nextRepeatTime) {
mPendingEvent = synthesizeKeyRepeatLocked(currentTime);
} else {
if (mKeyRepeatState.nextRepeatTime < *nextWakeupTime) {
*nextWakeupTime = mKeyRepeatState.nextRepeatTime;
}
}
}
// Nothing to do if there is no pending event.
if (!mPendingEvent) { // 如果沒有要處理的事件 , 則返回
return;
}
} else {
// Inbound queue has at least one entry.
mPendingEvent = mInboundQueue.dequeueAtHead(); // 有Event時螟左,取出第一個Event啡浊;
traceInboundQueueLengthLocked();
}
// Poke user activity for this event.
if (mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER) {
pokeUserActivityLocked(mPendingEvent);
}
// 重置此次事件分發(fā)的ANR超時時間觅够,如果超過5秒,就會產(chǎn)生ANR
resetANRTimeoutsLocked();
}
// Now we have an event to dispatch.
// All events are eventually dequeued and processed this way, even if we intend to drop them.
ALOG_ASSERT(mPendingEvent != NULL);
bool done = false;
DropReason dropReason = DROP_REASON_NOT_DROPPED;
if (!(mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER)) {
dropReason = DROP_REASON_POLICY;
} else if (!mDispatchEnabled) {
dropReason = DROP_REASON_DISABLED;
}
if (mNextUnblockedEvent == mPendingEvent) {
mNextUnblockedEvent = NULL;
}
switch (mPendingEvent->type) {
// 處理Configuration Change消息 , 即屏幕旋轉等等
case EventEntry::TYPE_CONFIGURATION_CHANGED: {
ConfigurationChangedEntry* typedEntry =
static_cast<ConfigurationChangedEntry*>(mPendingEvent);
done = dispatchConfigurationChangedLocked(currentTime, typedEntry);
dropReason = DROP_REASON_NOT_DROPPED; // configuration changes are never dropped
break;
}
// 處理設備重置消息
case EventEntry::TYPE_DEVICE_RESET: {
DeviceResetEntry* typedEntry =
static_cast<DeviceResetEntry*>(mPendingEvent);
done = dispatchDeviceResetLocked(currentTime, typedEntry);
dropReason = DROP_REASON_NOT_DROPPED; // device resets are never dropped
break;
}
// 處理Key按鍵消息
case EventEntry::TYPE_KEY: {
KeyEntry* typedEntry = static_cast<KeyEntry*>(mPendingEvent);
if (isAppSwitchDue) {
if (isAppSwitchKeyEventLocked(typedEntry)) {
resetPendingAppSwitchLocked(true);
isAppSwitchDue = false;
} else if (dropReason == DROP_REASON_NOT_DROPPED) {
dropReason = DROP_REASON_APP_SWITCH;
}
}
if (dropReason == DROP_REASON_NOT_DROPPED
&& isStaleEventLocked(currentTime, typedEntry)) {
dropReason = DROP_REASON_STALE;
}
if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) {
dropReason = DROP_REASON_BLOCKED;
}
done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);
break;
}
// 判斷時觸屏事件時:
case EventEntry::TYPE_MOTION: {
MotionEntry* typedEntry = static_cast<MotionEntry*>(mPendingEvent);
if (dropReason == DROP_REASON_NOT_DROPPED && isAppSwitchDue) {
dropReason = DROP_REASON_APP_SWITCH;
}
if (dropReason == DROP_REASON_NOT_DROPPED
&& isStaleEventLocked(currentTime, typedEntry)) {
dropReason = DROP_REASON_STALE;
}
if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) {
dropReason = DROP_REASON_BLOCKED;
}
done = dispatchMotionLocked(currentTime, typedEntry,
&dropReason, nextWakeupTime); // 分發(fā)事件
break;
}
default:
ALOG_ASSERT(false);
break;
}
if (done) {
if (dropReason != DROP_REASON_NOT_DROPPED) {
dropInboundEventLocked(mPendingEvent, dropReason); // 從配發(fā)隊列里面丟棄事件
}
releasePendingEventLocked();
*nextWakeupTime = LONG_LONG_MIN; // force next poll to wake up immediately
}
}
分發(fā)事件:
bool InputDispatcher::dispatchMotionLocked(
nsecs_t currentTime, MotionEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) {
bool isPointerEvent = entry->source & AINPUT_SOURCE_CLASS_POINTER;
// 找到目標窗口
Vector<InputTarget> inputTargets;
bool conflictingPointerActions = false;
int32_t injectionResult;
if (isPointerEvent) {
// 如果是手指事件的話 ,則找到Touch窗口:關鍵代碼1
injectionResult = findTouchedWindowTargetsLocked(currentTime,
entry, inputTargets, nextWakeupTime, &conflictingPointerActions);
} else {
// 如果不是手指觸摸事件 , 比如軌跡球事件的話 , 則找到Focus窗口
injectionResult = findFocusedWindowTargetsLocked(currentTime,
entry, inputTargets, nextWakeupTime);
}
// 如果找到窗口失敗, 返回
if (injectionResult == INPUT_EVENT_INJECTION_PENDING) {
return false;
}
// 開始向窗口分發(fā)事件:關鍵代碼2
dispatchEventLocked(currentTime, entry, inputTargets);
return true;
}
(關鍵代碼1)找到Touch窗口findFocusedWindowTargetsLocked():也是這個方法限制了不同app在不同窗口層級時巷嚣,上面的app不能把觸屏事件分發(fā)給下面的app喘先;
int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
const MotionEntry* entry, Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime,
bool* outConflictingPointerActions) {
// ...
if (newGesture || (isSplit && maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN)) {
//從MotionEntry中獲取坐標點
int32_t pointerIndex = getMotionEventActionPointerIndex(action);
int32_t x = int32_t(entry->pointerCoords[pointerIndex].
getAxisValue(AMOTION_EVENT_AXIS_X));
int32_t y = int32_t(entry->pointerCoords[pointerIndex].
getAxisValue(AMOTION_EVENT_AXIS_Y));
sp<InputWindowHandle> newTouchedWindowHandle;
bool isTouchModal = false;
size_t numWindows = mWindowHandles.size();//1
// 遍歷窗口,找到觸摸過的窗口和窗口之外的外部目標
for (size_t i = 0; i < numWindows; i++) {//2
//獲取InputDispatcher中代表窗口的windowHandle
sp<InputWindowHandle> windowHandle = mWindowHandles.itemAt(i);
//得到窗口信息windowInfo
const InputWindowInfo* windowInfo = windowHandle->getInfo();
if (windowInfo->displayId != displayId) {
//如果displayId不匹配廷粒,開始下一次循環(huán)
continue;
}
//獲取窗口的flag
int32_t flags = windowInfo->layoutParamsFlags;
//如果窗口時可見的
if (windowInfo->visible) {
//如果窗口的flag不為FLAG_NOT_TOUCHABLE(窗口是touchable)
if (! (flags & InputWindowInfo::FLAG_NOT_TOUCHABLE)) {
// 如果窗口是focusable或者flag不為FLAG_NOT_FOCUSABLE窘拯,則說明該窗口是"可觸摸模式"
isTouchModal = (flags & (InputWindowInfo::FLAG_NOT_FOCUSABLE
| InputWindowInfo::FLAG_NOT_TOUCH_MODAL)) == 0;//3
//如果窗口是 可觸摸模式或者坐標點落在窗口之上(找到目標窗口)
if (isTouchModal || windowInfo->touchableRegionContainsPoint(x, y)) {
newTouchedWindowHandle = windowHandle;//4
break; // found touched window, exit window loop
}
}
if (maskedAction == AMOTION_EVENT_ACTION_DOWN
&& (flags & InputWindowInfo::FLAG_WATCH_OUTSIDE_TOUCH)) {
//將符合條件的窗口放入TempTouchState中,以便后續(xù)處理坝茎。
mTempTouchState.addOrUpdateWindow(
windowHandle, InputTarget::FLAG_DISPATCH_AS_OUTSIDE, BitSet32(0));//5
}
}
// ...
}
} else{
// ...
}
// ...
// 把臨時存放窗口的 TempTouchState 加入到全局的 inputTargets 中
for (size_t i = 0; i < mTempTouchState.windows.size(); i++) {
const TouchedWindow& touchedWindow = mTempTouchState.windows.itemAt(i);
addWindowTargetLocked(touchedWindow.windowHandle, touchedWindow.targetFlags,
touchedWindow.pointerIds, inputTargets);
}
// ...
}
(關鍵代碼2)開始向窗口分發(fā)事件 dispatchEventLocked(currentTime, entry, inputTargets):
void InputDispatcher::dispatchEventLocked(nsecs_t currentTime,
EventEntry* eventEntry, const Vector<InputTarget>& inputTargets) {
ALOG_ASSERT(eventEntry->dispatchInProgress); // should already have been set to true
pokeUserActivityLocked(eventEntry);
for (size_t i = 0; i < inputTargets.size(); i++) { // 遍歷 inputTargets
const InputTarget& inputTarget = inputTargets.itemAt(i);
ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel);
if (connectionIndex >= 0) {
// 獲取跨進程通訊的連接涤姊;
sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
// 通過拿到的連接進行分發(fā);
prepareDispatchCycleLocked(currentTime, connection, eventEntry, &inputTarget);
} else {
// ...
}
}
}
prepareDispatchCycleLocked(currentTime, connection, eventEntry, &inputTarget) ->
enqueueDispatchEntriesLocked(currentTime, connection, splitMotionEntry, inputTarget) ->
startDispatchCycleLocked(currentTime, connection)
void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
const sp<Connection>& connection) {
#if DEBUG_DISPATCH_CYCLE
ALOGD("channel '%s' ~ startDispatchCycle",
connection->getInputChannelName());
#endif
while (connection->status == Connection::STATUS_NORMAL&& !connection->outboundQueue.isEmpty()) {
DispatchEntry* dispatchEntry = connection->outboundQueue.head;
dispatchEntry->deliveryTime = currentTime;
// Publish the event.
status_t status;
EventEntry* eventEntry = dispatchEntry->eventEntry;
switch (eventEntry->type) {
case EventEntry::TYPE_KEY: {
// ... key 事件
break;
}
case EventEntry::TYPE_MOTION: {
MotionEntry* motionEntry = static_cast<MotionEntry*>(eventEntry);
PointerCoords scaledCoords[MAX_POINTERS];
const PointerCoords* usingCoords = motionEntry->pointerCoords;
// Set the X and Y offset depending on the input source.
float xOffset, yOffset, scaleFactor;
if ((motionEntry->source & AINPUT_SOURCE_CLASS_POINTER)
&& !(dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS)) {
scaleFactor = dispatchEntry->scaleFactor;
xOffset = dispatchEntry->xOffset * scaleFactor;
yOffset = dispatchEntry->yOffset * scaleFactor;
if (scaleFactor != 1.0f) {
for (uint32_t i = 0; i < motionEntry->pointerCount; i++) {
scaledCoords[i] = motionEntry->pointerCoords[i];
scaledCoords[i].scale(scaleFactor);
}
usingCoords = scaledCoords;
}
} else {
xOffset = 0.0f;
yOffset = 0.0f;
scaleFactor = 1.0f;
// We don't want the dispatch target to know.
if (dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS) {
for (uint32_t i = 0; i < motionEntry->pointerCount; i++) {
scaledCoords[i].clear();
}
usingCoords = scaledCoords;
}
}
// Publish the motion event.
// 通過連接分發(fā)給遠程端嗤放;
status = connection->inputPublisher.publishMotionEvent(dispatchEntry->seq,
motionEntry->deviceId, motionEntry->source,
dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags,
motionEntry->edgeFlags, motionEntry->metaState, motionEntry->buttonState,
xOffset, yOffset,
motionEntry->xPrecision, motionEntry->yPrecision,
motionEntry->downTime, motionEntry->eventTime,
motionEntry->pointerCount, motionEntry->pointerProperties,
usingCoords);
break;
}
// Check the result.
if (status) {
// ...
return;
}
// Re-enqueue the event on the wait queue.
connection->outboundQueue.dequeue(dispatchEntry);
traceOutboundQueueLengthLocked(connection);
connection->waitQueue.enqueueAtTail(dispatchEntry);
traceWaitQueueLengthLocked(connection);
}
}