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之读一次事件的流程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 第一次去他家他开车接我,第二次呢?
- 下一篇: android+命令行编译,打包生成ap