日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

android 事件管理器,Android输入管理InputManager之读一次事件的流程

發布時間:2025/4/5 Android 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 android 事件管理器,Android输入管理InputManager之读一次事件的流程 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

流程圖如下所示:

讀一次事件的流程.png

讀取線程InputReaderThread執行InputReader#loopOnce一次

void InputReader::loopOnce() {

int32_t oldGeneration;

int32_t timeoutMillis;

bool inputDevicesChanged = false;

Vector inputDevices;

....

size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);

{ // acquire lock

....

if (count) {//處理事件

processEventsLocked(mEventBuffer, count);

}

....

} // release lock

...

mQueuedListener->flush();//刷新派發

}

EventHub#getEvents獲取事件,線程在此阻塞,直到被喚醒。

InputReader#processEventsLocked方法。如果count數據不空,事件處理。

void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {

//遍歷count個事件RawEvent*

for (const RawEvent* rawEvent = rawEvents; count;) {

int32_t type = rawEvent->type;

size_t batchSize = 1;

//來自input.h中的事件類型

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;

}

//處理一批batchSize個事件,從rawEvent指針開始

processEventsForDeviceLocked(deviceId, rawEvent, batchSize);

} else {

...處理其他類型,設備增加刪除等

switch (rawEvent->type) {

case EventHubInterface::DEVICE_ADDED:

//當受到增加新設備的事件時,addDeviceLocked負

//責創建InputDevice,建立deviceId與InputDevice

//的鍵值對裝入KeyedVector容器mDevices中,根據

//設備class,為InputDevice創建一個InputMapper

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;

}

count -= batchSize;

rawEvent += batchSize;

}

}

在EventHubInterface中定義的枚舉中,FIRST_SYNTHETIC_EVENT被設置為DEVICE_ADDED。

在type小于FIRST_SYNTHETIC_EVENT時,說明事件類型不是增加/刪除/掃描設備事件。

EventHubInterface類

enum {

DEVICE_ADDED = 0x10000000,//增加設備

DEVICE_REMOVED = 0x20000000,//移除設備

FINISHED_DEVICE_SCAN = 0x30000000,

FIRST_SYNTHETIC_EVENT = DEVICE_ADDED,

};

processEventsLocked處理一系列事件的集合如圖:

processEventsLocked處理的一系列事件.png

batchSize代表rawEvents中以當前rawEvent為頭指針的一批連續待處理事件的數量,deviceId相同且非增加/刪除/掃描設備事件。

若rawEvents中存在增加/刪除/掃描設備事件(大于FIRST_SYNTHETIC_EVENT)如上圖,在偏移batchSize=5處查到rawEvent[batchSize].type滿足增加/刪除/掃描設備事件,break退出while,之前統計的一批5個Motion事件通過processEventsForDeviceLocked處理,rawEvent設置為頭指針。

在最后兩行將rawEvent指向batchSize偏移處,即下一次處理的Add/Del事件,count減去已處理的數量batchSize。增加/刪除/掃描設備事件處理中,只能處理一個事件,batchSize值保持1。

processEventsForDeviceLocked

負責RawEvent*事件處理,根據設備deviceId,找到InputDevice類,count是此次處理的事件數量,rawEvents代表這些事件的頭指針。

void InputReader::processEventsForDeviceLocked(int32_t deviceId,const RawEvent* rawEvents,

size_t count){

ssize_t deviceIndex = mDevices.indexOfKey(deviceId);

if (deviceIndex < 0) {

ALOGW("Discarding event for unknown deviceId %d.", deviceId);

return;

}

InputDevice* device = mDevices.valueAt(deviceIndex);

if (device->isIgnored()) {//設備忽略直接退出

return;

}

device->process(rawEvents, count);

}

InputDevice表示單個輸入設備。

InputDevice#process具體設備處理每一個RawEvent*,交給mMappers,InputDevice內部的InputMapper數組。

void InputDevice::process(const RawEvent* rawEvents, size_t count) {

size_t numMappers = mMappers.size();

for (const RawEvent* rawEvent = rawEvents; count--; rawEvent++) {

if (mDropUntilNextSync) {

.....

} else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_DROPPED) {

mDropUntilNextSync = true;

reset(rawEvent->when);

} else {

for (size_t i = 0; i < numMappers; i++) {//每個InputMapper處理事件

InputMapper* mapper = mMappers[i];

mapper->process(rawEvent);

}

}

}

}

