This chapter will continue to explore the InputReader thread, which is responsible for obtaining events from the eventhub, converting them into EventEntry events, and adding them to the InputDispatcher's mInboundQueue.
threadLoop
After the InputReaderThread thread is started, a thredLoop method will be called. This method continuously obtains events from the eventhub and performs subsequent processing. The relevant code is located in frameworks/native/services/inputlinker/reader/inputreader cpp:
// Start InputReader and call loopOnce status_t InputReader::start() { if (mThread) { return ALREADY_EXISTS; } mThread = std::make_unique<InputThread>( "InputReader", [this]() { loopOnce(); }, [this]() { mEventHub->wake(); }); return OK; } void InputReader::loopOnce() { ... // Get events from the eventhub (EVENT_BUFFER_SIZE = 256) size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE); { AutoMutex _l(mLock); mReaderIsAliveCondition.broadcast(); if (count) { // Handling events processEventsLocked(mEventBuffer, count); } ... // If the input device is changed, the current input device is retrieved if (oldGeneration != mGeneration) { inputDevicesChanged = true; getInputDevicesLocked(inputDevices); } } // release lock // Send notification of input device changes if (inputDevicesChanged) { mPolicy->notifyInputDevicesChanged(inputDevices); } // Send events to nputDispatcher mQueuedListener->flush(); }
In the above code, there are three key nodes to focus on: meventhub->getevents, processeventslocked, and mqueedlistener->flush. The following will focus on these methods.
Meventhub->getevents [get events]
The getEvents method is mainly responsible for obtaining the event of the kernel. Here, the event includes not only input, but also add/remove and other related events of the input device.
When there is no event in the input device, it will block the epoll in the EventHub. When an event occurs, the epoll_wait will return, and then handle the changed event. The relevant codes are located in frameworks/native/services/inputlinker/reader/EventHub cpp:
size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) { ... for (;;) { nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); // Scanning equipment if (mNeedToScanDevices) { mNeedToScanDevices = false; scanDevicesLocked(); mNeedToSendFinishedDeviceScan = true; } while (mOpeningDevices != NULL) { Device* device = mOpeningDevices; ALOGV("Reporting device opened: id=%d, name=%s\n", device->id, device->path.string()); mOpeningDevices = device->next; event->when = now; event->deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id; // Add device event event->type = DEVICE_ADDED; event += 1; } ... Device* device = mDevices.valueAt(deviceIndex); if (eventItem.events & EPOLLIN) { // Read events from the device and put them into the readBuffer int32_t readSize = read(device->fd, readBuffer, sizeof(struct input_event) * capacity); 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++) { // Read events struct input_event& iev = readBuffer[i]; // Set input_event information is encapsulated into RawEvent event->when = processEventTimestamp(iev); event->readTime = systemTime(SYSTEM_TIME_MONOTONIC); event->deviceId = deviceId; event->type = iev.type; event->code = iev.code; event->value = iev.value; event += 1; capacity -= 1; } } ... } mLock.unlock(); // release lock before poll, must be before release_wake_lock release_wake_lock(WAKE_LOCK_ID); //Release the lock before poll and wait for the input event int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis); acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID); } else { // Some events occurred. mPendingEventCount = size_t(pollResult); } } // All done, return the number of events we read. return event - buffer; }
The EventHub uses the INotify + epoll mechanism to listen to the device nodes under the directory /dev/input. The input_event structure + deviceId is converted to RawEvent structure. The declaration of RawEvent structure is located in frameworks/native/services/inputlinker/reader/include/EventHub h. Its structure is as follows:
RawEvent mEventBuffer[EVENT_BUFFER_SIZE]; struct RawEvent { // Time when the event happened nsecs_t when; // Time when the event was read by EventHub. Only populated for input events. // For other events (device added/removed/etc), this value is undefined and should not be read. nsecs_t readTime; int32_t deviceId; int32_t type; int32_t code; int32_t value; }; struct input_event { struct timeval time; //Time point of the event __u16 type; __u16 code; __s32 value; };
processEventsLocked [process event]
The processEventsLocked method is responsible for adding, removing, and deleting devices, as well as processing events. The relevant codes are located in frameworks/av/media/libstrming/input/key_injector.cpp:
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) { // Handling events int32_t deviceId = rawEvent->deviceId; while (batchSize < count) { if (rawEvent[batchSize].type >= EventHubInterface::FIRST_SYNTHETIC_EVENT || rawEvent[batchSize].deviceId != deviceId) { break; } batchSize += 1; } processEventsForDeviceLocked(deviceId, rawEvent, batchSize); } else { switch (rawEvent->type) { // Add device case EventHubInterface::DEVICE_ADDED: addDeviceLocked(rawEvent->when, rawEvent->deviceId); break; // Remove device case EventHubInterface::DEVICE_REMOVED: removeDeviceLocked(rawEvent->when, rawEvent->deviceId); break; // Device scan case EventHubInterface::FINISHED_DEVICE_SCAN: handleConfigurationChangedLocked(rawEvent->when); break; default: ALOG_ASSERT(false); // can't happen break; } } count -= batchSize; rawEvent += batchSize; } }
processEventsForDeviceLocked
The processeventsfordevice locked method is used to process input device events. More specifically, it verifies the relevant information of input events. This method is located in frameworks/native/services/inputlinker/reader/inputreader cpp:
void InputReader::processEventsForDeviceLocked(int32_t eventHubId, const RawEvent* rawEvents, size_t count) { // Use eventhubbid to find out which device sent the event auto deviceIt = mDevices.find(eventHubId); if (deviceIt == mDevices.end()) { ALOGW("Discarding event for unknown eventHubId %d.", eventHubId); return; } std::shared_ptr<InputDevice>& device = deviceIt->second; if (device->isIgnored()) { // ALOGD("Discarding event for ignored deviceId %d.", deviceId); return; } device->process(rawEvents, count); }
InputDevice::process
The InputDevice::process method is responsible for mapping input events and processing all events in device order, because there may be dependencies between each device processing. The relevant codes are located in frameworks/native/services/inputlinker/reader/inputdevice cpp:
void InputDevice::process(const RawEvent* rawEvents, size_t count) { for (const RawEvent* rawEvent = rawEvents; count != 0; rawEvent++) { if (mDropUntilNextSync) { if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) { // Handle incident escalation mDropUntilNextSync = false; } else { ... } } else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_DROPPED) { // Processing event cancellation ALOGI("Detected input event buffer overrun for device %s.", getName().c_str()); mDropUntilNextSync = true; reset(rawEvent->when); } else { // Relevant processing according to event type for_each_mapper_in_subdevice(rawEvent->deviceId, [rawEvent](InputMapper& mapper) { mapper.process(rawEvent); }); } --count; } }
KeyboardInputMapper::process
As mentioned above, the InputDevice::process method uses different processing methods to process input events, including but not limited to touch events, keyboard events, sensor events, etc. to sum up, the following processing methods are available
class SwitchInputMapper : public InputMapper { class VibratorInputMapper : public InputMapper { class KeyboardInputMapper : public InputMapper { class CursorInputMapper : public InputMapper { class RotaryEncoderInputMapper : public InputMapper { class TouchInputMapper : public InputMapper { class ExternalStylusInputMapper : public InputMapper { class JoystickInputMapper : public InputMapper {
Among them, the keyboard event processing is the simplest and easiest to analyze, and the touch event is the most complex. Therefore, the keyboard event is taken as an example for analysis. The relevant code is located in frameworks/native/services/inputlinker/reader/mapper/keyboardinputmapper cpp:
// Keyboard event handling void KeyboardInputMapper::process(const RawEvent* rawEvent) { switch (rawEvent->type) { case EV_KEY: { // Handling key events int32_t scanCode = rawEvent->code; int32_t usageCode = mCurrentHidUsage; mCurrentHidUsage = 0; if (isKeyboardOrGamepadKey(scanCode)) { processKey(rawEvent->when, rawEvent->readTime, rawEvent->value != 0, scanCode, usageCode); } break; } case EV_MSC: { // Handle events that cannot be classified into other categories if (rawEvent->code == MSC_SCAN) { mCurrentHidUsage = rawEvent->value; } break; } case EV_SYN: { // Escalation events if (rawEvent->code == SYN_REPORT) { mCurrentHidUsage = 0; } } } }
KeyboardInputMapper::processKey
The KeyboardInputMapper::processKey method is used to handle key related events. The related codes are located in frameworks/native/services/inputlinker/reader/mapper/keyboardinputmapper cpp:
void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t scanCode, int32_t usageCode) { int32_t keyCode; int32_t keyMetaState; uint32_t policyFlags; // Convert event scancode to keycode if (getEventHub()->mapKey(getDeviceId(), scanCode, usageCode, mMetaState, &keyCode, &keyMetaState, &policyFlags)) { keyCode = AKEYCODE_UNKNOWN; keyMetaState = mMetaState; policyFlags = 0; } if (down) { ... mDownTime = when; } else { ... } // Create NotifyKeyArgs object, when record eventTime, downTime record pressing time NotifyKeyArgs args(when, getDeviceId(), mSource, policyFlags, down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP, AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, keyMetaState, downTime); // Send key event getListener()->notifyKey(&args); }
EventHub::mapKey
EventHub::mapKey is responsible for converting the event scancode into keycode. The relevant codes are located in frameworks/native/services/inputlinker/reader/eventhub cpp:
status_t EventHub::mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, int32_t metaState, int32_t* outKeycode, int32_t* outMetaState, uint32_t* outFlags) const { std::scoped_lock _l(mLock); Device* device = getDeviceLocked(deviceId); status_t status = NAME_NOT_FOUND; if (device != nullptr) { // Check the key character map first. const std::shared_ptr<KeyCharacterMap> kcm = device->getKeyCharacterMap(); if (kcm) { if (!kcm->mapKey(scanCode, usageCode, outKeycode)) { *outFlags = 0; status = NO_ERROR; } } // Check the key layout next. if (status != NO_ERROR && device->keyMap.haveKeyLayout()) { if (!device->keyMap.keyLayoutMap->mapKey(scanCode, usageCode, outKeycode, outFlags)) { status = NO_ERROR; } } if (status == NO_ERROR) { if (kcm) { kcm->tryRemapKey(*outKeycode, metaState, outKeycode, outMetaState); } else { *outMetaState = metaState; } } } if (status != NO_ERROR) { *outKeycode = 0; *outFlags = 0; *outMetaState = metaState; } return status; }
end of document
If you want to be an architect, you should not be limited to coding and business. You should be able to select, expand and improve your programming thinking. In addition, good career planning is also very important. The habit of learning is very important, but the most important thing is to persevere. Any plan that cannot be implemented is empty talk.
If you have no direction, here is a set of advanced notes on the eight Android modules prepared by Ali senior architects to help you systematize the messy, scattered and fragmented knowledge, so that you can systematically and efficiently master all the knowledge points of Android development.
Compared with the fragmented content we usually read, the knowledge points of this note are more systematic, easier to understand and remember, and are arranged strictly according to the knowledge system.
1, Necessary skills for architects to build foundations
1. Deep understanding of Java generics
2. Notes in simple terms
3. Concurrent programming
4. Data transmission and serialization
5. Principles of Java virtual machine
6. High efficiency IO
......
2, Source code analysis of top 100 Android frameworks
1.retro 2.0 source code analysis
2.Okhttp3 source code analysis
3.ButterKnife source code analysis
4.mpadroidchart source code analysis
5.Glide source code analysis
6.Leakcanary source code analysis
7. Universal lmage loader source code analysis
8.EventBus 3.0 source code analysis
9.zxing source code analysis
10.Picasso source code analysis
11.LottieAndroid usage details and source code analysis
12.Fresco source code analysis - picture loading process
3, Practical analysis of Android performance optimization
- Tencent Bugly: some understanding of string matching algorithm
- Iqiyi: Android APP crash capture scheme - xCrash
- Byte skipping: deeply understand one of the Gradle frameworks: Plugin, Extension, buildSrc
- Baidu APP Technology: Android H5 first screen Optimization Practice
- Alipay client architecture analysis: Android client startup speed optimization "garbage collection"
- Ctrip: component architecture practice from the perspective of Zhixing Android project
- Netease News Construction Optimization: how to make your construction speed "like lightning"?
- ...
4, Advanced kotlin enhanced combat
1. Getting started with Kotlin
2. Kotlin practical pit avoidance Guide
3. Project practice "Kotlin Jetpack practice"
-
Start with a Demo of worshiping the great God
-
What was Kotlin's experience writing Gradle scripts?
-
Three realms of Kotlin programming
-
Kotlin higher order function
-
Kotlin generics
-
Kotlin extension
-
Entrusted by Kotlin
-
Debugging skills of "unknown" coordination process
-
Graphic collaboration: suspend
5, Advanced decryption of Android advanced UI open source framework
1. Use of smartrefreshlayout
2.Android PullToRefresh control source code analysis
3. Basic usage of Android pulltorefresh pull-down refresh Library
4.LoadSir- efficient and easy-to-use loading feedback page management framework
5. Detailed explanation of Android general LoadingView loading framework
6.mpadroidchart implements LineChart (line chart)
7. Hellocharts Android User Guide
8.SmartTable User Guide
9. introduction to the open source project Android uitableview
10.ExcelPanel User Guide
11. Deep analysis of Android open source project SlidingMenu
12.MaterialDrawer User Guide
6, NDK module development
1. NDK module development
2. JNI module
3. Native development tools
4. Linux Programming
5. Bottom picture processing
6. Audio and video development
7. Machine learning
7, Advanced shuttle Technology
1. Overview of Flutter cross platform development
2. Setup of the fluent development environment in Windows
3. Write your first shuttle app
4. Setup and debugging of Flutter development environment
5. Basic grammar of Dart Grammar (1)
6. The use and source code analysis of the collection of Dart Grammar (2)
7. Set operator functions and source code analysis in Dart Grammar (3)
...
8, Wechat applet development
1. Applet overview and introduction
2. Applet UI development
3. API operation
4. Shopping mall project practice
Full set of video materials:
1, Interview collection
2, Source code analysis collection
3, Open source framework collection
You are welcome to support three links with one button. If you need the information in the text, you can directly click on the official certified wechat card of CSDN at the end of the text to receive [guarantee 100% free] ↓↓