在上一節(jié) input輸入事件番外3 中講到 IMS 在 native 層的啟動,其中關(guān)于事件讀取線程循環(huán)讀取事件時調(diào)用了如下代碼:
// 循環(huán)執(zhí)行任務(wù)
bool InputReaderThread::threadLoop() {
mReader->loopOnce(); // 循環(huán)執(zhí)行 mReader 的 loopOnce() 方法锈至;
return true;
}
事件的讀取關(guān)鍵就是 InputReader 的 loopOnce() 方法剪况,接下來就從這個方法入手分析 InputReader 這個類以及它所要完成的任務(wù)吕粗;
void InputReader::loopOnce() {
int32_t oldGeneration;
int32_t timeoutMillis;
bool inputDevicesChanged = false;
Vector<InputDeviceInfo> inputDevices;
{ // acquire lock
AutoMutex _l(mLock);
oldGeneration = mGeneration;
timeoutMillis = -1;
uint32_t changes = mConfigurationChangesToRefresh;
if (changes) {
mConfigurationChangesToRefresh = 0;
timeoutMillis = 0;
refreshConfigurationLocked(changes);
} else if (mNextTimeout != LLONG_MAX) {
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
timeoutMillis = toMillisecondTimeoutDelay(now, mNextTimeout);
}
} // release lock
// 1. 讀取事件
size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
{ // acquire lock
AutoMutex _l(mLock);
mReaderIsAliveCondition.broadcast();
if (count) {
// 2. 事件的簡單處理试读;
processEventsLocked(mEventBuffer, count);
}
if (mNextTimeout != LLONG_MAX) {
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
if (now >= mNextTimeout) {
mNextTimeout = LLONG_MAX;
timeoutExpiredLocked(now);
}
}
if (oldGeneration != mGeneration) {
inputDevicesChanged = true;
getInputDevicesLocked(inputDevices);
}
} // release lock
// Send out a message that the describes the changed input devices.
if (inputDevicesChanged) {
mPolicy->notifyInputDevicesChanged(inputDevices);
}
// 3. 把事件傳給 InputDispatcher 處理(也可以理解為交給分發(fā)線程處理)
mQueuedListener->flush(); // 這個 mQueuedListener 其實(shí)就是 InputDispatcher
}
從上面的代碼中可以總結(jié)為三點(diǎn):
(1)讀取事件锨咙;
(2)事件的簡單處理十兢;
(3)把事件傳給 InputDispatcher 處理(也可以理解為交給分發(fā)線程處理)餐济;
1. 讀取事件
讀取事件是通過 mEventHub->getEvents() 方法獲取的耘擂,其基本原理在 Linux知識 中已經(jīng)介紹過,接下來簡單分析一下 EventHub絮姆。
1.1 EventHub 的構(gòu)造函數(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);
//(epoll 的用法第 1 步):epoll_create()
mEpollFd = epoll_create(EPOLL_SIZE_HINT); // EPOLL_SIZE_HINT 指定最大監(jiān)聽個數(shù)為 8
// inotify 用法第 1 步:inotify_init()醉冤,初始化 fd
mINotifyFd = inotify_init();
// inotify 用法第 2 步:inotify_add_watch()秩霍,監(jiān)測;其中 DEVICE_PATH = "/dev/input";
// inotify 用法第 3 步:read()蚁阳,讀攘迦蕖;在 getEvents() 中調(diào)用
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; // 這里并沒有使用fd字段螺捐,而使用了自定義的值EPOLL_ID_INOTIFY
//(epoll 的用法第 2 步):epoll_ctl()
//(epoll 的用法第 3 步):epoll_wait()颠悬;在 getEvents() 中調(diào)用
result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem); // 將對mINotifyFd的監(jiān)聽注冊到epoll對象中
// ... 省略部分代碼 見注釋 1
}
在構(gòu)造函數(shù)中,使用了 inotify 機(jī)制監(jiān)測 "/dev/input" 目錄的變化定血;使用 epoll 監(jiān)測有無數(shù)據(jù)赔癌;大致流程如下:
(1)創(chuàng)建 inotify 的文件句柄 mINotifyFd = inotify_init() 并通過 inotify_add_watch() 監(jiān)測 "/dev/input" 目錄;
(2)在 openDeviceLocked() 中調(diào)用 fd = open(devicePath, O_RDWR | O_CLOEXEC) 打開各種設(shè)備節(jié)點(diǎn)澜沟,例如 /dev/input/event0灾票;
(3)使用 epoll_wait() 監(jiān)測這些文件句柄 mINotifyFd、fd茫虽;
(4)讀取文件句柄刊苍,構(gòu)造相應(yīng)的 RawEvent (下面有介紹),例如新增了設(shè)備節(jié)點(diǎn)就可以通過 mINotifyFd 監(jiān)測到濒析;
注釋1:在構(gòu)造函數(shù)省略的代碼中正什,EventHub 創(chuàng)建了一個名為 wakeFds 的匿名管道,并將管道讀取端的描述符的可讀事件注冊到 epoll 對象中号杏。因?yàn)?InputReader 在執(zhí)行 getEvents() 時會因無事件而導(dǎo)致其線程阻塞在 epoll_wait() 的調(diào)用里婴氮,然而有時希望能夠立刻喚醒 InputReader 線程使其處理一些請求。此時只需向 wakeFds 管道的寫入端寫入任意數(shù)據(jù)馒索,此時讀取端有數(shù)據(jù)可讀莹妒,使得epoll_wait() 得以返回,從而達(dá)到喚醒 InputReader 線程的目的绰上;
1.2 獲取事件:getEvents()
通過 mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE) 方法來獲取事件,其中 mEventBuffer 是一個大小為 256 的 RawEvent 數(shù)組渠驼,用于存放獲取到的事件蜈块;
static const int EVENT_BUFFER_SIZE = 256;
RawEvent mEventBuffer[EVENT_BUFFER_SIZE];
struct RawEvent {
nsecs_t when;
int32_t deviceId;
int32_t type; // 事件的類型
int32_t code;
int32_t value;
};
// RawEvent 的 type 類型:
enum {
// Sent when a device is added.
DEVICE_ADDED = 0x10000000,
// Sent when a device is removed.
DEVICE_REMOVED = 0x20000000,
// Sent when all added/removed devices from the most recent scan have been reported.
// This event is always sent at least once.
FINISHED_DEVICE_SCAN = 0x30000000,
FIRST_SYNTHETIC_EVENT = DEVICE_ADDED,
};
// 另外在掃描 "dev/input" 目錄下設(shè)備節(jié)點(diǎn)的過程中,中可以發(fā)現(xiàn)還有一下的一些事件類型:
// openDeviceLocked() 中迷扇;
// EV_KEY 0x01 按鍵事件
ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(device->keyBitmask)), device->keyBitmask);
// EV_ABS 0x03 絕對坐標(biāo)百揭,如觸摸屏上報的坐標(biāo)
ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(device->absBitmask)), device->absBitmask);
// EV_REL 0x02 相對坐標(biāo), 如鼠標(biāo)上報的坐標(biāo)
ioctl(fd, EVIOCGBIT(EV_REL, sizeof(device->relBitmask)), device->relBitmask);
// 用來描述具備兩種狀態(tài)的輸入開關(guān)
ioctl(fd, EVIOCGBIT(EV_SW, sizeof(device->swBitmask)), device->swBitmask);
// EV_LED 0x11 LED
ioctl(fd, EVIOCGBIT(EV_LED, sizeof(device->ledBitmask)), device->ledBitmask);
// EV_FF 0x15 力反饋
ioctl(fd, EVIOCGBIT(EV_FF, sizeof(device->ffBitmask)), device->ffBitmask);
ioctl(fd, EVIOCGPROP(sizeof(device->propBitmask)), device->propBitmask);
// 另外,還有 EV_SYN(0x00 同步事件)蜓席;SYN_REPORT(一次事件的結(jié)尾) 等等器一;
// 收到一個點(diǎn)之后并不會立即處理,而是一個事件完成之后才會處理厨内,SYN_REPORT就是這個事件的標(biāo)志祈秕。
接下來是 getEvents() 的分析:
size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
ALOG_ASSERT(bufferSize >= 1);
AutoMutex _l(mLock);
struct input_event readBuffer[bufferSize];
// event指針指向了在 buffer 下一個可用于存儲事件的 RawEvent 結(jié)構(gòu)體渺贤。每存儲一個事件,event 指針都回向后偏移一個元素
RawEvent* event = buffer;
// capacity 記錄了 buffer 中剩余的元素數(shù)量请毛。當(dāng)capacity為0時志鞍,表示 buffer 已滿,此時需要停繼續(xù)處理新
// 事件方仿,并將已處理的事件返回給調(diào)用者
size_t capacity = bufferSize;
bool awoken = false;
// getEvents()的關(guān)鍵部分:在這個循環(huán)中固棚,會先將可用事件放入到buffer中并返回。如果沒有可用事件仙蚜,
// 則進(jìn)入 epoll_wait() 等待事件的到來此洲,epoll_wait() 返回后會重新循環(huán)將可用將新事件放入 buffer
for (;;) {
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
// ... 省略部分代碼
//(1)第一步:****************************** 見下方解釋 *****************************
if (mNeedToScanDevices) { // 稍稍注意下在 EventHub 構(gòu)造函數(shù)中 mNeedToScanDevices(true)
mNeedToScanDevices = false;
// 第一次進(jìn)入時掃描 "dev/input" 目錄下所有的設(shè)備節(jié)點(diǎn)時,會建立設(shè)備列表存儲在mDevice成員變量
// 中 (EventHub中有設(shè)備列表 KeyedVector<int32_t, Device*> mDevices)委粉;并通過 open() 函
// 數(shù)打開節(jié)點(diǎn)黍翎,最終調(diào)用 epoll_ctl() 添加到 epoll 中;
scanDevicesLocked(); // 這個方法有興趣可以跟進(jìn)去看看
mNeedToSendFinishedDeviceScan = true;
}
// ...
if (mNeedToSendFinishedDeviceScan) {
mNeedToSendFinishedDeviceScan = false;
event->when = now;
event->type = FINISHED_DEVICE_SCAN;
event += 1;
if (--capacity == 0) {
break;
}
}
// Grab the next input event.
//(2)第二步:****************************** 見下方解釋 *****************************
bool deviceChanged = false;
// mPendingEventItems:處理未被 InputReader 取走的輸入事件與設(shè)備事件
while (mPendingEventIndex < mPendingEventCount) {
/* 在這里分析每一個 epoll_event艳丛,如果是表示設(shè)備節(jié)點(diǎn)可讀匣掸,則讀取原始事件并放置到 buffer
中。如果是表示 mINotifyFd 可讀氮双,則設(shè)置 mPendingINotify 為 true碰酝,當(dāng) InputReader
將現(xiàn)有的輸入事件都取出后讀取 mINotifyFd 中的事件,并進(jìn)行相應(yīng)的設(shè)備加載與卸載操作戴差。
另外送爸,如果此 epoll_event 表示 wakeFds 的讀取端有數(shù)據(jù)可讀,則設(shè)置 awake 標(biāo)志為 true暖释,
無論此次 getEvents() 調(diào)用有無取到事件袭厂,都不會再次進(jìn)行 epoll_wait() 進(jìn)行事件等待 */
const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];
if (eventItem.data.u32 == EPOLL_ID_INOTIFY) {
if (eventItem.events & EPOLLIN) {
mPendingINotify = true;
} else {
ALOGW("Received unexpected epoll event 0x%08x for INotify.", eventItem.events);
}
continue;
}
if (eventItem.data.u32 == EPOLL_ID_WAKE) {
if (eventItem.events & EPOLLIN) {
ALOGV("awoken after wake()");
awoken = true;
char buffer[16];
ssize_t nRead;
do {
nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer));
} while ((nRead == -1 && errno == EINTR) || nRead == sizeof(buffer));
} else {
ALOGW("Received unexpected epoll event 0x%08x for wake read pipe.",
eventItem.events);
}
continue;
}
ssize_t deviceIndex = mDevices.indexOfKey(eventItem.data.u32);
if (deviceIndex < 0) {
ALOGW("Received unexpected epoll event 0x%08x for unknown device id %d.",
eventItem.events, eventItem.data.u32);
continue;
}
Device* device = mDevices.valueAt(deviceIndex);
if (eventItem.events & EPOLLIN) {
int32_t readSize = read(device->fd, readBuffer,
sizeof(struct input_event) * capacity);
if (readSize == 0 || (readSize < 0 && errno == ENODEV)) {
// Device was removed before INotify noticed.
ALOGW("could not get event, removed? (fd: %d size: %" PRId32
" bufferSize: %zu capacity: %zu errno: %d)\n",
device->fd, readSize, bufferSize, capacity, errno);
deviceChanged = true;
closeDeviceLocked(device);
} else if (readSize < 0) {
if (errno != EAGAIN && errno != EINTR) {
ALOGW("could not get event (errno=%d)", errno);
}
} else if ((readSize % sizeof(struct input_event)) != 0) {
ALOGE("could not get event (wrong size: %d)", readSize);
} else {
int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
size_t count = size_t(readSize) / sizeof(struct input_event);
for (size_t i = 0; i < count; i++) {
// input_event 是 linux kernel 獲取到的輸入事件
struct input_event& iev = readBuffer[i];
if (iev.type == EV_MSC) {
if (iev.code == MSC_ANDROID_TIME_SEC) {
device->timestampOverrideSec = iev.value;
continue;
} else if (iev.code == MSC_ANDROID_TIME_USEC) {
device->timestampOverrideUsec = iev.value;
continue;
}
}
if (device->timestampOverrideSec || device->timestampOverrideUsec) {
iev.time.tv_sec = device->timestampOverrideSec;
iev.time.tv_usec = device->timestampOverrideUsec;
if (iev.type == EV_SYN && iev.code == SYN_REPORT) {
device->timestampOverrideSec = 0;
device->timestampOverrideUsec = 0;
}
ALOGV("applied override time %d.%06d",
int(iev.time.tv_sec), int(iev.time.tv_usec));
}
#else
event->when = now;
#endif
// 將 input_event 封裝成 RawEvent
event->deviceId = deviceId;
event->type = iev.type;
event->code = iev.code;
event->value = iev.value;
event += 1;
capacity -= 1;
}
if (capacity == 0) {
// The result buffer is full. Reset the pending event index
// so we will try to read the device again on the next iteration.
mPendingEventIndex -= 1;
break;
}
}
} else if (eventItem.events & EPOLLHUP) {
ALOGI("Removing device %s due to epoll hang-up event.",
device->identifier.name.string());
deviceChanged = true;
closeDeviceLocked(device);
} else {
ALOGW("Received unexpected epoll event 0x%08x for device %s.",
eventItem.events, device->identifier.name.string());
}
}
//(3)第三步:****************************** 見下方解釋 *****************************
if (mPendingINotify && mPendingEventIndex >= mPendingEventCount) {
/* 讀取 mINotifyFd 中的事件,同時對輸入設(shè)備進(jìn)行相應(yīng)的加載與卸載操作球匕。這個操作必須當(dāng)
InputReader 將現(xiàn)有輸入事件讀取并處理完畢后才能進(jìn)行纹磺,因?yàn)楝F(xiàn)有的輸入事件可能來自需要
被卸載的輸入設(shè)備,InputReader 處理這些事件依賴于對應(yīng)的設(shè)備信息 */
mPendingINotify = false;
readNotifyLocked();
deviceChanged = true;
}
// Report added or removed devices immediately.
// 設(shè)備節(jié)點(diǎn)增刪操作發(fā)生時亮曹,則重新執(zhí)行循環(huán)體橄杨,以便將設(shè)備變化的事件放入buffer中
if (deviceChanged) {
continue;
}
// Return now if we have collected any events or if we were explicitly awoken.
// 如果此次getEvents()調(diào)用成功獲取了一些事件,或者要求喚醒InputReader照卦,則退出循環(huán)并
// 結(jié)束getEvents()的調(diào)用式矫,使InputReader可以立刻對事件進(jìn)行處理
if (event != buffer || awoken) {
break;
}
//(4)第四步:****************************** 見下方解釋 *****************************
// 此次getEvents()調(diào)用沒能獲取事件
mPendingEventIndex = 0;
mLock.unlock(); // release lock before poll, must be before release_wake_lock
release_wake_lock(WAKE_LOCK_ID);
int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis);
acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
mLock.lock(); // reacquire lock after poll, must be after acquire_wake_lock
if (pollResult == 0) {
// Timed out.
mPendingEventCount = 0;
break;
}
if (pollResult < 0) {
// An error occurred.
mPendingEventCount = 0;
// Sleep after errors to avoid locking up the system.
// Hopefully the error is transient.
if (errno != EINTR) {
ALOGW("poll failed (errno=%d)\n", errno);
usleep(100000);
}
} else {
// Some events occurred.
// 從 epoll_wait() 中得到新的事件后,重新循環(huán)役耕,對新事件進(jìn)行處理
mPendingEventCount = size_t(pollResult);
}
}
// All done, return the number of events we read.
// 返回本次getEvents()調(diào)用所讀取的事件數(shù)量
return event - buffer;
}
(1)第一步:首先進(jìn)行與設(shè)備相關(guān)的工作采转。如 EventHub 創(chuàng)建后第一次執(zhí)行 getEvents() 函數(shù)時,需要掃描 "/de/input" 目錄下所有設(shè)備節(jié)點(diǎn)并打開這些設(shè)備節(jié)點(diǎn)瞬痘。另外故慈,當(dāng)設(shè)備節(jié)點(diǎn)的發(fā)生增加時板熊,會將設(shè)備事件存入到 buffer 中;
(2)第二步:處理未被 InputReader 取走的輸入事件與設(shè)備事件惯悠。epoll_wait() 所取出的 epoll_event 存儲在mPendingEventItems中邻邮,mPendingEventCount 指定了 mPendingEventItems 數(shù)組所存儲的事件個數(shù)。而mPendingEventIndex 指定尚未處理的 epoll_event 的索引克婶;
(3)第三步:如果 mINotifyFd 有數(shù)據(jù)可讀筒严,說明設(shè)備節(jié)點(diǎn)發(fā)生了增刪操作;
(4)第四步:如果此次 getEvents() 調(diào)用沒能獲取事件情萤,說明 mPendingEventItems 中沒有事件可用鸭蛙,于是執(zhí)行 epoll_wait() 函數(shù)等待新的事件到來,將結(jié)果存儲到 mPendingEventItems 里筋岛,并重置 mPendingEventIndex 為 0娶视;
2. 事件的簡單處理
在 InputReader 中 loopOnce() 方法中調(diào)用 processEventsLocked(mEventBuffer, count) 會對獲取到的事件進(jìn)行簡單的處理,其復(fù)雜的處理及分發(fā)是在 InputDispatcher 中完成的睁宰;
// 根據(jù)獲取到的 RawEvent 的 type 類型進(jìn)行處理:
void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {
for (const RawEvent* rawEvent = rawEvents; count;) {
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;
}
// processEventsForDeviceLocked() 處理一般的事件: 見 2.2
// 把這次獲取到的 event 數(shù)組中屬于同一批次的,進(jìn)一步處理柒傻,判定條件就是:常規(guī) event 以及是屬于同一設(shè)備
processEventsForDeviceLocked(deviceId, rawEvent, batchSize);
}
// 處理 3 種特殊的事件:例如添加設(shè)備孝赫, 見 2.1
else { // 這里就是3種特殊的 event 類型邓厕,例如有時候打開設(shè)備的時候會有這個 ADD 事件
switch (rawEvent->type) {
case EventHubInterface::DEVICE_ADDED:
addDeviceLocked(rawEvent->when, rawEvent->deviceId);
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.1 添加設(shè)備:
既然是添加設(shè)備,那么必定有一個容器來保存這些設(shè)備映胁,這個容器就是 KeyedVector<int32_t, InputDevice* > mDevices预侯;還記得獲取輸入事件的時候致开,掃描 "dev/input" 目錄下設(shè)備節(jié)點(diǎn)時也有一個保存設(shè)備的容器 KeyedVector<int32_t, Device *> mDevices 嗎?在這里介紹一下兩者的區(qū)別:簡單來說就是里面的設(shè)備不同萎馅;
// EventHub 中的 Device:
struct Device {
Device* next;
// 文件句柄双戳;
int fd; // may be -1 if device is virtual
// classes 信息,在 InputReader 中會用到校坑;
uint32_t classes;
// 設(shè)備信息拣技;
const InputDeviceIdentifier identifier;
// 配置信息(例如 Linux 內(nèi)核獲取到的按鍵值1,在 Android 中經(jīng)過配置文件轉(zhuǎn)換并不是1耍目,而是其他值);
String8 configurationFile;
PropertyMap* configuration;
// ... 省略
}
// InputReader 中的 InputDevice:
class InputDevice {
private:
InputReaderContext* mContext;
int32_t mId;
int32_t mGeneration;
int32_t mControllerNumber;
InputDeviceIdentifier mIdentifier;
// 關(guān)注點(diǎn):這里有一個 InputMapper 的成員變量徐绑,它的作用是將各種封裝了各種不同的事件類型邪驮,例如
// 鍵盤事件的設(shè)備對應(yīng)的是 KeyboardInputMapper;
Vector<InputMapper*> mMappers;
// ... 省略
}
這里就會有一個問題傲茄,為什么對于一個設(shè)備要進(jìn)行添加兩次毅访,這么做是不是多余的呢沮榜?在我看來,這么設(shè)計的目的應(yīng)該是一個分層設(shè)計(或者說單一職責(zé))的思想喻粹;在 EventHub 中處理的是比較原始的數(shù)據(jù)蟆融,主要是一些事件的獲取、設(shè)備的配置等工作守呜,而在 InputReader 中是對 EventHub 中獲取的一些事件進(jìn)行初步處理和傳遞事件發(fā)給 InputDispatcher 處理型酥,所以才這么封裝的;
那么查乒,接下來就分析一下添加設(shè)備的源代碼 addDeviceLocked():
void InputReader::addDeviceLocked(nsecs_t when, int32_t deviceId) {
ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
if (deviceIndex >= 0) {
ALOGW("Ignoring spurious device added event for deviceId %d.", deviceId);
return;
}
InputDeviceIdentifier identifier = mEventHub->getDeviceIdentifier(deviceId);
uint32_t classes = mEventHub->getDeviceClasses(deviceId);
int32_t controllerNumber = mEventHub->getDeviceControllerNumber(deviceId);
// 創(chuàng)建出 InputDevice弥喉; 詳見下面 createDeviceLocked() 的分析
InputDevice* device = createDeviceLocked(deviceId, controllerNumber, identifier, classes);
device->configure(when, &mConfig, 0);
device->reset(when);
if (device->isIgnored()) {
ALOGI("Device added: id=%d, name='%s' (ignored non-input device)", deviceId,
identifier.name.string());
} else {
ALOGI("Device added: id=%d, name='%s', sources=0x%08x", deviceId,
identifier.name.string(), device->getSources());
}
mDevices.add(deviceId, device); // 將創(chuàng)建出的 device 加入到 mDevices 中;
bumpGenerationLocked();
}
創(chuàng)建 InputDevice:createDeviceLocked()
// 根據(jù) rawEvent 中的 deviceId 創(chuàng)建相應(yīng)的 InputDevice 并添加相應(yīng)的 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);
}
// Switch-like devices.
if (classes & INPUT_DEVICE_CLASS_SWITCH) {
device->addMapper(new SwitchInputMapper(device));
}
// Vibrator-like devices.
if (classes & INPUT_DEVICE_CLASS_VIBRATOR) {
device->addMapper(new VibratorInputMapper(device));
}
// Keyboard-like devices.
uint32_t keyboardSource = 0;
int32_t keyboardType = AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC;
if (classes & INPUT_DEVICE_CLASS_KEYBOARD) {
keyboardSource |= AINPUT_SOURCE_KEYBOARD;
}
if (classes & INPUT_DEVICE_CLASS_ALPHAKEY) {
keyboardType = AINPUT_KEYBOARD_TYPE_ALPHABETIC;
}
if (classes & INPUT_DEVICE_CLASS_DPAD) {
keyboardSource |= AINPUT_SOURCE_DPAD;
}
if (classes & INPUT_DEVICE_CLASS_GAMEPAD) {
keyboardSource |= AINPUT_SOURCE_GAMEPAD;
}
if (keyboardSource != 0) {
device->addMapper(new KeyboardInputMapper(device, keyboardSource, keyboardType));
}
// Cursor-like devices.
if (classes & INPUT_DEVICE_CLASS_CURSOR) {
device->addMapper(new CursorInputMapper(device));
}
// 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));
}
// Joystick-like devices.
if (classes & INPUT_DEVICE_CLASS_JOYSTICK) {
device->addMapper(new JoystickInputMapper(device));
}
return device;
}
2.2 事件初步處理:
// InputReader.cpp 中 processEventsForDeviceLocked() 方法:
void InputReader::processEventsForDeviceLocked(int32_t deviceId,
const RawEvent* rawEvents, size_t count) {
ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
if (deviceIndex < 0) {
ALOGW("Discarding event for unknown deviceId %d.", deviceId);
return;
}
// 這里根據(jù) deviceId 取出上面添加進(jìn)去的 InputDevice
InputDevice* device = mDevices.valueAt(deviceIndex);
if (device->isIgnored()) {
//ALOGD("Discarding event for ignored deviceId %d.", deviceId);
return;
}
device->process(rawEvents, count);
}
// InputReader.cpp 中 process() 方法:
void InputDevice::process(const RawEvent* rawEvents, size_t count) {
// 這里有個 mapper 數(shù)組玛迄,在 create 時 會根據(jù) classes 類型去匹配處理 mapper由境,一般都是匹配一個
size_t numMappers = mMappers.size();
// 遍歷事件數(shù)組,依次去處理
for (const RawEvent* rawEvent = rawEvents; count--; rawEvent++) {
ALOGD("Input event: device=%d type=0x%04x code=0x%04x value=0x%08x when=%lld",
rawEvent->deviceId, rawEvent->type, rawEvent->code, rawEvent->value,
rawEvent->when);
if (mDropUntilNextSync) {
if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
mDropUntilNextSync = false;
ALOGD("Recovered from input event buffer overrun.");
} 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++) {
// 調(diào)用 mapper 的 process 函數(shù)蓖议,交給 InputDispatcher 并開始分發(fā)流程虏杰;
InputMapper* mapper = mMappers[i];
mapper->process(rawEvent); // 最終是調(diào)用了 設(shè)備相應(yīng)的 mapper->process(rawEvent) 方法;
}
}
}
}
3. 事件傳遞給 InputDispatcher 處理:
事件經(jīng)過獲取勒虾,初步處理纺阔,最終執(zhí)行了 mapper->process(rawEvent) 方法,對于 mapper->process() 這個方法需要查看 InputReader::createDeviceLocked() 中創(chuàng)建的具體的InputMapper的process函數(shù)从撼。下面就以 SingleTouchInputMapper 的 process() 為例:
SingleTouchInputMapper 的 process() 方法:
// (1)
void SingleTouchInputMapper::process(const RawEvent* rawEvent) {
TouchInputMapper::process(rawEvent); // 調(diào)用父類的process
mSingleTouchMotionAccumulator.process(rawEvent);
}
void TouchInputMapper::process(const RawEvent* rawEvent) {
mCursorButtonAccumulator.process(rawEvent);
mCursorScrollAccumulator.process(rawEvent);
mTouchButtonAccumulator.process(rawEvent);
// 一組同步事件州弟,并且已經(jīng)完結(jié)(有事件結(jié)束標(biāo)值 SYN_REPORT);
if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
sync(rawEvent->when); // 關(guān)鍵方法低零,后續(xù)有分析婆翔;
}
}
/**
以下語句均是將輸入事件信息轉(zhuǎn)存至類成員變量中:
mCursorButtonAccumulator.process(rawEvent); // 注釋 1
mCursorScrollAccumulator.process(rawEvent); // 注釋 2
mTouchButtonAccumulator.process(rawEvent); // 注釋 3
mSingleTouchMotionAccumulator.process(rawEvent); // 注釋 4
**/
注釋1:mCursorButtonAccumulator.process(rawEvent)
記錄鼠標(biāo)或觸摸板的按鍵狀態(tài):記錄 rawEvent->type 為 EV_KEY,且rawEvent->code為BTN_LEFT掏婶、BTN_RIGHT啃奴、BTN_MIDDLE、BTN_BACK雄妥、BTN_SIDE最蕾、BTN_FORWARD、BTN_EXTRA老厌、BTN_TASK 事件瘟则。
注釋2:mCursorScrollAccumulator.process(rawEvent)
記錄光標(biāo)滾動:記錄rawEvent->type為EV_REL,且rawEvent->code為REL_WHEEL枝秤、REL_HWHEEL 事件醋拧。
注釋3:mTouchButtonAccumulator.process(rawEvent)
記錄觸摸 手寫筆 工具按鈕狀態(tài):記錄rawEvent->type為EV_KEY,且rawEvent->code為BTN_TOUCH、BTN_STYLUS丹壕、BTN_STYLUS2庆械、BTN_TOOL_FINGER、BTN_TOOL_PEN菌赖、BTN_TOOL_RUBBER缭乘、BTN_TOOL_BRUSH、BTN_TOOL_PENCIL琉用、BTN_TOOL_AIRBRUSH堕绩、BTN_TOOL_MOUSE、BTN_TOOL_LENS辕羽、BTN_TOOL_DOUBLETAP逛尚、BTN_TOOL_TRIPLETAP、BTN_TOOL_QUADTAP 事件刁愿。
BTN_TOUCH 的數(shù)據(jù)在這里被處理了绰寞,且其 value 被保存在 mBtnTouch 成員變量中;
注釋4:mSingleTouchMotionAccumulator.process
記錄ABS相關(guān)的值铣口,記錄rawEvent->type為EV_ABS滤钱,且rawEvent->scanCode為ABS_X、ABS_Y脑题、ABS_PRESSURE件缸、ABS_TOOL_WIDTH、ABS_DISTANCE叔遂、ABS_TILT_X他炊、ABS_TILT_Y的事件。
ABS_X和ABS_Y 的數(shù)據(jù)在這里被處理了已艰。
TouchInputMapper 中的 sync(nsecs_t when)方法:
// 輸入事件分發(fā)的關(guān)鍵在 sync(nsecs_t when) 中:這個同步函數(shù)比較長痊末,下面是簡化后的代碼,重點(diǎn)事件的分發(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();
/*調(diào)用子類的 syncTouch哩掺,這里是 SingleTouchMotionAccumulator的syncTouch()凿叠,
更新 ABS 坐標(biāo)值,這里是把數(shù)據(jù)存入到 mCurrentRawPointerData 中供下面 cook */
syncTouch(when, &havePointerIds); //這里是一個虛函數(shù)
/***** 虛函數(shù)是一個類中希望重載的成員函數(shù) 嚼吞,通過指向派生類的基類指針或引用盒件,訪問派生類中同名覆蓋成員函數(shù) *****/
// 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 {
// ...
// 這個函數(shù)很龐大,cook 數(shù)據(jù)舱禽,主要是生成 mCurrentCookedPointerData.pointerCoords炒刁,
// mCurrentCookedPointerData.pointerProperties 和 mCurrentCookedPointerData.idToIndex
cookPointerData();
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ā)事件,這里的三個方法最終都回調(diào)用 dispatchMotion()
dispatchHoverExit(when, policyFlags);
dispatchTouches(when, policyFlags);
dispatchHoverEnterAndMove(when, policyFlags);
}
// 之后的代碼是一些數(shù)據(jù)保存之類的操作
// ...
}
// ...
mCurrentRawVScroll = 0;
mCurrentRawHScroll = 0;
}
事件傳遞給 InputDispatcher 處理 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() 其實(shí)就是 InputReader 的構(gòu)造函數(shù)中傳入的 mDispatcher 作為回調(diào)誊稚,只是做了進(jìn)一步封裝切心;
getListener()->notifyMotion(&args);
}
通過調(diào)用 dispatchMotion() 方法飒筑,事件最終交由 InputDispatcher 處理片吊,到這里本小節(jié)的內(nèi)容就結(jié)束了绽昏,下一節(jié)將繼續(xù) InputDispatcher 的學(xué)習(xí)。