每一種類型的設備都有對應的InputMapper,觸屏Maper是SingleTouchInputMapper。

InputReader#createDeviceLocked方法

InputDevice* InputReader::createDeviceLocked(int32_t deviceId, int32_t controllerNumber,

const InputDeviceIdentifier& identifier, uint32_t classes) {

InputDevice* device = new InputDevice(&mContext, deviceId, bumpGenerationLocked(),

controllerNumber, identifier, classes);

....其他設備設置與addMapper

//觸屏設備

if (classes & INPUT_DEVICE_CLASS_TOUCH_MT) {

device->addMapper(new MultiTouchInputMapper(device));

} else if (classes & INPUT_DEVICE_CLASS_TOUCH) {

device->addMapper(new SingleTouchInputMapper(device));

}

....

return device;

}

創建InputDevice,同時創建了InputMapper。根據classes類型,只增加了一個SingleTouchInputMapper,下面所有的RawEvent*交給SingleTouchInputMapper處理。

EventHub.h頭文件定義

INPUT_DEVICE_CLASS_TOUCH = 0x00000004,//觸屏

SingleTouchInputMapper處理流

中間過程繁瑣,僅看下流程

從process開始,依次經過方法sync、processRawTouches、cookAndDispatch、dispatchTouches、dispatchMotion,最后包裝一個NotifyMotionArgs交給回調監聽。

SingleTouchInputMapper#process方法,SingleTouchInputMapper是TouchInputMapper派生類。

void SingleTouchInputMapper::process(const RawEvent* rawEvent) {

TouchInputMapper::process(rawEvent);

mSingleTouchMotionAccumulator.process(rawEvent);

}

TouchInputMapper#process方法。

void TouchInputMapper::process(const RawEvent* rawEvent) {

mCursorButtonAccumulator.process(rawEvent);

mCursorScrollAccumulator.process(rawEvent);

mTouchButtonAccumulator.process(rawEvent);

if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {

sync(rawEvent->when);

}

}

TouchInputMapper#sync方法。

void TouchInputMapper::sync(nsecs_t when) {

const RawState* last = mRawStatesPending.isEmpty() ?

&mCurrentRawState : &mRawStatesPending.top();

mRawStatesPending.push();

RawState* next = &processRawTouchesmRawStatesPending.editTop();

next->clear();

next->when = when;

...

syncTouch(when, next);

//分配手指ids

if (!mHavePointerIds) {

assignPointerIds(last, next);

}

processRawTouches(false /*timeout*/);

}

TouchInputMapper#processRawTouches方法。

void TouchInputMapper::processRawTouches(bool timeout) {

if (mDeviceMode == DEVICE_MODE_DISABLED) {

// Drop all input if the device is disabled.

mCurrentRawState.clear();

mRawStatesPending.clear();

return;

}

const size_t N = mRawStatesPending.size();

size_t count;

for(count = 0; count < N; count++) {

...

cookAndDispatch(mCurrentRawState.when);

}

}

TouchInputMapper#cookAndDispatch方法。

void TouchInputMapper::cookAndDispatch(nsecs_t when) {

....

if (mDeviceMode == DEVICE_MODE_POINTER) {

.....

} else {

if (mDeviceMode == DEVICE_MODE_DIRECT

&& mConfig.showTouches && mPointerController != NULL) {

...

}

if (!mCurrentMotionAborted) {

....

dispatchTouches(when, policyFlags);

...

}

...

}

...

}

TouchInputMapper#dispatchTouches方法。

void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags){

...

dispatchMotion(when, policyFlags, mSource,

AMOTION_EVENT_ACTION_POINTER_DOWN, 0, 0, metaState, buttonState, 0,

mCurrentCookedState.cookedPointerData.pointerProperties,

mCurrentCookedState.cookedPointerData.pointerCoords,

mCurrentCookedState.cookedPointerData.idToIndex,

dispatchedIdBits, downId, mOrientedXPrecision, mOrientedYPrecision, mDownTime);

...

}

