第一章 文章简介... 3
第二章 涉及类说明... 3
第三章 能解决的问题... 4
第四章 读取流程图... 5
第五章 详细代码分析... 7
这篇文章详细的讲解android Q上InputReader,如何将事件读取加工,并转发给InputDispatcher的。学习了这片文章,相信你对安卓的触摸事件等会有一个全新的认识。看这篇文章之前要先看
https://blog.csdn.net/chen364567628/article/details/102790372
https://blog.csdn.net/chen364567628/article/details/102811219
这两篇文章,不然你无法理解其中的奥妙。
InputReader是自IMS启动后的唯一入口,里面包含了loopOnce
frameworks\native\services\inputflinger\reader\include\InputReader.h
frameworks\native\services\inputflinger\reader\InputReader.cpp
EventHub是核心的事件读取对象
frameworks\native\services\inputflinger\reader\include\EventHub.h
frameworks\native\services\inputflinger\reader\EventHub.cpp
InputDevice设备对象
frameworks\native\services\inputflinger\reader\include\InputDevice.h
frameworks\native\services\inputflinger\reader\InputDevice.cpp
InputMapper事件解析映射基类
frameworks\native\services\inputflinger\reader\mapper\InputMapper.h
frameworks\native\services\inputflinger\reader\mapper\InputMapper.cpp
此处有很多的mapper,以TouchInputMapper为例
frameworks\native\services\inputflinger\reader\mapper\TouchInputMapper.h
frameworks\native\services\inputflinger\reader\mapper\TouchInputMapper.cpp
按钮光标累加器,跟踪按钮按下位置
frameworks\native\services\inputflinger\reader\mapper\accumulator\CursorButtonAccumulator.h
frameworks\native\services\inputflinger\reader\mapper\accumulator\CursorButtonAccumulator.cpp
滚动光标累加器,跟踪光标滚动动作。
frameworks\native\services\inputflinger\reader\mapper\accumulator\CursorScrollAccumulator.h
frameworks\native\services\inputflinger\reader\mapper\accumulator\CursorScrollAccumulator.cpp
触摸按钮累加器,跟踪触摸,触控笔和工具按钮的状态。
frameworks\native\services\inputflinger\reader\mapper\accumulator\TouchButtonAccumulator.h
frameworks\native\services\inputflinger\reader\mapper\accumulator\TouchButtonAccumulator.cpp
触摸映射的基类
frameworks\native\services\inputflinger\reader\mapper\TouchCursorInputMapperCommon.h
事件读取监听,里面维护这事件加工后的事件队列
frameworks\native\services\inputflinger\include\InputListener.h
frameworks\native\services\inputflinger\InputListener.cpp
InputDispatcher是事件分发的类
frameworks\native\services\inputflinger\dispatcher\InputDispatcher.h
frameworks\native\services\inputflinger\dispatcher\InputDispatcher.cpp
学习了这片文章,你就认识了IMS中的第一步。那么有人问能解决什么问题呢?很显然学习了这片文章你不仅仅能更加直观的了解IMS,还能解决一些触屏失效、按键无效等问题。
void InputReader::loopOnce() {
//上一次读取的,在InputReader中进行初始化为1
int32_t oldGeneration;
//读取事件的的超时时间间隔
int32_t timeoutMillis;
//描述设备是否改变,即就是在/dev/下的目录是否改变
bool inputDevicesChanged = false;
std::vector inputDevices;
{ // acquire lock
AutoMutex _l(mLock);
oldGeneration = mGeneration;
//第一次分发重置超时时间为-1,即就是是立马读取事件
timeoutMillis = -1;
//mConfigurationChangesToRefresh在构造中初始化,默认是0
uint32_t changes = mConfigurationChangesToRefresh;
//0是false 1是true
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
//此处开始读取设备,返回的是读取到的时间数量。
//timeoutMillis是读取超时时间
// mEventBuffer 是一个连边,时间会被读取到里面,EVENT_BUFFER_SIZE指的是mEventBuffer的大小,在头文件中定义是256。
//即就是说最多读取到的事件是256个,超过就必须等待下一次读取
size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
{ // acquire lock
AutoMutex _l(mLock);
mReaderIsAliveCondition.broadcast();
//如果读取到的事件大于0个,就解析事件
if (count) {
processEventsLocked(mEventBuffer, count);
}
//判断下一次读取超时事件是否为最大
if (mNextTimeout != LLONG_MAX) {
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
if (now >= mNextTimeout) {
#if DEBUG_RAW_EVENTS
ALOGD("Timeout expired, latency=%0.3fms", (now - mNextTimeout) * 0.000001f);
#endif
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) {
//将设备改变通知给Java层窗口
mPolicy->notifyInputDevicesChanged(inputDevices);
}
// Flush queued events out to the listener.
// This must happen outside of the lock because the listener could potentially call
// back into the InputReader's methods, such as getScanCodeState, or become blocked
// on another thread similarly waiting to acquire the InputReader lock thereby
// resulting in a deadlock. This situation is actually quite plausible because the
// listener is actually the input dispatcher, which calls into the window manager,
// which occasionally calls into the input reader.
//最后将事件放入的InputDispatcher
mQueuedListener->flush();
}
void InputReader::refreshConfigurationLocked(uint32_t changes) {
mPolicy->getReaderConfiguration(&mConfig);
mEventHub->setExcludedDevices(mConfig.excludedDeviceNames);
if (changes) {
ALOGI("Reconfiguring input devices. changes=0x%08x", changes);
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
if (changes & InputReaderConfiguration::CHANGE_MUST_REOPEN) {
//打开设备
mEventHub->requestReopenDevices();
} else {
for (size_t i = 0; i < mDevices.size(); i++) {
InputDevice* device = mDevices.valueAt(i);
//配置设备
device->configure(now, &mConfig, changes);
}
}
}
}
size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
ALOG_ASSERT(bufferSize >= 1);
AutoMutex _l(mLock);
//创建读取缓冲区
struct input_event readBuffer[bufferSize];
//变换指针
RawEvent* event = buffer;
//用一个变量来判断是否已经读满缓,event链表,没读取一个时间,就会减1
size_t capacity = bufferSize;
bool awoken = false;
for (;;) {//此处用一个无线循环读取,当读满或者设备刷新的时候就会跳出
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
// Reopen input devices if needed.
//mNeedToReopenDevices是一个bool值,表示是否需要重新打开设备,默认是false,在构造中初始化。
//该值会随着InputReader中的设备配置刷新,而被设置为true,就是说第一次是不需要重新加载的。
if (mNeedToReopenDevices) {
mNeedToReopenDevices = false;
ALOGI("Reopening all input devices due to a configuration change.");
//如果需要重新打开设备,那么就必须先关闭所有的设备
closeAllDevicesLocked();
mNeedToScanDevices = true;
break; // return to the caller before we actually rescan
}
// Report any devices that had last been added/removed.
// 遍历所有的关闭的设备,将其封装成为移除设备的事件
while (mClosingDevices) {
Device* device = mClosingDevices;
ALOGV("Reporting device closed: id=%d, name=%s\n", device->id, device->path.c_str());
mClosingDevices = device->next;
event->when = now;
event->deviceId = (device->id == mBuiltInKeyboardId)
? ReservedInputDeviceId::BUILT_IN_KEYBOARD_ID
: device->id;
event->type = DEVICE_REMOVED;
event += 1;
delete device;
//此处的含义我并不清楚,我认为可以不要,此处应该是移除设备完成的标记
mNeedToSendFinishedDeviceScan = true;
//链表数量减一,如果链表已经满了,直接跳出循环,等待下次读取
if (--capacity == 0) {
break;
}
}
if (mNeedToScanDevices) {
mNeedToScanDevices = false;
//扫描设备,也就是打开刚刚关闭的设备
scanDevicesLocked();
mNeedToSendFinishedDeviceScan = true;
}
//封装每一个设备添加的
while (mOpeningDevices != nullptr) {
Device* device = mOpeningDevices;
ALOGV("Reporting device opened: id=%d, name=%s\n", device->id, device->path.c_str());
mOpeningDevices = device->next;
event->when = now;
event->deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
event->type = DEVICE_ADDED;
event += 1;
mNeedToSendFinishedDeviceScan = true;
//链表数量减一,如果链表已经满了,直接跳出循环,等待下次读取
if (--capacity == 0) {
break;
}
}
//设备扫描完成事件
if (mNeedToSendFinishedDeviceScan) {
mNeedToSendFinishedDeviceScan = false;
event->when = now;
event->type = FINISHED_DEVICE_SCAN;
event += 1;
//链表数量减一,如果链表已经满了,直接跳出循环,等待下次读取
if (--capacity == 0) {
break;
}
}
// Grab the next input event.
//此处就是正式的事件读取
bool deviceChanged = false;
//判断事件读取的小标和缓存区的大小
while (mPendingEventIndex < mPendingEventCount) {
//获取缓冲区中的事件
const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];
if (eventItem.data.fd == mINotifyFd) {
if (eventItem.events & EPOLLIN) {
mPendingINotify = true;
} else {
ALOGW("Received unexpected epoll event 0x%08x for INotify.", eventItem.events);
}
continue;
}
if (eventItem.data.fd == mWakeReadPipeFd) {
if (eventItem.events & EPOLLIN) {
ALOGV("awoken after wake()");
awoken = true;
char buffer[16];
ssize_t nRead;
do {
往缓冲区buffer中读取事件
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;
}
//通过事件的文件描述符获取对应的设备
Device* device = getDeviceByFdLocked(eventItem.data.fd);
if (!device) {
ALOGE("Received unexpected epoll event 0x%08x for unknown fd %d.", eventItem.events,
eventItem.data.fd);
ALOG_ASSERT(!DEBUG);
continue;
}
//此处是判断是否是v4l设备
if (device->videoDevice && eventItem.data.fd == device->videoDevice->getFd()) {
if (eventItem.events & EPOLLIN) {
size_t numFrames = device->videoDevice->readAndQueueFrames();
if (numFrames == 0) {
ALOGE("Received epoll event for video device %s, but could not read frame",
device->videoDevice->getName().c_str());
}
} else if (eventItem.events & EPOLLHUP) {
// TODO(b/121395353) - consider adding EPOLLRDHUP
ALOGI("Removing video device %s due to epoll hang-up event.",
device->videoDevice->getName().c_str());
unregisterVideoDeviceFromEpollLocked(*device->videoDevice);
device->videoDevice = nullptr;
} else {
ALOGW("Received unexpected epoll event 0x%08x for device %s.", eventItem.events,
device->videoDevice->getName().c_str());
ALOG_ASSERT(!DEBUG);
}
continue;
}
// This must be an input event
if (eventItem.events & EPOLLIN) {//有事件到来,有数据
//王缓冲区readBuffer中读取事件
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);
//将读取到的事件逐个封装成RawEvent事件
for (size_t i = 0; i < count; i++) {
struct input_event& iev = readBuffer[i];
event->when = processEventTimestamp(iev);
event->deviceId = deviceId;//设备ID
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
mPendingEventIndex -= 1;
break;
}
}
} else if (eventItem.events & EPOLLHUP) {//eppoll机制,说的是没有检测到没有读取到事件
ALOGI("Removing device %s due to epoll hang-up event.",
device->identifier.name.c_str());
deviceChanged = true;
closeDeviceLocked(device);
} else {
ALOGW("Received unexpected epoll event 0x%08x for device %s.", eventItem.events,
device->identifier.name.c_str());
}
}
// readNotify() will modify the list of devices so this must be done after
// processing all other events to ensure that we read all remaining events
// before closing the devices.
// readNotify()将修改设备列表,因此必须在处理所有其他事件之后执行此操作,以确保在关闭设备之前读取所有剩余事件。
if (mPendingINotify && mPendingEventIndex >= mPendingEventCount) {
mPendingINotify = false;
readNotifyLocked();
deviceChanged = true;
}
// Report added or removed devices immediately.
//设备改变就要重新扫描设备,重新执行循环
if (deviceChanged) {
continue;
}
// Return now if we have collected any events or if we were explicitly awoken.
//如果我们已经读取了任何事件或被明确唤醒,请立即返回。
if (event != buffer || awoken) {
break;
}
// Poll for events. Mind the wake lock dance!
// We hold a wake lock at all times except during epoll_wait(). This works due to some
// subtle choreography. When a device driver has pending (unread) events, it acquires
// a kernel wake lock. However, once the last pending event has been read, the device
// driver will release the kernel wake lock. To prevent the system from going to sleep
// when this happens, the EventHub holds onto its own user wake lock while the client
// is processing events. Thus the system can only sleep if there are no events
// pending or currently being processed.
//
// The timeout is advisory only. If the device is asleep, it will not wake just to
// service the timeout.
//轮询事件。 注意唤醒锁! 除了在epoll_wait()期间,我们始终保持唤醒锁。 由于一些微妙的编排,所以此方法有效。
//当设备驱动程序具有挂起(未读)事件时,它将获取内核唤醒锁。 但是,一旦读取了最后一个未决事件,设备驱动程序将释放内核唤醒锁。
//为了防止系统在这种情况下进入睡眠状态,在客户端处理事件时,EventHub会保留其自己的用户唤醒锁。
//因此,只有在没有待处理或当前正在处理的事件时,系统才能进入睡眠状态。超时仅是建议性的。
// 如果设备处于睡眠状态,它不会仅出于超时目的而唤醒。
mPendingEventIndex = 0;
mLock.unlock(); // release lock before poll, must be before release_wake_lock
release_wake_lock(WAKE_LOCK_ID);
//此处就是从epoll中将事件读取到mPendingEventItems的数组中,EPOLL_MAX_EVENTS = 16
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
//如果读取到结果是0,就是没读到,线程就会一直被阻塞
if (pollResult == 0) {
// Timed out.
mPendingEventCount = 0;
break;
}
//如果读取到的是负数说明,Linux内核产生了anr
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.
mPendingEventCount = size_t(pollResult);
//如果都不是,mPendingEventCount缓冲区的数量就是读取到的数据
}
}
// All done, return the number of events we read.
// 最后返回读取的事件数量
return event - buffer;
}
void EventHub::closeAllDevicesLocked() {
mUnattachedVideoDevices.clear();
while (mDevices.size() > 0) {
closeDeviceLocked(mDevices.valueAt(mDevices.size() - 1));
}
}
void EventHub::closeDeviceLocked(Device* device) {
ALOGI("Removed device: path=%s name=%s id=%d fd=%d classes=0x%x", device->path.c_str(),
device->identifier.name.c_str(), device->id, device->fd, device->classes);
if (device->id == mBuiltInKeyboardId) {
ALOGW("built-in keyboard device %s (id=%d) is closing! the apps will not like this",
device->path.c_str(), mBuiltInKeyboardId);
mBuiltInKeyboardId = NO_BUILT_IN_KEYBOARD;
}
unregisterDeviceFromEpollLocked(device);
if (device->videoDevice) {
// This must be done after the video device is removed from epoll
mUnattachedVideoDevices.push_back(std::move(device->videoDevice));
}
releaseControllerNumberLocked(device);
mDevices.removeItem(device->id);
device->close();
// Unlink for opening devices list if it is present.
Device* pred = nullptr;
bool found = false;
for (Device* entry = mOpeningDevices; entry != nullptr;) {
if (entry == device) {
found = true;
break;
}
pred = entry;
entry = entry->next;
}
if (found) {
// Unlink the device from the opening devices list then delete it.
// We don't need to tell the client that the device was closed because
// it does not even know it was opened in the first place.
ALOGI("Device %s was immediately closed after opening.", device->path.c_str());
if (pred) {
pred->next = device->next;
} else {
mOpeningDevices = device->next;
}
delete device;
} else {
// Link into closing devices list.
// The device will be deleted later after we have informed the client.
device->next = mClosingDevices;
mClosingDevices = device;
}
}
void EventHub::scanDevicesLocked() {
//扫描/dev/input目录打开
status_t result = scanDirLocked(DEVICE_PATH);
if (result < 0) {
ALOGE("scan dir failed for %s", DEVICE_PATH);
}
if (isV4lScanningEnabled()) {
result = scanVideoDirLocked(VIDEO_DEVICE_PATH);
if (result != OK) {
ALOGE("scan video dir failed for %s", VIDEO_DEVICE_PATH);
}
}
if (mDevices.indexOfKey(ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID) < 0) {
createVirtualKeyboardLocked();
}
}
status_t EventHub::scanDirLocked(const char* dirname) {
char devname[PATH_MAX];
char* filename;
DIR* dir;
struct dirent* de;
//读取逐个目录
dir = opendir(dirname);
if (dir == nullptr) return -1;
strcpy(devname, dirname);
filename = devname + strlen(devname);
*filename++ = '/';
while ((de = readdir(dir))) {
if (de->d_name[0] == '.' &&
(de->d_name[1] == '\0' || (de->d_name[1] == '.' && de->d_name[2] == '\0')))
continue;
strcpy(filename, de->d_name);
//dev/input下的一个目录代表一个设备,将其打开
openDeviceLocked(devname);
}
//关闭目录流
closedir(dir);
return 0;
}
status_t EventHub::openDeviceLocked(const char* devicePath) {
char buffer[80];
ALOGV("Opening device: %s", devicePath);
//获取文件描述符
int fd = open(devicePath, O_RDWR | O_CLOEXEC | O_NONBLOCK);
if (fd < 0) {
ALOGE("could not open %s, %s\n", devicePath, strerror(errno));
return -1;
}
//设备标识
InputDeviceIdentifier identifier;
// Get device name.
if (ioctl(fd, EVIOCGNAME(sizeof(buffer) - 1), &buffer) < 1) {
ALOGE("Could not get device name for %s: %s", devicePath, strerror(errno));
} else {
buffer[sizeof(buffer) - 1] = '\0';
identifier.name = buffer;
}
// Check to see if the device is on our excluded list
for (size_t i = 0; i < mExcludedDevices.size(); i++) {
const std::string& item = mExcludedDevices[i];
if (identifier.name == item) {
ALOGI("ignoring event id %s driver %s\n", devicePath, item.c_str());
close(fd);
return -1;
}
}
// Get device driver version.
//获取驱动版本
int driverVersion;
if (ioctl(fd, EVIOCGVERSION, &driverVersion)) {
ALOGE("could not get driver version for %s, %s\n", devicePath, strerror(errno));
close(fd);
return -1;
}
// Get device identifier.
struct input_id inputId;
if (ioctl(fd, EVIOCGID, &inputId)) {
ALOGE("could not get device input id for %s, %s\n", devicePath, strerror(errno));
close(fd);
return -1;
}
identifier.bus = inputId.bustype;
identifier.product = inputId.product;
identifier.vendor = inputId.vendor;
identifier.version = inputId.version;
// Get device physical location.
if (ioctl(fd, EVIOCGPHYS(sizeof(buffer) - 1), &buffer) < 1) {
// fprintf(stderr, "could not get location for %s, %s\n", devicePath, strerror(errno));
} else {
buffer[sizeof(buffer) - 1] = '\0';
identifier.location = buffer;
}
// Get device unique id.
if (ioctl(fd, EVIOCGUNIQ(sizeof(buffer) - 1), &buffer) < 1) {
// fprintf(stderr, "could not get idstring for %s, %s\n", devicePath, strerror(errno));
} else {
buffer[sizeof(buffer) - 1] = '\0';
identifier.uniqueId = buffer;
}
// Fill in the descriptor.
//生成设备标识符
assignDescriptorLocked(identifier);
// Allocate device. (The device object takes ownership of the fd at this point.)
int32_t deviceId = mNextDeviceId++;
//创建设备对象
Device* device = new Device(fd, deviceId, devicePath, identifier);
ALOGV("add device %d: %s\n", deviceId, devicePath);
ALOGV(" bus: %04x\n"
" vendor %04x\n"
" product %04x\n"
" version %04x\n",
identifier.bus, identifier.vendor, identifier.product, identifier.version);
ALOGV(" name: \"%s\"\n", identifier.name.c_str());
ALOGV(" location: \"%s\"\n", identifier.location.c_str());
ALOGV(" unique id: \"%s\"\n", identifier.uniqueId.c_str());
ALOGV(" descriptor: \"%s\"\n", identifier.descriptor.c_str());
ALOGV(" driver: v%d.%d.%d\n", driverVersion >> 16, (driverVersion >> 8) & 0xff,
driverVersion & 0xff);
// Load the configuration file for the device.
加载配置
loadConfigurationLocked(device);
// Figure out the kinds of events the device reports.
// 获取设备上报事件类型
ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(device->keyBitmask)), device->keyBitmask);
ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(device->absBitmask)), device->absBitmask);
ioctl(fd, EVIOCGBIT(EV_REL, sizeof(device->relBitmask)), device->relBitmask);
ioctl(fd, EVIOCGBIT(EV_SW, sizeof(device->swBitmask)), device->swBitmask);
ioctl(fd, EVIOCGBIT(EV_LED, sizeof(device->ledBitmask)), device->ledBitmask);
ioctl(fd, EVIOCGBIT(EV_FF, sizeof(device->ffBitmask)), device->ffBitmask);
ioctl(fd, EVIOCGPROP(sizeof(device->propBitmask)), device->propBitmask);
// See if this is a keyboard. Ignore everything in the button range except for
// joystick and gamepad buttons which are handled like keyboards for the most part.
bool haveKeyboardKeys =
containsNonZeroByte(device->keyBitmask, 0, sizeof_bit_array(BTN_MISC)) ||
containsNonZeroByte(device->keyBitmask, sizeof_bit_array(KEY_OK),
sizeof_bit_array(KEY_MAX + 1));
bool haveGamepadButtons = containsNonZeroByte(device->keyBitmask, sizeof_bit_array(BTN_MISC),
sizeof_bit_array(BTN_MOUSE)) ||
containsNonZeroByte(device->keyBitmask, sizeof_bit_array(BTN_JOYSTICK),
sizeof_bit_array(BTN_DIGI));
if (haveKeyboardKeys || haveGamepadButtons) {
device->classes |= INPUT_DEVICE_CLASS_KEYBOARD;
}
// See if this is a cursor device such as a trackball or mouse.
if (test_bit(BTN_MOUSE, device->keyBitmask) && test_bit(REL_X, device->relBitmask) &&
test_bit(REL_Y, device->relBitmask)) {
device->classes |= INPUT_DEVICE_CLASS_CURSOR;
}
// See if this is a rotary encoder type device.
String8 deviceType = String8();
if (device->configuration &&
device->configuration->tryGetProperty(String8("device.type"), deviceType)) {
if (!deviceType.compare(String8("rotaryEncoder"))) {
device->classes |= INPUT_DEVICE_CLASS_ROTARY_ENCODER;
}
}
// See if this is a touch pad.
// Is this a new modern multi-touch driver?
if (test_bit(ABS_MT_POSITION_X, device->absBitmask) &&
test_bit(ABS_MT_POSITION_Y, device->absBitmask)) {
// Some joysticks such as the PS3 controller report axes that conflict
// with the ABS_MT range. Try to confirm that the device really is
// a touch screen.
if (test_bit(BTN_TOUCH, device->keyBitmask) || !haveGamepadButtons) {
device->classes |= INPUT_DEVICE_CLASS_TOUCH | INPUT_DEVICE_CLASS_TOUCH_MT;
}
// Is this an old style single-touch driver?
} else if (test_bit(BTN_TOUCH, device->keyBitmask) && test_bit(ABS_X, device->absBitmask) &&
test_bit(ABS_Y, device->absBitmask)) {
device->classes |= INPUT_DEVICE_CLASS_TOUCH;
// Is this a BT stylus?
} else if ((test_bit(ABS_PRESSURE, device->absBitmask) ||
test_bit(BTN_TOUCH, device->keyBitmask)) &&
!test_bit(ABS_X, device->absBitmask) && !test_bit(ABS_Y, device->absBitmask)) {
device->classes |= INPUT_DEVICE_CLASS_EXTERNAL_STYLUS;
// Keyboard will try to claim some of the buttons but we really want to reserve those so we
// can fuse it with the touch screen data, so just take them back. Note this means an
// external stylus cannot also be a keyboard device.
device->classes &= ~INPUT_DEVICE_CLASS_KEYBOARD;
}
// See if this device is a joystick.
// Assumes that joysticks always have gamepad buttons in order to distinguish them
// from other devices such as accelerometers that also have absolute axes.
if (haveGamepadButtons) {
uint32_t assumedClasses = device->classes | INPUT_DEVICE_CLASS_JOYSTICK;
for (int i = 0; i <= ABS_MAX; i++) {
if (test_bit(i, device->absBitmask) &&
(getAbsAxisUsage(i, assumedClasses) & INPUT_DEVICE_CLASS_JOYSTICK)) {
device->classes = assumedClasses;
break;
}
}
}
// Check whether this device has switches.
for (int i = 0; i <= SW_MAX; i++) {
if (test_bit(i, device->swBitmask)) {
device->classes |= INPUT_DEVICE_CLASS_SWITCH;
break;
}
}
// Check whether this device supports the vibrator.
// 事件是否震动
if (test_bit(FF_RUMBLE, device->ffBitmask)) {
device->classes |= INPUT_DEVICE_CLASS_VIBRATOR;
}
// Configure virtual keys.
if ((device->classes & INPUT_DEVICE_CLASS_TOUCH)) {
// Load the virtual keys for the touch screen, if any.
// We do this now so that we can make sure to load the keymap if necessary.
//加载映射
bool success = loadVirtualKeyMapLocked(device);
if (success) {
device->classes |= INPUT_DEVICE_CLASS_KEYBOARD;
}
}
// Load the key map.
// We need to do this for joysticks too because the key layout may specify axes.
status_t keyMapStatus = NAME_NOT_FOUND;
if (device->classes & (INPUT_DEVICE_CLASS_KEYBOARD | INPUT_DEVICE_CLASS_JOYSTICK)) {
// Load the keymap for the device.
keyMapStatus = loadKeyMapLocked(device);
}
// Configure the keyboard, gamepad or virtual keyboard.
if (device->classes & INPUT_DEVICE_CLASS_KEYBOARD) {
// Register the keyboard as a built-in keyboard if it is eligible.
if (!keyMapStatus && mBuiltInKeyboardId == NO_BUILT_IN_KEYBOARD &&
isEligibleBuiltInKeyboard(device->identifier, device->configuration, &device->keyMap)) {
mBuiltInKeyboardId = device->id;
}
// 'Q' key support = cheap test of whether this is an alpha-capable kbd
if (hasKeycodeLocked(device, AKEYCODE_Q)) {
device->classes |= INPUT_DEVICE_CLASS_ALPHAKEY;
}
// See if this device has a DPAD.
if (hasKeycodeLocked(device, AKEYCODE_DPAD_UP) &&
hasKeycodeLocked(device, AKEYCODE_DPAD_DOWN) &&
hasKeycodeLocked(device, AKEYCODE_DPAD_LEFT) &&
hasKeycodeLocked(device, AKEYCODE_DPAD_RIGHT) &&
hasKeycodeLocked(device, AKEYCODE_DPAD_CENTER)) {
device->classes |= INPUT_DEVICE_CLASS_DPAD;
}
// See if this device has a gamepad.
for (size_t i = 0; i < sizeof(GAMEPAD_KEYCODES) / sizeof(GAMEPAD_KEYCODES[0]); i++) {
if (hasKeycodeLocked(device, GAMEPAD_KEYCODES[i])) {
device->classes |= INPUT_DEVICE_CLASS_GAMEPAD;
break;
}
}
}
// If the device isn't recognized as something we handle, don't monitor it.
if (device->classes == 0) {
ALOGV("Dropping device: id=%d, path='%s', name='%s'", deviceId, devicePath,
device->identifier.name.c_str());
delete device;
return -1;
}
// Determine whether the device has a mic.
if (deviceHasMicLocked(device)) {
device->classes |= INPUT_DEVICE_CLASS_MIC;
}
// Determine whether the device is external or internal.
if (isExternalDeviceLocked(device)) {
device->classes |= INPUT_DEVICE_CLASS_EXTERNAL;
}
if (device->classes & (INPUT_DEVICE_CLASS_JOYSTICK | INPUT_DEVICE_CLASS_DPAD) &&
device->classes & INPUT_DEVICE_CLASS_GAMEPAD) {
device->controllerNumber = getNextControllerNumberLocked(device);
setLedForControllerLocked(device);
}
// Find a matching video device by comparing device names
// This should be done before registerDeviceForEpollLocked, so that both fds are added to epoll
for (std::unique_ptr& videoDevice : mUnattachedVideoDevices) {
if (device->identifier.name == videoDevice->getName()) {
device->videoDevice = std::move(videoDevice);
break;
}
}
mUnattachedVideoDevices
.erase(std::remove_if(mUnattachedVideoDevices.begin(), mUnattachedVideoDevices.end(),
[](const std::unique_ptr& videoDevice) {
return videoDevice == nullptr;
}),
mUnattachedVideoDevices.end());
if (registerDeviceForEpollLocked(device) != OK) {
delete device;
return -1;
}
configureFd(device);
ALOGI("New device: id=%d, fd=%d, path='%s', name='%s', classes=0x%x, "
"configuration='%s', keyLayout='%s', keyCharacterMap='%s', builtinKeyboard=%s, ",
deviceId, fd, devicePath, device->identifier.name.c_str(), device->classes,
device->configurationFile.c_str(), device->keyMap.keyLayoutFile.c_str(),
device->keyMap.keyCharacterMapFile.c_str(), toString(mBuiltInKeyboardId == deviceId));
addDeviceLocked(device);
return OK;
}
void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {
for (const RawEvent* rawEvent = rawEvents; count;) {
int32_t type = rawEvent->type;
size_t batchSize = 1;
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;
}
#if DEBUG_RAW_EVENTS
ALOGD("BatchSize: %zu Count: %zu", batchSize, count);
#endif
processEventsForDeviceLocked(deviceId, rawEvent, batchSize);
} else {
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;
}
}
count -= batchSize;
rawEvent += batchSize;
}
}
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;
}
InputDevice* device = mDevices.valueAt(deviceIndex);
if (device->isIgnored()) {
// ALOGD("Discarding event for ignored deviceId %d.", deviceId);
return;
}
device->process(rawEvents, count);
}
//解析事件
void InputDevice::process(const RawEvent* rawEvents, size_t count) {
// Process all of the events in order for each mapper.
// We cannot simply ask each mapper to process them in bulk because mappers may
// have side-effects that must be interleaved. For example, joystick movement events and
// gamepad button presses are handled by different mappers but they should be dispatched
// in the order received.
for (const RawEvent* rawEvent = rawEvents; count != 0; rawEvent++) {
#if DEBUG_RAW_EVENTS
ALOGD("Input event: device=%d type=0x%04x code=0x%04x value=0x%08x when=%" PRId64,
rawEvent->deviceId, rawEvent->type, rawEvent->code, rawEvent->value, rawEvent->when);
#endif
if (mDropUntilNextSync) {
if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
mDropUntilNextSync = false;
#if DEBUG_RAW_EVENTS
ALOGD("Recovered from input event buffer overrun.");
#endif
} else {
#if DEBUG_RAW_EVENTS
ALOGD("Dropped input event while waiting for next input sync.");
#endif
}
} else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_DROPPED) {
ALOGI("Detected input event buffer overrun for device %s.", getName().c_str());
mDropUntilNextSync = true;
reset(rawEvent->when);
} else {
for (InputMapper* mapper : mMappers) {
mapper->process(rawEvent);
}
}
--count;
}
}
void TouchInputMapper::process(const RawEvent* rawEvent) {
mCursorButtonAccumulator.process(rawEvent);
mCursorScrollAccumulator.process(rawEvent);
mTouchButtonAccumulator.process(rawEvent);
if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
reportEventForStatistics(rawEvent->when);
sync(rawEvent->when);
}
}
void TouchInputMapper::sync(nsecs_t when) {
const RawState* last =
mRawStatesPending.empty() ? &mCurrentRawState : &mRawStatesPending.back();
// Push a new state.
mRawStatesPending.emplace_back();
RawState* next = &mRawStatesPending.back();
next->clear();
next->when = when;
// Sync button state.
next->buttonState =
mTouchButtonAccumulator.getButtonState() | mCursorButtonAccumulator.getButtonState();
// Sync scroll
next->rawVScroll = mCursorScrollAccumulator.getRelativeVWheel();
next->rawHScroll = mCursorScrollAccumulator.getRelativeHWheel();
mCursorScrollAccumulator.finishSync();
// Sync touch
syncTouch(when, next);
// Assign pointer ids.
if (!mHavePointerIds) {
assignPointerIds(last, next);
}
#if DEBUG_RAW_EVENTS
ALOGD("syncTouch: pointerCount %d -> %d, touching ids 0x%08x -> 0x%08x, "
"hovering ids 0x%08x -> 0x%08x",
last->rawPointerData.pointerCount, next->rawPointerData.pointerCount,
last->rawPointerData.touchingIdBits.value, next->rawPointerData.touchingIdBits.value,
last->rawPointerData.hoveringIdBits.value, next->rawPointerData.hoveringIdBits.value);
#endif
processRawTouches(false /*timeout*/);
}
void TouchInputMapper::processRawTouches(bool timeout) {
if (mDeviceMode == DEVICE_MODE_DISABLED) {
// Drop all input if the device is disabled.
mCurrentRawState.clear();
mRawStatesPending.clear();
return;
}
// Drain any pending touch states. The invariant here is that the mCurrentRawState is always
// valid and must go through the full cook and dispatch cycle. This ensures that anything
// touching the current state will only observe the events that have been dispatched to the
// rest of the pipeline.
//清空所有未决的触摸状态。 这里的不变之处在于,mCurrentRawState始终有效,并且必须经过完整的烹饪和调度周期。
//这样可以确保任何接触当前状态的事件都只能观察到已调度到管道其余部分的事件。
const size_t N = mRawStatesPending.size();
size_t count;
for (count = 0; count < N; count++) {
const RawState& next = mRawStatesPending[count];
// A failure to assign the stylus id means that we're waiting on stylus data
// and so should defer the rest of the pipeline.
//未能分配手写笔ID表示我们正在等待手写笔数据,因此应延迟其余的管道。
if (assignExternalStylusId(next, timeout)) {
break;
}
// All ready to go.
clearStylusDataPendingFlags();
mCurrentRawState.copyFrom(next);
if (mCurrentRawState.when < mLastRawState.when) {
mCurrentRawState.when = mLastRawState.when;
}
cookAndDispatch(mCurrentRawState.when);
}
if (count != 0) {
mRawStatesPending.erase(mRawStatesPending.begin(), mRawStatesPending.begin() + count);
}
if (mExternalStylusDataPending) {
if (timeout) {
nsecs_t when = mExternalStylusFusionTimeout - STYLUS_DATA_LATENCY;
clearStylusDataPendingFlags();
mCurrentRawState.copyFrom(mLastRawState);
#if DEBUG_STYLUS_FUSION
ALOGD("Timeout expired, synthesizing event with new stylus data");
#endif
cookAndDispatch(when);
} else if (mExternalStylusFusionTimeout == LLONG_MAX) {
mExternalStylusFusionTimeout = mExternalStylusState.when + TOUCH_DATA_TIMEOUT;
getContext()->requestTimeoutAtTime(mExternalStylusFusionTimeout);
}
}
}
void TouchInputMapper::cookAndDispatch(nsecs_t when) {
// Always start with a clean state.
mCurrentCookedState.clear();
// Apply stylus buttons to current raw state.
applyExternalStylusButtonState(when);
// Handle policy on initial down or hover events.
bool initialDown = mLastRawState.rawPointerData.pointerCount == 0 &&
mCurrentRawState.rawPointerData.pointerCount != 0;
uint32_t policyFlags = 0;
bool buttonsPressed = mCurrentRawState.buttonState & ~mLastRawState.buttonState;
//处理按压
if (initialDown || buttonsPressed) {
// If this is a touch screen, hide the pointer on an initial down.
if (mDeviceMode == DEVICE_MODE_DIRECT) {
getContext()->fadePointer();
}
if (mParameters.wake) {
policyFlags |= POLICY_FLAG_WAKE;
}
}
// Consume raw off-screen touches before cooking pointer data.
// If touches are consumed, subsequent code will not receive any pointer data.
if (consumeRawTouches(when, policyFlags)) {
mCurrentRawState.rawPointerData.clear();
}
// Cook pointer data. This call populates the mCurrentCookedState.cookedPointerData structure
// with cooked pointer data that has the same ids and indices as the raw data.
// The following code can use either the raw or cooked data, as needed.
//处理当前的压力,距离,以及屏幕方向等等
cookPointerData();
// Apply stylus pressure to current cooked state.
applyExternalStylusTouchState(when);
// Synthesize key down from raw buttons if needed.
// 根据需要从原始按钮向下合成键。
synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, getDeviceId(), mSource,
mViewport.displayId, policyFlags, mLastCookedState.buttonState,
mCurrentCookedState.buttonState);
// Dispatch the touches either directly or by translation through a pointer on screen.
if (mDeviceMode == DEVICE_MODE_POINTER) {
for (BitSet32 idBits(mCurrentRawState.rawPointerData.touchingIdBits); !idBits.isEmpty();) {
uint32_t id = idBits.clearFirstMarkedBit();
const RawPointerData::Pointer& pointer =
mCurrentRawState.rawPointerData.pointerForId(id);
if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS ||
pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) {
mCurrentCookedState.stylusIdBits.markBit(id);
} else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_FINGER ||
pointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) {
mCurrentCookedState.fingerIdBits.markBit(id);
} else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_MOUSE) {
mCurrentCookedState.mouseIdBits.markBit(id);
}
}
for (BitSet32 idBits(mCurrentRawState.rawPointerData.hoveringIdBits); !idBits.isEmpty();) {
uint32_t id = idBits.clearFirstMarkedBit();
const RawPointerData::Pointer& pointer =
mCurrentRawState.rawPointerData.pointerForId(id);
if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS ||
pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) {
mCurrentCookedState.stylusIdBits.markBit(id);
}
}
// Stylus takes precedence over all tools, then mouse, then finger.
PointerUsage pointerUsage = mPointerUsage;
if (!mCurrentCookedState.stylusIdBits.isEmpty()) {
mCurrentCookedState.mouseIdBits.clear();
mCurrentCookedState.fingerIdBits.clear();
pointerUsage = POINTER_USAGE_STYLUS;
} else if (!mCurrentCookedState.mouseIdBits.isEmpty()) {
mCurrentCookedState.fingerIdBits.clear();
pointerUsage = POINTER_USAGE_MOUSE;
} else if (!mCurrentCookedState.fingerIdBits.isEmpty() ||
isPointerDown(mCurrentRawState.buttonState)) {
pointerUsage = POINTER_USAGE_GESTURES;
}
dispatchPointerUsage(when, policyFlags, pointerUsage);
} else {
if (mDeviceMode == DEVICE_MODE_DIRECT && mConfig.showTouches &&
mPointerController != nullptr) {
mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_SPOT);
mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
mPointerController->setButtonState(mCurrentRawState.buttonState);
mPointerController->setSpots(mCurrentCookedState.cookedPointerData.pointerCoords,
mCurrentCookedState.cookedPointerData.idToIndex,
mCurrentCookedState.cookedPointerData.touchingIdBits,
mViewport.displayId);
}
if (!mCurrentMotionAborted) {
dispatchButtonRelease(when, policyFlags);
dispatchHoverExit(when, policyFlags);
dispatchTouches(when, policyFlags);
dispatchHoverEnterAndMove(when, policyFlags);
dispatchButtonPress(when, policyFlags);
}
if (mCurrentCookedState.cookedPointerData.pointerCount == 0) {
mCurrentMotionAborted = false;
}
}
// Synthesize key up from raw buttons if needed.
synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, getDeviceId(), mSource,
mViewport.displayId, policyFlags, mLastCookedState.buttonState,
mCurrentCookedState.buttonState);
// Clear some transient state.
mCurrentRawState.rawVScroll = 0;
mCurrentRawState.rawHScroll = 0;
// Copy current touch to last touch in preparation for the next cycle.
mLastRawState.copyFrom(mCurrentRawState);
mLastCookedState.copyFrom(mCurrentCookedState);
}
static void synthesizeButtonKey(InputReaderContext* context, int32_t action, nsecs_t when,
int32_t deviceId, uint32_t source, int32_t displayId,
uint32_t policyFlags, int32_t lastButtonState,
int32_t currentButtonState, int32_t buttonState, int32_t keyCode) {
if ((action == AKEY_EVENT_ACTION_DOWN && !(lastButtonState & buttonState) &&
(currentButtonState & buttonState)) ||
(action == AKEY_EVENT_ACTION_UP && (lastButtonState & buttonState) &&
!(currentButtonState & buttonState))) {
NotifyKeyArgs args(context->getNextSequenceNum(), when, deviceId, source, displayId,
policyFlags, action, 0, keyCode, 0, context->getGlobalMetaState(), when);
context->getListener()->notifyKey(&args);
}
}
static void synthesizeButtonKeys(InputReaderContext* context, int32_t action, nsecs_t when,
int32_t deviceId, uint32_t source, int32_t displayId,
uint32_t policyFlags, int32_t lastButtonState,
int32_t currentButtonState) {
synthesizeButtonKey(context, action, when, deviceId, source, displayId, policyFlags,
lastButtonState, currentButtonState, AMOTION_EVENT_BUTTON_BACK,
AKEYCODE_BACK);
synthesizeButtonKey(context, action, when, deviceId, source, displayId, policyFlags,
lastButtonState, currentButtonState, AMOTION_EVENT_BUTTON_FORWARD,
AKEYCODE_FORWARD);
}
void NotifyMotionArgs::notify(const sp& listener) const {
listener->notifyMotion(this);
}
void QueuedInputListener::flush() {
size_t count = mArgsQueue.size();
for (size_t i = 0; i < count; i++) {
NotifyArgs* args = mArgsQueue[i];
//此处的mInnerListener就是InputDispather
args->notify(mInnerListener);
delete args;
}
mArgsQueue.clear();
}
void QueuedInputListener::notifyKey(const NotifyKeyArgs* args) {
mArgsQueue.push_back(new NotifyKeyArgs(*args));
}
void QueuedInputListener::notifyMotion(const NotifyMotionArgs* args) {
mArgsQueue.push_back(new NotifyMotionArgs(*args));
}
void QueuedInputListener::notifySwitch(const NotifySwitchArgs* args) {
mArgsQueue.push_back(new NotifySwitchArgs(*args));
}
void QueuedInputListener::notifyDeviceReset(const NotifyDeviceResetArgs* args) {
mArgsQueue.push_back(new NotifyDeviceResetArgs(*args));
}
void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) {
#if DEBUG_INBOUND_EVENT_DETAILS
ALOGD("notifyMotion - eventTime=%" PRId64 ", deviceId=%d, source=0x%x, displayId=%" PRId32
", policyFlags=0x%x, "
"action=0x%x, actionButton=0x%x, flags=0x%x, metaState=0x%x, buttonState=0x%x,"
"edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%" PRId64,
args->eventTime, args->deviceId, args->source, args->displayId, args->policyFlags,
args->action, args->actionButton, args->flags, args->metaState, args->buttonState,
args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime);
for (uint32_t i = 0; i < args->pointerCount; i++) {
ALOGD(" Pointer %d: id=%d, toolType=%d, "
"x=%f, y=%f, pressure=%f, size=%f, "
"touchMajor=%f, touchMinor=%f, toolMajor=%f, toolMinor=%f, "
"orientation=%f",
i, args->pointerProperties[i].id, args->pointerProperties[i].toolType,
args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X),
args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y),
args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE),
args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_SIZE),
args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR),
args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR),
args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR),
args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR),
args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION));
}
#endif
if (!validateMotionEvent(args->action, args->actionButton, args->pointerCount,
args->pointerProperties)) {
return;
}
uint32_t policyFlags = args->policyFlags;
policyFlags |= POLICY_FLAG_TRUSTED;
android::base::Timer t;
mPolicy->interceptMotionBeforeQueueing(args->displayId, args->eventTime, /*byref*/ policyFlags);
if (t.duration() > SLOW_INTERCEPTION_THRESHOLD) {
ALOGW("Excessive delay in interceptMotionBeforeQueueing; took %s ms",
std::to_string(t.duration().count()).c_str());
}
bool needWake;
{ // acquire lock
mLock.lock();
if (shouldSendMotionToInputFilterLocked(args)) {
mLock.unlock();
MotionEvent event;
event.initialize(args->deviceId, args->source, args->displayId, args->action,
args->actionButton, args->flags, args->edgeFlags, args->metaState,
args->buttonState, args->classification, 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 =
new MotionEntry(args->sequenceNum, args->eventTime, args->deviceId, args->source,
args->displayId, policyFlags, args->action, args->actionButton,
args->flags, args->metaState, args->buttonState,
args->classification, args->edgeFlags, args->xPrecision,
args->yPrecision, args->downTime, args->pointerCount,
args->pointerProperties, args->pointerCoords, 0, 0);
needWake = enqueueInboundEventLocked(newEntry);
mLock.unlock();
} // release lock
if (needWake) {
mLooper->wake();
}
}
void NativeInputManager::interceptMotionBeforeQueueing(const int32_t displayId, nsecs_t when,
uint32_t& policyFlags) {
ATRACE_CALL();
// Policy:
// - Ignore untrusted events and pass them along.
// - No special filtering for injected events required at this time.
// - Filter normal events based on screen state.
// - For normal events brighten (but do not wake) the screen if currently dim.
bool interactive = mInteractive.load();
if (interactive) {
policyFlags |= POLICY_FLAG_INTERACTIVE;
}
if ((policyFlags & POLICY_FLAG_TRUSTED) && !(policyFlags & POLICY_FLAG_INJECTED)) {
if (policyFlags & POLICY_FLAG_INTERACTIVE) {
policyFlags |= POLICY_FLAG_PASS_TO_USER;
} else {
JNIEnv* env = jniEnv();
jint wmActions = env->CallIntMethod(mServiceObj,
gServiceClassInfo.interceptMotionBeforeQueueingNonInteractive,
displayId, when, policyFlags);
if (checkAndClearExceptionFromCallback(env,
"interceptMotionBeforeQueueingNonInteractive")) {
wmActions = 0;
}
handleInterceptActions(wmActions, when, /*byref*/ policyFlags);
}
} else {
if (interactive) {
policyFlags |= POLICY_FLAG_PASS_TO_USER;
}
}
}
bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {
bool needWake = mInboundQueue.isEmpty();
mInboundQueue.enqueueAtTail(entry);
traceInboundQueueLengthLocked();
switch (entry->type) {
case EventEntry::TYPE_KEY: {
// Optimize app switch latency.
// If the application takes too long to catch up then we drop all events preceding
// the app switch key.
KeyEntry* keyEntry = static_cast(entry);
if (isAppSwitchKeyEvent(keyEntry)) {
if (keyEntry->action == AKEY_EVENT_ACTION_DOWN) {
mAppSwitchSawKeyDown = true;
} else if (keyEntry->action == AKEY_EVENT_ACTION_UP) {
if (mAppSwitchSawKeyDown) {
#if DEBUG_APP_SWITCH
ALOGD("App switch is pending!");
#endif
mAppSwitchDueTime = keyEntry->eventTime + APP_SWITCH_TIMEOUT;
mAppSwitchSawKeyDown = false;
needWake = true;
}
}
}
break;
}
case EventEntry::TYPE_MOTION: {
// Optimize case where the current application is unresponsive and the user
// decides to touch a window in a different application.
// If the application takes too long to catch up then we drop all events preceding
// the touch into the other window.
MotionEntry* motionEntry = static_cast(entry);
if (motionEntry->action == AMOTION_EVENT_ACTION_DOWN &&
(motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) &&
mInputTargetWaitCause == INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY &&
mInputTargetWaitApplicationToken != nullptr) {
int32_t displayId = motionEntry->displayId;
int32_t x =
int32_t(motionEntry->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X));
int32_t y =
int32_t(motionEntry->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y));
sp touchedWindowHandle =
findTouchedWindowAtLocked(displayId, x, y);
if (touchedWindowHandle != nullptr &&
touchedWindowHandle->getApplicationToken() !=
mInputTargetWaitApplicationToken) {
// User touched a different application than the one we are waiting on.
// Flag the event, and start pruning the input queue.
mNextUnblockedEvent = motionEntry;
needWake = true;
}
}
break;
}
}
return needWake;
}