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

news2024/9/27 13:33:43

前言

上一篇文章我们具体分析了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.cpp

void 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 happen
                    break;
            }
        }
        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 lock
        std::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 lock
        mLock.lock();
		...代码省略...
        //注释1
        std::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);
        //注释2
        needWake = enqueueInboundEventLocked(std::move(newEntry));
        mLock.unlock();
    } // release lock

    if (needWake) {
        //注释3
        mLooper->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 lock
        std::scoped_lock _l(mLock);
        mDispatcherIsAlive.notify_all();

        //注释1,检测缓存队列中是否没有等待处理的指令
        if (!haveCommandsLocked()) {
            //调用dispatchOnceInnerLocked方法
            dispatchOnceInnerLocked(&nextWakeupTime);
        }
        //注释2,执行指令
        if (runCommandsLockedInterruptible()) {
              nextWakeupTime = LONG_LONG_MIN;
        }
        //检查ANR
        const 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最前端条目取出赋值给mPendingEvent
            mPendingEvent = 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>> mConnectionsByToken
            GUARDED_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对应的connection
        sp<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;
    }
    //遍历mConnectionsByToken
    for (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方法查找当前系统的焦点窗口,然后将输入事件分发给焦点目标窗口

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2170115.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

混拨动态IP代理的优势是什么

在当今互联网时代&#xff0c;隐私保护和网络安全成为了人们关注的焦点。无论是个人用户还是企业&#xff0c;都希望能够在网络上自由、安全地进行各种活动。混拨动态IP代理作为一种新兴的技术手段&#xff0c;正逐渐受到大家的青睐。那么&#xff0c;混拨动态IP代理到底有哪些…

【工具】JDK版本不好管理,SDKMAN来帮你

前言 &#x1f34a;缘由 SDKMAN真是好&#xff0c;JDK切换没烦恼 &#x1f423; 闪亮主角 大家好&#xff0c;我是JavaDog程序狗 今天跟大家能分享一个JDK版本管理工具SDKMAN 当你同时使用JDK 1.8的和JDK 17并行维护两个项目时。每次在两个项目之间并行开发&#xff0c;切…

进阶数据库系列(十三):PostgreSQL 分区分表

概述 在组件开发迭代的过程中&#xff0c;随着使用时间的增加&#xff0c;数据库中的数据量也不断增加&#xff0c;因此数据库查询越来越慢。 通常加速数据库的方法很多&#xff0c;如添加特定的索引&#xff0c;将日志目录换到单独的磁盘分区&#xff0c;调整数据库引擎的参…

2.4卷积3

2.4卷积3 文章学习自https://zhuanlan.zhihu.com/p/41609577&#xff0c;详细细节请读原文。 狄拉克 δ \delta δ 函数&#xff1a; δ ( x ) { ∞ , x 0 0 , x ≠ 0 \delta (x){\begin{cases} \infty ,& x0\\ 0,& x\neq 0\end{cases}} δ(x){∞,0,​x0x0​ 并…

小柴冲刺软考中级嵌入式系统设计师系列二、嵌入式系统硬件基础知识(2)嵌入式微处理器基础

目录 冯诺依曼结构 哈佛结构 一、嵌入式微处理器的结构和类型 1、8位、16位、32位处理器的体系结构特点 2、DSP处理器的体系结构特点 3、多核处理器的体系结构特点 二、嵌入式微处理器的异常与中断 1、异常 2、中断 flechazohttps://www.zhihu.com/people/jiu_sheng …

54 循环神经网络RNN_by《李沐:动手学深度学习v2》pytorch版

系列文章目录 文章目录 系列文章目录循环神经网络使用循环神经网络的语言模型困惑度&#xff08;perplexity&#xff09;梯度剪裁 循环神经网络 使用循环神经网络的语言模型 输入“你”&#xff0c;更新隐变量&#xff0c;输出“好”。 困惑度&#xff08;perplexity&#xff…

【递归】8. leetcode 671 二叉树中第二小的节点

题目描述 题目链接&#xff1a;二叉树中第二小的节点 2 解答思路 注意这句话&#xff1a;该节点的值等于两个子节点中较小的一个 二叉树的根节点的值是整棵树中最小的值 本道题所要求的是二叉树中第二小的节点。因为根节点是最小的节点&#xff0c;那么我们只需要找到第一…

HT5169内置BOOST升压的11W I2S输入D类音频功放

1 特性 ● 电源供电 升压输入VBAT:2.5V-5.5V; 升压输出PVDD可调&#xff0c;最高7.5V DVDD/AVDD分辨率:3.3V ● 音频性能 9.0W (VBAT3.7V, PVDD 7.5V, RL3Ω.THDN10%) 11.0W(VBAT3.7V, PVDD 7.5V, RL2Ω.THDN10% 5.5W (VBAT3.7V, PVDD 6.5V, RL4Ω.THDN10%) ● 灵活的…

红米k60至尊版工程固件 MTK芯片 资源预览 刷写说明 与nv损坏修复去除电阻图示

红米k60至尊版机型代码为:corot。 搭载了联发科天玑9200+处理器。此固件mtk引导为MT6985。博文将简单说明此固件的一些特点与刷写注意事项。对于NV损坏的机型。展示修改校验电阻的图示。方便改写参数等 通过博文了解 1💝💝💝-----此机型工程固件的资源刷写注意事项 2…

css 中 ~ 符号、text-indent、ellipsis、ellipsis-2、text-overflow: ellipsis的使用

1、~的使用直接看代码 <script setup> </script><template><div class"container"><p><a href"javascript:;">纪检委</a><a href"javascript:;">中介为</a><a href"javascript:…

曲线图异常波形检测系统源码分享

曲线图异常波形检测检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Comput…

【cache】浅析四种常用的缓存淘汰算法 FIFO/LRU/LFU/W-TinyLFU

本文浅析淘汰策略与工作中结合使用、选取&#xff0c;并非针对算法本身如何实现的 文章目录 FIFOLFULRUW-TinyLFU实践与优化监控与调整 FIFO first input first output &#xff0c; 先进先出&#xff0c;即最早存入的元素最先取出&#xff0c; 典型数据结构代表&#xff1a;…

SpringCloud-Netflix第一代微服务快速入门

1.springCloud常用组件 Netflix Eureka 当我们的微服务过多的时候&#xff0c;管理服务的通信地址是一个非常麻烦的事情&#xff0c;Eureka就是用来管理微服务的通信地址清单的&#xff0c;有了Eureka之后我们通过服务的名字就能实现服务的调用。 Netflix Ribbon\Feign : 客…

Python精选200Tips:171-175

深度学习实战项目 P171--CIFAR10数据集图像分类(Image Classification)P172--MS COCO数据集物体检测(Object Detection)P173-- MNIST手写数字数据集DCGAN生成P174--基于EasyOCR的字符识别P175--基于Air Quality数据集的变分自编码器(Variational autoEncoder&#xff0c;VAE) 运…

QT版数据采集系统研发过程记录

研发目的&#xff1a;通过智能监测设备将各个变电站运行的电压、电流、温湿度等数据采集汇总到计算机中心服务器&#xff0c;通过系统软件展示各个站点对应的运行工况。 软件架构&#xff1a;使用QT开发跨平台&#xff08;Windows系统、Ubuntu20.04&#xff09;客户端软件、连…

基于MATLAB的苹果外观特征检测

摘 要 本文根据苹果分级判定标准中的两个评定指标&#xff1a;果径和果面缺陷&#xff0c;探讨如何利用MATLAB技术进行苹果外观的特征检测&#xff0c;从而提高苹果品质检测的工作效率。 关键词 MATLAB&#xff1b;苹果分级&#xff1b;果径&#xff1b;果面缺陷 0 引言 …

Pandas -----------------------基础知识(四)

自定义函数 Series 加载数据 import pandas as pd df pd.DataFrame({Age: [20, 25, 30, 35, 40]}) df # 目标: 让 Age 列 的每个元素 num1 num2 def add_nums(x,num1,num2):return x num1 num2 df[Age].apply(add_nums,num1 2,num2 3) 法二 df[Age].apply(lambda x ,num1…

大模型算法入行转行?指南来了!

最近私信问我关于入行、转行方面的问题比较多&#xff0c;就专门写一篇讲讲我的理解。 首先说明一下个人的背景和现状&#xff0c;我本人是本科学历&#xff0c;有互联网大厂搜推方向经验&#xff0c;后来跳到中厂继续做推荐&#xff0c;去年开始做大模型。现在是个小组长&…

用ChatGPT做数据分析与挖掘,爽!

导读&#xff1a;在现代数据分析中&#xff0c;Python凭借其强大的数据处理能力和丰富的库资源成为首选工具。ChatGPT&#xff0c;作为先进的自然语言处理模型&#xff0c;正逐步成为Python数据分析与挖掘的强大辅助工具。 通过ChatGPT的自然语言处理能力&#xff0c;用户可以…

模糊综合评价法详细讲解+Python代码实现

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…