Android 12系统源码_输入系统(三)输入事件的加工和分发

news/2024/12/22 12:12:37/

前言

上一篇文章我们具体分析了InputManagerService的构造方法和start方法,知道IMS的start方法经过层层调用,最终会触发Navite层InputDispatcher的start方法和InputReader的start方法。InputDispatcher的start方法会启动一个名为InputDispatcher的线程,该线程会循环调用自己的dispatchOnce方法;InputReader的start方法会启动一个名为InputReader的线程,该线程会循环调用自己的loopOnce方法;并绘制了一个简单的IMS架构图。
在这里插入图片描述
本篇文章我们将在此基础上,继续结合Navite层的InputDispatcher和InputReader的源码,来分析Android系统是如何对输入事件进行加工和分发的。

一、输入事件的加工

1.1 InputReader的start方法

>frameworks/>native/services/inputflinger/reader/InputReader.cpp
status_t InputReader::start() {if (mThread) {return ALREADY_EXISTS;}//开启InputThread线程,并循环调用loopOnce方法。mThread = std::make_unique<InputThread>("InputReader", [this]() { loopOnce(); }, [this]() { mEventHub->wake(); });return OK;
}void InputReader::loopOnce() {...代码省略...//从事件缓冲区中获取设备节点的事件信息并将其存放到mEventBuffer中size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);...代码省略...if (count) {//如果有事件,则调用processEventsLocked方法处理这些事件。processEventsLocked(mEventBuffer, count);}...代码省略...
}

InputReader的start方法会开启一个名为InputThread的线程,该线程会循环调用loopOnce方法,该方法先是从事件缓冲区中获取设备节点的事件信息并将其存放到mEventBuffer中,如果有事件,则调用processEventsLocked方法处理这些事件。

1.2 InputReader的processEventsLocked方法

>frameworks/>native/services/inputflinger/reader/InputReader.cppvoid InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {//注释1,遍历所有事件for (const RawEvent* rawEvent = rawEvents; count;) {int32_t type = rawEvent->type;size_t batchSize = 1;//注释2,事件类型分为原始输入事件和设备事件,这个条件语句对原始输入事件进行处理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;}//处理deviceId所对应设备的原始输入事件processEventsForDeviceLocked(deviceId, rawEvent, batchSize);} else {//注释3,对设备事件进行处理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;}

在注释1处会对传递进来的所有事件进行遍历。在注释2处会判断事件是输入事件还是设备事件,如果是输入事件,会调用processEventsForDeviceLocked方法。在注释3处判断如果是事件是设备事件,则会进一步判断设备事件的具体类型,针对不同的事件类型进行不同的操作,如果是设备新增,则调用addDeviceLocked方法,如果是设备移除,则调用removeDeviceLocked,如果配置变化,则调用handleConfigurationChangedLocked方法。

1.2.1 InputReader的processEventsForDeviceLocked方法

>frameworks/>native/services/inputflinger/reader/InputReader.cpp
//处理同一个设备的输入事件
void InputReader::processEventsForDeviceLocked(int32_t eventHubId, const RawEvent* rawEvents,size_t count) {//注释1,通过设备id获取设备对象                                           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;}//注释,2,调用InputDevices的process方法device->process(rawEvents, count);
}>frameworks/native/services/inputflinger/reader/InputDevice.cpp
void InputDevice::process(const RawEvent* rawEvents, size_t count) {//遍历输入事件for (const RawEvent* rawEvent = rawEvents; count != 0; rawEvent++) {...代码省略...//C++ Lambda 表达式,遍历与输入事件对应的设备ID关联的所有映射器,并调用每个映射器的process方法处理事件。for_each_mapper_in_subdevice(rawEvent->deviceId, [rawEvent](InputMapper& mapper) {//调用InputMapper的process方法mapper.process(rawEvent);});...代码省略...--count;}
}>frameworks/native/services/inputflinger/reader/include/InputDevice.h
inline void for_each_mapper_in_subdevice(int32_t eventHubDevice,std::function<void(InputMapper&)> f) {auto deviceIt = mDevices.find(eventHubDevice);//获取设备对象if (deviceIt != mDevices.end()) {auto& devicePair = deviceIt->second;auto& mappers = devicePair.second;for (auto& mapperPtr : mappers) {//获取设备对象的InputMapper集合,循环执行其方法,其实就是process方法f(*mapperPtr);}}
}
}

在注释1处通过deviceId获取输入设备在mDevices中实例对象,然后调用InputDevice实例对象的process方法,process方法会遍历所有输入事件,获取每个输入事件对应的设备ID关联的所有InputMapper映射器,并调用这些映射器的process方法处理事件。那么这些映射器是在什么地方被初始化的呢?

1.2.2 InputReader的addDeviceLocked方法

重新回到前面InputReader的processEventsLocked方法中,当一个输入事件类型为设备事件类型,且该设备事件类型为设备新增类型的时候,会调用addDeviceLocked方法来处理。

