Android4的InputReader
上次分析到
通过new一个InputManager来添加进去接下来我们看下InputManager
首先我们看下InputReader
,他其实就是创建一个inputReader
这里有个问题,我们只分析了创建的流程,没有分析启动的,到这里走不下去了
在之前添加服务后他还执行了一个方法
他执行了
,通过jni调用到
最后启动了
接下来我们就可以继续了这里启动了radaer和dispatcher
这里执行了loopOnce来等待唤醒处理
void InputReader::loopOnce() {int32_t oldGeneration;int32_t timeoutMillis;// Copy some state so that we can access it outside the lock later.bool inputDevicesChanged = false;std::vector<InputDeviceInfo> inputDevices;std::list<NotifyArgs> notifyArgs;{ // acquire lockstd::scoped_lock _l(mLock);oldGeneration = mGeneration;timeoutMillis = -1;auto changes = mConfigurationChangesToRefresh;if (changes.any()) {mConfigurationChangesToRefresh.clear();timeoutMillis = 0;refreshConfigurationLocked(changes);} else if (mNextTimeout != LLONG_MAX) {nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);timeoutMillis = toMillisecondTimeoutDelay(now, mNextTimeout);}} // release lockstd::vector<RawEvent> events = mEventHub->getEvents(timeoutMillis);{ // acquire lockstd::scoped_lock _l(mLock);mReaderIsAliveCondition.notify_all();if (!events.empty()) {notifyArgs += processEventsLocked(events.data(), events.size());}if (mNextTimeout != LLONG_MAX) {nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);if (now >= mNextTimeout) {if (debugRawEvents()) {ALOGD("Timeout expired, latency=%0.3fms", (now - mNextTimeout) * 0.000001f);}mNextTimeout = LLONG_MAX;notifyArgs += timeoutExpiredLocked(now);}}if (oldGeneration != mGeneration) {inputDevicesChanged = true;inputDevices = getInputDevicesLocked();notifyArgs.emplace_back(NotifyInputDevicesChangedArgs{mContext.getNextId(), inputDevices});}} // release lock// Send out a message that the describes the changed input devices.if (inputDevicesChanged) {mPolicy->notifyInputDevicesChanged(inputDevices);}// Notify the policy of the start of every new stylus gesture outside the lock.for (const auto& args : notifyArgs) {const auto* motionArgs = std::get_if<NotifyMotionArgs>(&args);if (motionArgs != nullptr && isStylusPointerGestureStart(*motionArgs)) {mPolicy->notifyStylusGestureStarted(motionArgs->deviceId, motionArgs->eventTime);}}notifyAll(std::move(notifyArgs));// 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.mQueuedListener.flush();
}
首先执行了std::vector<RawEvent> events = mEventHub->getEvents(timeoutMillis);
我们看下这个方法
std::vector<RawEvent> EventHub::getEvents(int timeoutMillis) {std::scoped_lock _l(mLock);std::array<input_event, EVENT_BUFFER_SIZE> readBuffer;std::vector<RawEvent> events;bool awoken = false;for (;;) {nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);// Reopen input devices if needed.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.for (auto it = mClosingDevices.begin(); it != mClosingDevices.end();) {std::unique_ptr<Device> device = std::move(*it);ALOGV("Reporting device closed: id=%d, name=%s\n", device->id, device->path.c_str());const int32_t deviceId = (device->id == mBuiltInKeyboardId)? ReservedInputDeviceId::BUILT_IN_KEYBOARD_ID: device->id;events.push_back({.when = now,.deviceId = deviceId,.type = DEVICE_REMOVED,});it = mClosingDevices.erase(it);mNeedToSendFinishedDeviceScan = true;if (events.size() == EVENT_BUFFER_SIZE) {break;}}if (mNeedToScanDevices) {mNeedToScanDevices = false;scanDevicesLocked();mNeedToSendFinishedDeviceScan = true;}while (!mOpeningDevices.empty()) {std::unique_ptr<Device> device = std::move(*mOpeningDevices.rbegin());mOpeningDevices.pop_back();ALOGV("Reporting device opened: id=%d, name=%s\n", device->id, device->path.c_str());const int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;events.push_back({.when = now,.deviceId = deviceId,.type = DEVICE_ADDED,});// Try to find a matching video device by comparing device namesfor (auto it = mUnattachedVideoDevices.begin(); it != mUnattachedVideoDevices.end();it++) {std::unique_ptr<TouchVideoDevice>& videoDevice = *it;if (tryAddVideoDeviceLocked(*device, videoDevice)) {// videoDevice was transferred to 'device'it = mUnattachedVideoDevices.erase(it);break;}}auto [dev_it, inserted] = mDevices.insert_or_assign(device->id, std::move(device));if (!inserted) {ALOGW("Device id %d exists, replaced.", device->id);}mNeedToSendFinishedDeviceScan = true;if (events.size() == EVENT_BUFFER_SIZE) {break;}}if (mNeedToSendFinishedDeviceScan) {mNeedToSendFinishedDeviceScan = false;events.push_back({.when = now,.type = FINISHED_DEVICE_SCAN,});if (events.size() == EVENT_BUFFER_SIZE) {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 wakeReadBuffer[16];ssize_t nRead;do {nRead = read(mWakeReadPipeFd, wakeReadBuffer, sizeof(wakeReadBuffer));} while ((nRead == -1 && errno == EINTR) || nRead == sizeof(wakeReadBuffer));} else {ALOGW("Received unexpected epoll event 0x%08x for wake read pipe.",eventItem.events);}continue;}Device* device = getDeviceByFdLocked(eventItem.data.fd);if (device == nullptr) {ALOGE("Received unexpected epoll event 0x%08x for unknown fd %d.", eventItem.events,eventItem.data.fd);ALOG_ASSERT(!DEBUG);continue;}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 EPOLLRDHUPALOGI("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 eventif (eventItem.events & EPOLLIN) {int32_t readSize =read(device->fd, readBuffer.data(),sizeof(decltype(readBuffer)::value_type) * readBuffer.size());if (readSize == 0 || (readSize < 0 && errno == ENODEV)) {// Device was removed before INotify noticed.ALOGW("could not get event, removed? (fd: %d size: %" PRId32" capacity: %zu errno: %d)\n",device->fd, readSize, readBuffer.size(), 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 {const int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;const size_t count = size_t(readSize) / sizeof(struct input_event);for (size_t i = 0; i < count; i++) {struct input_event& iev = readBuffer[i];events.push_back({.when = processEventTimestamp(iev),.readTime = systemTime(SYSTEM_TIME_MONOTONIC),.deviceId = deviceId,.type = iev.type,.code = iev.code,.value = iev.value,});}if (events.size() >= EVENT_BUFFER_SIZE) {// 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.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.if (mPendingINotify && mPendingEventIndex >= mPendingEventCount) {mPendingINotify = false;const auto res = readNotifyLocked();if (!res.ok()) {ALOGW("Failed to read from inotify: %s", res.error().message().c_str());}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 (!events.empty() || awoken) {break;}// Poll for events.// When a device driver has pending (unread) events, it acquires// a kernel wake lock. Once the last pending event has been read, the device// driver will release the kernel wake lock, but the epoll will hold the wakelock,// since we are using EPOLLWAKEUP. The wakelock is released by the epoll when epoll_wait// is called again for the same fd that produced the event.// 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.mPendingEventIndex = 0;mLock.unlock(); // release lock before pollint pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis);mLock.lock(); // reacquire lock after pollif (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.mPendingEventCount = size_t(pollResult);}}// All done, return the number of events we read.return events;
}
之后得到events后执行
之后执行了
std::list<NotifyArgs> InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {std::list<NotifyArgs> out;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 (debugRawEvents()) {ALOGD("BatchSize: %zu Count: %zu", batchSize, count);}out += 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 happenbreak;}}count -= batchSize;rawEvent += batchSize;}return out;
}
之后执行了
std::list<NotifyArgs> InputDevice::process(const RawEvent* rawEvents, size_t count) {// Process all of the events in order for each mapper.// 按照顺序处理每个 mapper 的所有事件。// We cannot simply ask each mapper to process them in bulk because mappers may// 我们不能简单地要求每个 mapper 批量处理它们,因为 mapper 可能// 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// 游戏手柄按钮按下由不同的 mapper 处理,但它们应该按接收的顺序进行调度。// This is the reason for the loop, processing raw events one-by-one.// 这就是循环的原因,逐个处理原始事件。std::list<NotifyArgs> out; // 用于存储所有 mapper 处理事件后产生的 NotifyArgs 的列表。// 遍历原始事件数组。for (const RawEvent* rawEvent = rawEvents; count != 0; rawEvent++) {// 如果开启了原始事件调试日志,则打印事件信息。if (debugRawEvents()) {// 从 InputEventLookup 获取事件类型、代码和值的标签字符串,用于日志输出。const auto [type, code, value] =InputEventLookup::getLinuxEvdevLabel(rawEvent->type, rawEvent->code,rawEvent->value);// 使用 ALOGD 打印调试信息,包括设备 ID、事件类型、代码、值和时间戳。ALOGD("Input event: eventHubDevice=%d type=%s code=%s value=%s when=%" PRId64,rawEvent->deviceId, type.c_str(), code.c_str(), value.c_str(), rawEvent->when);}// 处理输入事件缓冲区溢出的情况。if (mDropUntilNextSync) {// 如果当前正在丢弃事件,直到遇到下一个同步事件。if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {// 如果当前事件是同步报告事件,则停止丢弃事件。mDropUntilNextSync = false;ALOGD_IF(debugRawEvents(), "Recovered from input event buffer overrun.");} else {// 如果当前事件不是同步报告事件,则继续丢弃。ALOGD_IF(debugRawEvents(),"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().c_str());// 设置 mDropUntilNextSync 标志,开始丢弃事件,直到遇到下一个同步报告事件。mDropUntilNextSync = true;// 重置 InputDevice 的状态,并获取需要通知的事件列表。out += reset(rawEvent->when);} else {// 如果没有发生缓冲区溢出,则将事件传递给对应的 InputMapper 进行处理。// 遍历所有与当前子设备关联的 InputMapper。for_each_mapper_in_subdevice(rawEvent->deviceId, [&](InputMapper& mapper) {// 调用 InputMapper 的 process 方法处理事件,并将返回的 NotifyArgs 添加到 out 列表中。out += mapper.process(rawEvent);});}--count; // 减少剩余事件计数器。}return out; // 返回所有 InputMapper 处理事件后产生的 NotifyArgs 列表。
}