TouchInputMapper#dispatchMotion方法

定義一個通知發送參數NotifyMotionArgs交給回調Listener。

void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source,

int32_t action, int32_t actionButton, int32_t flags,

int32_t metaState, int32_t buttonState, int32_t edgeFlags,

const PointerProperties* properties, const PointerCoords* coords,

const uint32_t* idToIndex, BitSet32 idBits, int32_t changedId,

float xPrecision, float yPrecision, nsecs_t downTime) {

PointerCoords pointerCoords[MAX_POINTERS];

PointerProperties pointerProperties[MAX_POINTERS];

uint32_t pointerCount = 0;

while (!idBits.isEmpty()) {

uint32_t id = idBits.clearFirstMarkedBit();

uint32_t index = idToIndex[id];

pointerProperties[pointerCount].copyFrom(properties[index]);

pointerCoords[pointerCount].copyFrom(coords[index]);

...

...

NotifyMotionArgs args(when, getDeviceId(), source, policyFlags,

action, actionButton, flags, metaState, buttonState, edgeFlags,

mViewport.displayId, pointerCount, pointerProperties, pointerCoords,

xPrecision, yPrecision, downTime);

getListener()->notifyMotion(&args);

}

QueuedInputListener

TouchInputMapper#getListener()返回QueuedInputListener

在TouchInputMapper父類InputMapper中,描述了Listener的來源:InputReaderContext#getListener方法。

InputMapper類

inline InputListenerInterface* getListener() { return mContext->getListener(); }

上文mContext是InputReaderContext。ContextImpl是InputReaderContext的派生類(內部封裝InputReader),ContextImpl實現InputReaderContext的getListener方法。

InputListenerInterface* InputReader::ContextImpl::getListener() {

return mReader->mQueuedListener.get();

}

大體結構圖如下所示:

InputMapper主要結構示意圖.png

綜上:TouchInputMapper觸發內部ContextImpl的getListener方法,獲取的Listener是InputReader中的mQueuedListener。

InputReader實例化時創建QueuedInputListener。

mQueuedListener = new QueuedInputListener(listener);

上文中listener是InputReader構造方法入參,其實是InputDispatcher。

mDispatcher = new InputDispatcher(dispatcherPolicy);

mReader = new InputReader(eventHub, readerPolicy, mDispatcher);

QueuedInputListener#notifyMotion方法

QueuedInputListener是InputListenerInterface接口的派生類

定義了各種類型輸入的通知方法notifyXXX()。

class QueuedInputListener : public InputListenerInterface {

public:

QueuedInputListener(const sp& innerListener);

virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args);

virtual void notifyKey(const NotifyKeyArgs* args);

//通知觸屏事件

virtual void notifyMotion(const NotifyMotionArgs* args);

virtual void notifySwitch(const NotifySwitchArgs* args);

virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args);

void flush();

private:

sp mInnerListener;

Vector mArgsQueue;

};

通知參數實體也在此定義,每個事件類型都有自己的通知參數實體

/* Describes a motion event. */

struct NotifyMotionArgs : public NotifyArgs {

nsecs_t eventTime;

int32_t deviceId;

uint32_t source;

...

}

內部封裝了一個mInnerListener與mArgsQueue,mInnerListener就是InputDispatcher對象。

mArgsQueue是一個動態的數組容器。

notifyMotion方法

void QueuedInputListener::notifyMotion(const NotifyMotionArgs* args) {

mArgsQueue.push(new NotifyMotionArgs(*args));

}

向數組中增加一個NotifyMotionArgs實體,讀取的事件存放在QueuedInputListener的數組mArgsQueue中。

綜上,讀取線程一次讀取的流程結束,可以看出,該線程處于休眠狀態,當事件發生時,被喚醒,拿到事件,然后從InputReader對象一步步將事件交給QueuedInputListener對象,事件信息存儲在QueuedInputListener內部數組。

接下來讀取線程會通過QueuedInputListener的flush方法刷新,將事件消息讀出來交給內部InputDispatcher。

Happy

End

^ ^

總結

以上是生活随笔為你收集整理的android 事件管理器,Android输入管理InputManager之读一次事件的流程的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。