>frameworks/>native/services/inputflinger/reader/InputReader.cpp
void InputReader::addDeviceLocked(nsecs_t when, int32_t eventHubId) {if (mDevices.find(eventHubId) != mDevices.end()) {ALOGW("Ignoring spurious device added event for eventHubId %d.", eventHubId);return;}InputDeviceIdentifier identifier = mEventHub->getDeviceIdentifier(eventHubId);//注释1,调用createDeviceLocked方法创建InputDevice对象std::shared_ptr<InputDevice> device = createDeviceLocked(eventHubId, identifier);...代码省略...//注释2,将新创建的device对象添加到事件节点设备对象集合中mDevices.emplace(eventHubId, device);...代码省略...
}std::shared_ptr<InputDevice> InputReader::createDeviceLocked(int32_t eventHubId, const InputDeviceIdentifier& identifier) {auto deviceIt = std::find_if(mDevices.begin(), mDevices.end(), [identifier](auto& devicePair) {const InputDeviceIdentifier identifier2 =devicePair.second->getDeviceInfo().getIdentifier();return isSubDevice(identifier, identifier2);});std::shared_ptr<InputDevice> device;if (deviceIt != mDevices.end()) {device = deviceIt->second;} else {int32_t deviceId = (eventHubId < END_RESERVED_ID) ? eventHubId : nextInputDeviceIdLocked();//创建输入设备对象device = std::make_shared<InputDevice>(&mContext, deviceId, bumpGenerationLocked(),identifier);}//注释3,调用InputDevice的addEventHubDevice方法,将输入事件添加到输入设备对象中device->addEventHubDevice(eventHubId);return device;
}

在注释1处调用createDeviceLocked方法创建InputDevice对象。在注释2处将新创建的device对象添加到事件节点设备对象集合中。在注释3处,也就是createDeviceLocked方法中,调用InputDevice的addEventHubDevice方法,将输入事件添加到输入设备对象中。

1.3 InputDevice的addEventHubDevice方法

>frameworks/native/services/inputflinger/reader/include/InputDevice.h
class InputDevice {
private:using MapperVector = std::vector<std::unique_ptr<InputMapper>>;using DevicePair = std::pair<std::unique_ptr<InputDeviceContext>, MapperVector>;哈希映射表,里面存放了和eventHubId 关联的设备上下文和映射器列表std::unordered_map<int32_t, DevicePair> mDevices;
}
>frameworks/native/services/inputflinger/reader/InputDevice.cpp
void InputDevice::addEventHubDevice(int32_t eventHubId, bool populateMappers) {//注释1,检查是否已存在指定的设备if (mDevices.find(eventHubId) != mDevices.end()) {return;}//创建新的设备上下文std::unique_ptr<InputDeviceContext> contextPtr(new InputDeviceContext(*this, eventHubId));//获取设备类别Flags<InputDeviceClass> classes = contextPtr->getDeviceClasses();//创建输入事件映射器列表std::vector<std::unique_ptr<InputMapper>> mappers;if (!populateMappers) {mDevices.insert({eventHubId, std::make_pair(std::move(contextPtr), std::move(mappers))});return;}//注释2,根据设备类别创建相关的输入映射器//开关设备if (classes.test(InputDeviceClass::SWITCH)) {mappers.push_back(std::make_unique<SwitchInputMapper>(*contextPtr));}//旋转编码器设备if (classes.test(InputDeviceClass::ROTARY_ENCODER)) {mappers.push_back(std::make_unique<RotaryEncoderInputMapper>(*contextPtr));}//振动设备if (classes.test(InputDeviceClass::VIBRATOR)) {mappers.push_back(std::make_unique<VibratorInputMapper>(*contextPtr));}//电池或光源设备if (classes.test(InputDeviceClass::BATTERY) || classes.test(InputDeviceClass::LIGHT)) {mController = std::make_unique<PeripheralController>(*contextPtr);}//键盘和游戏控制器uint32_t keyboardSource = 0;int32_t keyboardType = AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC;if (classes.test(InputDeviceClass::KEYBOARD)) {keyboardSource |= AINPUT_SOURCE_KEYBOARD;}if (classes.test(InputDeviceClass::ALPHAKEY)) {keyboardType = AINPUT_KEYBOARD_TYPE_ALPHABETIC;}if (classes.test(InputDeviceClass::DPAD)) {keyboardSource |= AINPUT_SOURCE_DPAD;}if (classes.test(InputDeviceClass::GAMEPAD)) {keyboardSource |= AINPUT_SOURCE_GAMEPAD;}if (keyboardSource != 0) {mappers.push_back(std::make_unique<KeyboardInputMapper>(*contextPtr, keyboardSource, keyboardType));}//光标设备if (classes.test(InputDeviceClass::CURSOR)) {mappers.push_back(std::make_unique<CursorInputMapper>(*contextPtr));}//触摸屏和触摸板设备if (classes.test(InputDeviceClass::TOUCH_MT)) {mappers.push_back(std::make_unique<MultiTouchInputMapper>(*contextPtr));} else if (classes.test(InputDeviceClass::TOUCH)) {mappers.push_back(std::make_unique<SingleTouchInputMapper>(*contextPtr));}//操纵杆设备if (classes.test(InputDeviceClass::JOYSTICK)) {mappers.push_back(std::make_unique<JoystickInputMapper>(*contextPtr));}//运动传感器设备if (classes.test(InputDeviceClass::SENSOR)) {mappers.push_back(std::make_unique<SensorInputMapper>(*contextPtr));}//外部手写笔设备if (classes.test(InputDeviceClass::EXTERNAL_STYLUS)) {mappers.push_back(std::make_unique<ExternalStylusInputMapper>(*contextPtr));}//注释3,将设备上下文和事件映射器插入到哈希映射表中mDevices.insert({eventHubId, std::make_pair(std::move(contextPtr), std::move(mappers))});//更新设备生成代号bumpGeneration();
}

在注释1处检查是否已存在指定的设备,如果存在直接返回,如果设备不存在,则创建新的设备上下文和相关的事件映射器列表。
在注释2处会根据设备类别创建相关的输入映射器,比如开关设备(SwitchInputMapper)、旋转编码器设备(RotaryEncoderInputMapper)、振动设备(VibratorInputMapper)、电池或光源设备(PeripheralController)、键盘设备(KeyboardInputMapper)、光标设备(CursorInputMapper)、触摸屏(MultiTouchInputMapper)和触摸板设备(SingleTouchInputMapper)、操纵杆设备(JoystickInputMapper)、运动传感器设备(SensorInputMapper)、外部手写笔设备(ExternalStylusInputMapper)。在注释3处将前面创建的设备上下文和事件映射器添加到哈希映射表mDevices中,方便后续查找,最后调用bumpGeneration方法更新设备生成代号。

1.4 InputMapper处理输入事件

重新回到前面InputReader的processEventsLocked方法中,当一个事件类型为原始输入事件类型的时候,会调用InputReader的processEventsForDeviceLocked方法,然后调用InputDevice的process方法,该方法会遍历自己所有的事件映射器,将原始输入事件交给InputMapper的process方法来出来,至于到底是那个InputMapper来处理,InputReader并不关心。

1.4.1 KeyboardInputMapper的process方法

这里我们结合处理键盘输入事件的KeyboardInputMapper这个映射器的process方法来作进一步分析。

>frameworks/native/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
//处理了键盘输入事件
void KeyboardInputMapper::process(const RawEvent* rawEvent) {switch (rawEvent->type) {case EV_KEY: {int32_t scanCode = rawEvent->code;int32_t usageCode = mCurrentHidUsage;mCurrentHidUsage = 0;if (isKeyboardOrGamepadKey(scanCode)) {//注释1,处理按键事件processKey(rawEvent->when, rawEvent->readTime, rawEvent->value != 0, scanCode,usageCode);}break;}...代码省略...}
}void KeyboardInputMapper::processKey(nsecs_t when, nsecs_t readTime, bool down, int32_t scanCode,int32_t usageCode) {...代码省略...//注释2,将原始事件封装成一个新的NotifyKeyArgs对象NotifyKeyArgs args(getContext()->getNextId(), when, readTime, getDeviceId(), mSource,getDisplayId(), policyFlags,down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, keyMetaState, downTime);//注释3,调用监听者的notifyKey方法,这里其实就是InputDispatcher对象getListener()->notifyKey(&args);
}

在注释1处调用processKey方法处理按键事件。在注释2处,也就是processKey方法内,将原始事件封装为一个新的NotifyKeyArgs对象。在注释3处,先是调用getListener方法获取监听者,然后调用监听者的notifyKey方法。这里获取的监听者最早是在InputReader的构造方法中初始化的。

1.4.2 InputReader初始化监听者

InputReader::InputReader(std::shared_ptr<EventHubInterface> eventHub,const sp<InputReaderPolicyInterface>& policy,const sp<InputListenerInterface>& listener): mContext(this),mEventHub(eventHub),mPolicy(policy),mGlobalMetaState(0),mLedMetaState(AMETA_NUM_LOCK_ON),mGeneration(1),mNextInputDeviceId(END_RESERVED_ID),mDisableVirtualKeysTimeout(LLONG_MIN),mNextTimeout(LLONG_MAX),mConfigurationChangesToRefresh(0) {mQueuedListener = new QueuedInputListener(listener);//初始化监听者{ // acquire lockstd::scoped_lock _l(mLock);refreshConfigurationLocked(0);updateGlobalMetaStateLocked();} // release lock
}InputListenerInterface* InputReader::ContextImpl::getListener() {return mReader->mQueuedListener.get();
}>frameworks/native/services/inputflinger/include/InputListener.h
class QueuedInputListener : public InputListenerInterface {
private:sp<InputListenerInterface> mInnerListener;//监听者std::vector<NotifyArgs*> mArgsQueue;
};
>frameworks/native/services/inputflinger/InputListener.cpp
QueuedInputListener::QueuedInputListener(const sp<InputListenerInterface>& innerListener) :mInnerListener(innerListener) {
}

而InputReader最早是在InputManager的构造方法中被创建的。

>frameworks/native/services/inputflinger/InputManager.cpp
InputManager::InputManager(const sp<InputReaderPolicyInterface>& readerPolicy,const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {//创建inputDispatcher对象mDispatcher = createInputDispatcher(dispatcherPolicy);mClassifier = new InputClassifier(mDispatcher);//注释1,创建InputReader对象,其内部持有mDispatcher的引用mReader = createInputReader(readerPolicy, mClassifier);
}>frameworks/native/services/inputflinger/reader/InputReaderFactory.cpp
sp<InputReaderInterface> createInputReader(const sp<InputReaderPolicyInterface>& policy,const sp<InputListenerInterface>& listener) {//创建InputReader对象return new InputReader(std::make_unique<EventHub>(), policy, listener);
}

在注释1处调用createInputReader方法,这里传入的第二个参数就是InputDispatcher,其内部会调用InputReader的构造方法。

1.4.3 KeyboardInputMapper的loopOnce方法

重新回到KeyboardInputMapper的processKey方法中。

>frameworks/native/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
//处理了键盘输入事件
void KeyboardInputMapper::processKey(nsecs_t when, nsecs_t readTime, bool down, int32_t scanCode,int32_t usageCode) {...代码省略...NotifyKeyArgs args(getContext()->getNextId(), when, readTime, getDeviceId(), mSource,getDisplayId(), policyFlags,down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, keyMetaState, downTime);//调用监听者的notifyKey方法getListener()->notifyKey(&args);
}

该方法的最后会调用监听者的notifyKey方法。

>frameworks/native/services/inputflinger/InputListener.cpp
void QueuedInputListener::notifyKey(const NotifyKeyArgs* args) {traceEvent(__func__, args->id);//将NotifyKeyArgs对象存储到mArgsQueue队列中mArgsQueue.push_back(new NotifyKeyArgs(*args));
}void QueuedInputListener::flush() {...对事件进行处理...
}

可以发现QueuedInputListener的notifyKey方法只是将NotifyKeyArgs事件对象存储到mArgsQueue队列中,并没有真正对事件进行处理,真正对事件进行处理是在flush方法中,而QueuedInputListener的flush方法是在InputReader的loopOnce方法中被调用的。关于loopOnce这个方法的具体分析请参考Android 12系统源码_输入系统(二)InputManagerService服务这篇文章.

>frameworks/>native/services/inputflinger/reader/InputReader.cpp
void InputReader::loopOnce() {...代码省略...mQueuedListener->flush();//刷新或处理排队的监听器事件。
}
void QueuedInputListener::flush() {size_t count = mArgsQueue.size();for (size_t i = 0; i < count; i++) {NotifyArgs* args = mArgsQueue[i];args->notify(mInnerListener);delete args;}mArgsQueue.clear();
}

QueuedInputListener的flush方法就是循环调用列表中的事件,并依次执行NotifyArgs的notify方法,传入的参数mInnerListener为初始化时的InputDispatcher对象。

1.4.4 NotifyArgs的notify方法

>frameworks/native/services/inputflinger/include/InputListener.h
struct NotifyArgs {virtual void notify(const sp<InputListenerInterface>& listener) const = 0;
};

notify方法是一个纯虚函数,由其子类实现。KeyboardInputMapper事件映射器对应的子类就是NotifyKeyArgs对象。

>struct NotifyKeyArgs : public NotifyArgs {virtual void notify(const sp<InputListenerInterface>& listener) const;
}>frameworks/native/services/inputflinger/InputListener.cpp
NotifyKeyArgs::NotifyKeyArgs(const NotifyKeyArgs& other): NotifyArgs(other.id, other.eventTime),deviceId(other.deviceId),source(other.source),displayId(other.displayId),policyFlags(other.policyFlags),action(other.action),flags(other.flags),keyCode(other.keyCode),scanCode(other.scanCode),metaState(other.metaState),downTime(other.downTime),readTime(other.readTime) {}void NotifyKeyArgs::notify(const sp<InputListenerInterface>& listener) const {listener->notifyKey(this);//注释1
}

在注释1处调用listener的notifyKey方法,这里的listener就是InputDispatcher的对象。

1.5 InputDispatcher的notifyKey方法

>frameworks/native/services/inputflinger/dispatcher/InputDispatcher.h
class InputDispatcher : public android::InputDispatcherInterface, public gui::WindowInfosListener {
private://这是一个双端队列,用于存储输入事件条目(EventEntry)//std::shared_ptr 表示使用智能指针来管理事件条目的生命周期。//GUARDED_BY(mLock)表明 mInboundQueue 由 mLock 进行保护,确保在多线程环境中对队列的访问是安全的。std::deque<std::shared_ptr<EventEntry>> mInboundQueue GUARDED_BY(mLock);
}
>frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp
void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {...代码省略...bool needWake;{ // acquire lockmLock.lock();...代码省略...//注释1std::unique_ptr<KeyEntry> newEntry =std::make_unique<KeyEntry>(args->id, args->eventTime, args->deviceId, args->source,args->displayId, policyFlags, args->action, flags,keyCode, args->scanCode, metaState, repeatCount,args->downTime);//注释2needWake = enqueueInboundEventLocked(std::move(newEntry));mLock.unlock();} // release lockif (needWake) {//注释3mLooper->wake();}
}bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {bool needWake = mInboundQueue.empty();//将newEntry对象压入mInboundQueue中mInboundQueue.push_back(std::move(newEntry));...代码省略...
}

由于进入了InputDispatcher的“势力范围”,在注释1处会将NotifyKeyArgs事件重新封装为KeyEntry对象。在注释2处调用enqueueInboundEventLocked方法,该方法内部会将KeyEntry对象压入mInboundQueue中。在注释3处唤醒InputDispatche对应的线程。

1.6 输入事件的加工流程小结

1.SystemServer创建并启动InputManagerService
2.InputManagerService在native层创建一个NativeInputManager对象
3.NativeInputManager内部创建一个InputManager对象
4.InputManager的start方法会启动InputReader线程和InputDispatcher线程
5.在InputReader线程中调用EventHub的getEvents获取设备节点中的输入事件
6.并将输入事件封装为NotifyKeyArgs对象放入队列中
7.之后再调用flush,依次将事件传递给InputDispatcher
8.InputDispatcher在收到事件后,会重新封装为一个KeyEntry对象,并压力压入mInboundQueue列表中
9.最后唤醒InputDispatcherThread线程

二、输入事件的分发

我们在Android 12系统源码_输入系统(二)InputManagerService服务中有具体分析过InputDispatcher的start方法。

>frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp
status_t InputDispatcher::start() {if (mThread) {return ALREADY_EXISTS;}//注释1,创建InputThread对象mThread = std::make_unique<InputThread>("InputDispatcher", [this]() { dispatchOnce(); }, [this]() { mLooper->wake(); });return OK;
}

start方法会创建InputThread对象,该对象内部会启动名为InputDispatcher的线程,该线程会循环调用dispatchOnce方法。

2.1 InputDispatcher的dispatchOnce方法

>frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp
void InputDispatcher::dispatchOnce() {nsecs_t nextWakeupTime = LONG_LONG_MAX;{ // acquire lockstd::scoped_lock _l(mLock);mDispatcherIsAlive.notify_all();//注释1,检测缓存队列中是否没有等待处理的指令if (!haveCommandsLocked()) {//调用dispatchOnceInnerLocked方法dispatchOnceInnerLocked(&nextWakeupTime);}//注释2,执行指令if (runCommandsLockedInterruptible()) {nextWakeupTime = LONG_LONG_MIN;}//检查ANRconst nsecs_t nextAnrCheck = processAnrsLocked();nextWakeupTime = std::min(nextWakeupTime, nextAnrCheck);//处理空闲状态if (nextWakeupTime == LONG_LONG_MAX) {mDispatcherEnteredIdle.notify_all();}} // release lock//计算InputDisPatcherThread需要休眠的最长时间nsecs_t currentTime = now();int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime);//让mLooper线程休眠,timeoutMillis是休眠的最长时间mLooper->pollOnce(timeoutMillis);
}

在注释1处判断如果缓存队列中没有等待处理的指令,则会调用dispatchOnceInnerLocked方法来处理输入事件。如果当前有等待处理的指令,则在注释2处优先处理该指令,并将线程休眠时间nextWakeupTime设置为LONG_LONG_MIN,这样线程在执行完指令之后可以立刻被唤醒去处理输入事件。从这里可以看出dispatchOnce主要是做了两个功能:1.执行指令 2.处理输入事件,且指令执行优先级高于输入事件处理。例如对waitQueue中的事件进行出栈就属于指令的一种,这个后面我们还会讲到。

2.2 InputDispatcher的dispatchOnceInnerLocked方法

>frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp
void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {nsecs_t currentTime = now();if (!mDispatchEnabled) {//重置按键重复计数器resetKeyRepeatLocked();}//注释1,如果InputDispatcher被冻结,则不进行派发操作直接返回if (mDispatchFrozen) {if (DEBUG_FOCUS) {ALOGD("Dispatch frozen.  Waiting some more.");}return;}//注释2,如果isAppSwitchDue为true,则说明没有及时响应Home键操作bool isAppSwitchDue = mAppSwitchDueTime <= currentTime;if (mAppSwitchDueTime < *nextWakeupTime) {*nextWakeupTime = mAppSwitchDueTime;}if (!mPendingEvent) {//如果mInboundQueue为空,并且没有待分发的事件,直接返回if (mInboundQueue.empty()) {...代码省略...if (!mPendingEvent) {return;}} else {//注释3,将输入事件队列mInboundQueue最前端条目取出赋值给mPendingEventmPendingEvent = mInboundQueue.front();mInboundQueue.pop_front();traceInboundQueueLengthLocked();}// Poke user activity for this event.if (mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER) {pokeUserActivityLocked(*mPendingEvent);}}ALOG_ASSERT(mPendingEvent != nullptr);bool done = false;//事件丢失的原因,默认为不丢失DropReason dropReason = DropReason::NOT_DROPPED;if (!(mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER)) {dropReason = DropReason::POLICY;} else if (!mDispatchEnabled) {dropReason = DropReason::DISABLED;}if (mNextUnblockedEvent == mPendingEvent) {mNextUnblockedEvent = nullptr;}//注释4,判断输入事件的类型switch (mPendingEvent->type) {...代码省略...    case EventEntry::Type::KEY: {//按键事件std::shared_ptr<KeyEntry> keyEntry = std::static_pointer_cast<KeyEntry>(mPendingEvent);if (isAppSwitchDue) {if (isAppSwitchKeyEvent(*keyEntry)) {resetPendingAppSwitchLocked(true);isAppSwitchDue = false;} else if (dropReason == DropReason::NOT_DROPPED) {dropReason = DropReason::APP_SWITCH;}}//事件过期if (dropReason == DropReason::NOT_DROPPED && isStaleEvent(currentTime, *keyEntry)) {dropReason = DropReason::STALE;}//阻碍其他窗口获取事件if (dropReason == DropReason::NOT_DROPPED && mNextUnblockedEvent) {dropReason = DropReason::BLOCKED;}//注释5,调用dispatchKeyLocked方法分发按键事件done = dispatchKeyLocked(currentTime, keyEntry, &dropReason, nextWakeupTime);break;}case EventEntry::Type::MOTION: {//触摸事件std::shared_ptr<MotionEntry> motionEntry =std::static_pointer_cast<MotionEntry>(mPendingEvent);//如果没有及时响应窗口切换操作if (dropReason == DropReason::NOT_DROPPED && isAppSwitchDue) {dropReason = DropReason::APP_SWITCH;}//事件过期if (dropReason == DropReason::NOT_DROPPED && isStaleEvent(currentTime, *motionEntry)) {dropReason = DropReason::STALE;}//阻碍其他窗口获取事件if (dropReason == DropReason::NOT_DROPPED && mNextUnblockedEvent) {dropReason = DropReason::BLOCKED;}//调用dispatchMotionLocked方法分发触摸事件done = dispatchMotionLocked(currentTime, motionEntry, &dropReason, nextWakeupTime);break;}case EventEntry::Type::SENSOR: {std::shared_ptr<SensorEntry> sensorEntry =std::static_pointer_cast<SensorEntry>(mPendingEvent);if (dropReason == DropReason::NOT_DROPPED && isAppSwitchDue) {dropReason = DropReason::APP_SWITCH;}nsecs_t bootTime = systemTime(SYSTEM_TIME_BOOTTIME);if (dropReason == DropReason::NOT_DROPPED && isStaleEvent(bootTime, *sensorEntry)) {dropReason = DropReason::STALE;}dispatchSensorLocked(currentTime, sensorEntry, &dropReason, nextWakeupTime);done = true;break;}}if (done) {if (dropReason != DropReason::NOT_DROPPED) {dropInboundEventLocked(*mPendingEvent, dropReason);}mLastDropReason = dropReason;//注释6,释放本次处理完毕的分发事件对象releasePendingEventLocked();//注释7,使InputDispatcher能够立刻进行下一次事件的分发*nextWakeupTime = LONG_LONG_MIN; }
}

在注释1处,判断如果当前InputDispatcher被冻结,则不进行分发操作,InputDispatcher有三种状态:正常、冻结、禁用;可以通过InputDispatcher的setInputDispatchMode方法进行设置。在注释2处,mAppSwitchDueTime代表了App最近发生窗口切换操作时(比如按Home键,挂断电话),该操作事件最迟的分发时间,如果mAppSwitchDueTime小于或等于当前系统时间,说明没有及时响应窗口切换的操作,则isAppSwitchDue的值为true,如果mAppSwitchDueTime小于nextWakeupTime,这样当InputDispatcher处理完分发事件后,会立刻被唤醒执行窗口切换操作。在注释3处会将输入事件队列mInboundQueue最前端条目取出赋值给mPendingEvent。然后在注释4处判断输入事件的类型。如果为按键事件,则在注释5处调用dispatchKeyLocked方法开始分发按键事件。在注释6处会释放本次处理完毕的分发事件对象。然后将休眠时间设置为最短休眠时间,以便InputDispatcher能立刻被唤醒以便进行下一次事件的分发。

2.3 InputDispatcher的dispatchKeyLocked方法

>frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp
bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, std::shared_ptr<KeyEntry> entry,DropReason* dropReason, nsecs_t* nextWakeupTime) {...代码省略...//如果事件是需要丢弃的,则返回true,不再为该事件寻找合适的窗口if (*dropReason != DropReason::NOT_DROPPED) {setInjectionResult(*entry,*dropReason == DropReason::POLICY ? InputEventInjectionResult::SUCCEEDED: InputEventInjectionResult::FAILED);mReporter->reportDroppedKey(entry->id);return true;}//目标窗口列表std::vector<InputTarget> inputTargets;//注释1,调用findFocusedWindowTargetsLocked查找焦点窗口InputEventInjectionResult injectionResult =findFocusedWindowTargetsLocked(currentTime, *entry, inputTargets, nextWakeupTime);//输入事件被挂起,说明找到了窗口但是窗口无响应if (injectionResult == InputEventInjectionResult::PENDING) {return false;}setInjectionResult(*entry, injectionResult);//输入事件没有分发成功,说明没有找到合适的窗口if (injectionResult != InputEventInjectionResult::SUCCEEDED) {return true;}//将分发的目标添加到inputTargets列表中addGlobalMonitoringTargetsLocked(inputTargets, getTargetDisplayId(*entry));//注释2,调用dispatchEventLocked方法dispatchEventLocked(currentTime, entry, inputTargets);return true;
}

在注释1处会调用findFocusedWindowTargetsLocked查找当前的焦点窗口并将其存储到inputTargets中。然后在注释2处,会调用dispatchEventLocked方法将输入事件分发给inputTargets列表中的目标窗口。

2.4 InputDispatcher的dispatchEventLocked方法

>frameworks/native/services/inputflinger/dispatcher/InputDispatcher.h
class InputDispatcher : public android::InputDispatcherInterface, public gui::WindowInfosListener {
private:std::unordered_map<sp<IBinder>, sp<Connection>, StrongPointerHash<IBinder>> mConnectionsByTokenGUARDED_BY(mLock);
}
>frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp
void InputDispatcher::dispatchEventLocked(nsecs_t currentTime,std::shared_ptr<EventEntry> eventEntry,const std::vector<InputTarget>& inputTargets) {...代码省略...pokeUserActivityLocked(*eventEntry);//遍历inputTargets列表for (const InputTarget& inputTarget : inputTargets) {//注释1,调用getConnectionLocked方法获取当前inputTarget对应的connectionsp<Connection> connection = getConnectionLocked(inputTarget.inputChannel->getConnectionToken());if (connection != nullptr) {//注释2,调用prepareDispatchCycleLocked方法开始事件分发循环prepareDispatchCycleLocked(currentTime, connection, eventEntry, inputTarget);} else {if (DEBUG_FOCUS) {ALOGD("Dropping event delivery to target with channel '%s' because it ""is no longer registered with the input dispatcher.",inputTarget.inputChannel->getName().c_str());}}}
}sp<Connection> InputDispatcher::getConnectionLocked(const sp<IBinder>& inputConnectionToken) const {if (inputConnectionToken == nullptr) {return nullptr;}//遍历mConnectionsByTokenfor (const auto& [token, connection] : mConnectionsByToken) {//如果token相等,则返回该对象if (token == inputConnectionToken) {return connection;}}return nullptr;
}

在注释1处调用getConnectionLocked方法,传入当前inputTarget对应的连接令牌,该方法内部会遍历当前存在的所有窗口连接,返回和当前inputTarget令牌相等的窗口连接对象connection 。然后在注释2处调用prepareDispatchCycleLocked方法开始事件分发循环。

2.5 输入事件的加工和分发流程小结

1.InputReader将设备节点中的输入事件进行加工并发送给InputDispatcher
2.InputDispatcher在收到事件后,会重新封装为一个KeyEntry对象,并压入mInboundQueue列表中,唤醒InputDispatcher线程
3.InputDispatcher线程会循环调用dispatchOnce方法,将存放在mInboundQueue列表中的输入事件依次取出,并判断根据输入事件的具体类型调用对应的事件分发方法
4.如果是按键事件,则会调用dispatchKeyLocked方法;如果是触摸事件,则会调用dispatchMotionLocked方法
5.在调用特定dispatch*Locked方法进行特定事件分发的过程中,都会先调用findFocusedWindowTargetsLocked方法查找当前系统的焦点窗口,然后将输入事件分发给焦点目标窗口

三、系统窗口状态数据的传递

我们在Android 12系统源码_窗口管理(二)WindowManager对窗口的管理过程这篇文章有讲过,代表窗口视图的Window是在ViewRootImpl的setView方法中传入WMS的。

frameworks/base/core/java/android/view/ViewRootImpl.java

public final class ViewRootImpl implements ViewParent,View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks {final IWindowSession mWindowSession;final W mWindow;final View.AttachInfo mAttachInfo;public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,int userId) {synchronized (this) {...代码省略...InputChannel inputChannel = null;if ((mWindowAttributes.inputFeatures& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {inputChannel = new InputChannel();}...代码省略...res = mWindowSession.addToDisplayAsUser(mWindow, mWindowAttributes,getHostVisibility(), mDisplay.getDisplayId(), userId,mInsetsController.getRequestedVisibilities(), inputChannel, mTempInsets,mTempControls);...代码省略...}
}
>frameworks/base/services/core/java/com/android/server/wm/Session.java
class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {@Overridepublic int addToDisplay(IWindow window, WindowManager.LayoutParams attrs,int viewVisibility, int displayId, InsetsVisibilities requestedVisibilities,InputChannel outInputChannel, InsetsState outInsetsState,InsetsSourceControl[] outActiveControls) {return mService.addWindow(this, window, attrs, viewVisibility, displayId,UserHandle.getUserId(mUid), requestedVisibilities, outInputChannel, outInsetsState,outActiveControls);}
}
>frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
public class WindowManagerService extends IWindowManager.Stubimplements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {//窗口管理策略的接口类,用来定义一个窗口策略所要遵循的通用规范,具体实现类为PhoneWindowManager。final WindowManagerPolicy mPolicy;public int addWindow(Session session, IWindow client, LayoutParams attrs, int viewVisibility,int displayId, int requestUserId, InsetsVisibilities requestedVisibilities,InputChannel outInputChannel, InsetsState outInsetsState,InsetsSourceControl[] outActiveControls) {...代码省略...//创建窗口状态对象,该对象包含窗口所对应的所有信息,它就是要添加的窗口对象final WindowState win = new WindowState(this, session, client, token, parentWindow,appOp[0], attrs, viewVisibility, session.mUid, userId,session.mCanAddInternalSystemWindow);...代码省略...                //检验窗口是否可以被添加到系统中res = displayPolicy.validateAddingWindowLw(attrs, callingPid, callingUid);android.util.Log.d(TAG, "addWindow: res = "+res);if (res != ADD_OKAY) {return res;}final boolean openInputChannels = (outInputChannel != null&& (attrs.inputFeatures & INPUT_FEATURE_NO_INPUT_CHANNEL) == 0);if (openInputChannels) {win.openInputChannel(outInputChannel);}...代码省略...}
}
>frameworks/base/services/core/java/com/android/server/wm/WindowState.java
class WindowState extends WindowContainer<WindowState> implements WindowManagerPolicy.WindowState,InsetsControlTarget, InputTarget {void openInputChannel(InputChannel outInputChannel) {if (mInputChannel != null) {throw new IllegalStateException("Window already has an input channel.");}String name = getName();mInputChannel = mWmService.mInputManager.createInputChannel(name);mInputChannelToken = mInputChannel.getToken();mInputWindowHandle.setToken(mInputChannelToken);mWmService.mInputToWindowMap.put(mInputChannelToken, this);if (outInputChannel != null) {mInputChannel.copyTo(outInputChannel);} else {// If the window died visible, we setup a fake input channel, so that taps// can still detected by input monitor channel, and we can relaunch the app.// Create fake event receiver that simply reports all events as handled.mDeadWindowEventReceiver = new DeadWindowEventReceiver(mInputChannel);}}}
>frameworks/base/services/core/java/com/android/server/input/InputManagerService.java
public class InputManagerService extends IInputManager.Stubimplements Watchdog.Monitor {private static native InputChannel nativeCreateInputChannel(long ptr, String name);public InputChannel createInputChannel(String name) {return nativeCreateInputChannel(mPtr, name);}
}
>frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
static jobject nativeCreateInputChannel(JNIEnv* env, jclass /* clazz */, jlong ptr,jstring nameObj) {//获取NativeInputManager 实例NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);//转换 Java 字符串ScopedUtfChars nameChars(env, nameObj);std::string name = nameChars.c_str();//注释1,创建Native层的InputChannel对象base::Result<std::unique_ptr<InputChannel>> inputChannel = im->createInputChannel(env, name);//如果创建 InputChannel 失败,生成错误消息并抛出一个 RuntimeException,返回 nullptr。if (!inputChannel.ok()) {std::string message = inputChannel.error().message();message += StringPrintf(" Status=%d", inputChannel.error().code());jniThrowRuntimeException(env, message.c_str());return nullptr;}//注释3,将Navite层的inputChannel对象转化为Java层的inputChannel对象jobject inputChannelObj = android_view_InputChannel_createJavaObject(env, std::move(*inputChannel));if (!inputChannelObj) {return nullptr;}//设置一个回调函数 handleInputChannelDisposed,以便在Java层InputChannel被垃圾回收时处理清理操作。android_view_InputChannel_setDisposeCallback(env, inputChannelObj, handleInputChannelDisposed, im);//返回Java层的InputChannel对象return inputChannelObj;
}base::Result<std::unique_ptr<InputChannel>> NativeInputManager::createInputChannel(JNIEnv* /* env */, const std::string& name) {ATRACE_CALL();//注释2,调用InputDispatcher的createInputChannel方法return mInputManager->getDispatcher()->createInputChannel(name);
}>frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp
Result<std::unique_ptr<InputChannel>> InputDispatcher::createInputChannel(const std::string& name) {
#if DEBUG_CHANNEL_CREATIONALOGD("channel '%s' ~ createInputChannel", name.c_str());
#endifstd::unique_ptr<InputChannel> serverChannel;std::unique_ptr<InputChannel> clientChannel;status_t result = InputChannel::openInputChannelPair(name, serverChannel, clientChannel);if (result) {return base::Error(result) << "Failed to open input channel pair with name " << name;}{ // acquire lockstd::scoped_lock _l(mLock);const sp<IBinder>& token = serverChannel->getConnectionToken();int fd = serverChannel->getFd();sp<Connection> connection =new Connection(std::move(serverChannel), false /*monitor*/, mIdGenerator);if (mConnectionsByToken.find(token) != mConnectionsByToken.end()) {ALOGE("Created a new connection, but the token %p is already known", token.get());}mConnectionsByToken.emplace(token, connection);std::function<int(int events)> callback = std::bind(&InputDispatcher::handleReceiveCallback,this, std::placeholders::_1, token);mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, new LooperEventCallback(callback), nullptr);} // release lock// Wake the looper because some connections have changed.mLooper->wake();return clientChannel;
}

http://www.ppmy.cn/news/1533190.html

相关文章

Jupyter | jupyter notebook 使用 conda 环境

博客使用更佳 点我进入博客 创建虚拟环境 在 Anaconda Prompt 里面输入&#xff1a; conda create -n env-name并且输入 y 确认。例如我们创建环境名为 jupyter 激活环境 conda activate env-name激活之后发现环境从 base 变为 jupyter(笔者用的 env-name 为 jupyter) …

我店生活系统小程序开发功能解析

一、市场定位与目标用户 市场定位&#xff1a;我店生活小程序旨在打造一个集购物、娱乐、服务于一体的综合性本地生活服务平台&#xff0c;满足用户多样化的生活需求。通过整合周边生活服务资源&#xff0c;提供一站式的生活服务体验。 目标用户&#xff1a;主要面向中青年人…

CVPR2021 安全AI挑战者计划第六期赛道一第二名方案分享 (UM-SIAT队)

关联比赛: CVPR2021 安全AI挑战者计划第六期&#xff1a;防御模型的白盒对抗攻击 CVPR2021 安全AI挑战者计划第六期赛道一第二名方案分享 &#xff08;UM-SIAT队&#xff09; 1.赛题简介 1.比赛通过15个防御模型测试攻击算法&#xff0c;其中包括13个在CIFAR-10上训练的模型…

检查一个CentOS服务器的配置的常用命令

在CentOS系统中&#xff0c;查看服务器配置的常用命令非常丰富&#xff0c;这些命令可以帮助用户快速了解服务器的硬件信息、系统状态以及网络配置等。以下是一些常用的命令及其简要说明&#xff1a; 1. 查看CPU信息 (1) cat /proc/cpuinfo&#xff1a;显示CPU的详细信息&…

python访问SQL数据库

Step 1 创建一个数据库 Step 2 安装mysql-connector-python pip install mysql-connector-pythonStep 3 访问mysql,并查询表 import mysql.connectordef connect_and_query():try:# 连接到MySQL数据库connection = mysql.connector.connect(host=localhost, # 数据库主…

spring boot集成日志

1.spring boot集成日志 07 Springboot&#xff08;new&#xff09; 语雀 1、导包 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><!-- springboot默认是用logback的日志框架的…

VUE 开发——AJAX学习(一)

一、AJAX入门和axios使用 1.AJAX定义&#xff1a; 异步的javascript和XML&#xff0c;就是使用XMLHttp Request对象与服务器通信&#xff0c;浏览器和服务器进行数据交换的技术。 2.使用axios 引入axios.js&#xff1a;https://unpkg.com/axios/dist/axios.min.js使用axios函…

2024/9/30 英语每日一段

The British Academy has created three high-profile awards to sit alongside the trophies it hands out to adult television shows--going some way, it is hoped, to replace Bafta’s abandoned children’s TV awards event. “Children’s programme-making has been …