基于Android 7.0源碼分析
以最基本的MotionEvent(touchsreen single pointer)為例分析
InputReader讀取輸入事件分發給InputDispatcher的過程
下面從InputReader
的loopOnce()
開始分析
void InputReader::loopOnce() {
int32_t oldGeneration;
int32_t timeoutMillis;
bool inputDevicesChanged = false;
Vector<InputDeviceInfo> inputDevices;
......
// 獲取驅動上報的輸入事件,返回讀取的事件數
size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
{ // acquire lock
AutoMutex _l(mLock);
mReaderIsAliveCondition.broadcast();
if (count) {
// 處理輸入事件
processEventsLocked(mEventBuffer, count);
}
......
}
......
// 發送事件給InputDispatcher
mQueuedListener->flush();
}
size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
ALOG_ASSERT(bufferSize >= 1);
AutoMutex _l(mLock);
struct input_event readBuffer[bufferSize];
RawEvent* event = buffer;
size_t capacity = bufferSize;
bool awoken = false;
for (;;) {
......
// Grab the next input event.
// 讀取輸入事件
bool deviceChanged = false;
while (mPendingEventIndex < mPendingEventCount) {
......
ssize_t deviceIndex = mDevices.indexOfKey(eventItem.data.u32);
if (deviceIndex < 0) {
ALOGW("Received unexpected epoll event 0x%08x for unknown device id %d.",
eventItem.events, eventItem.data.u32);
continue;
}
// 找到上報事件的設備
Device* device = mDevices.valueAt(deviceIndex);
if (eventItem.events & EPOLLIN) {
// 讀取輸入事件
int32_t readSize = read(device->fd, readBuffer,
sizeof(struct input_event) * capacity);
if (readSize == 0 || (readSize < 0 && errno == ENODEV)) {
// Device was removed before INotify noticed.
// 讀取失敗,設備已經移除
ALOGW("could not get event, removed? (fd: %d size: %" PRId32
" bufferSize: %zu capacity: %zu errno: %d)\n",
device->fd, readSize, bufferSize, capacity, errno);
deviceChanged = true;
closeDeviceLocked(device);
} else if (readSize < 0) {
if (errno != EAGAIN && errno != EINTR) {
ALOGW("could not get event (errno=%d)", errno);
}
} else if ((readSize % sizeof(struct input_event)) != 0) {
// 輸入事件不完整
ALOGE("could not get event (wrong size: %d)", readSize);
} else {
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++) {
// 解析讀取的事件,封裝為RawEvent
struct input_event& iev = readBuffer[i];
......
event->deviceId = deviceId;
event->type = iev.type;
event->code = iev.code;
event->value = iev.value;
event += 1;
capacity -= 1;
}
}
}
}
......
// 讀取到一些事件立即返回
// Return now if we have collected any events or if we were explicitly awoken.
if (event != buffer || awoken) {
break;
}
}
......
// All done, return the number of events we read.
return event - buffer;
}
-
RawEvent
中的時間使用的是驅動上報事件的時間,更加精確;另外還要防止輸入設備時鐘源切換引入的問題
下面分析processEventsLocked()
的實現
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) {
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 {
......
}
count -= batchSize;
rawEvent += batchSize;
}
}
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()) {
//ALOGD("Discarding event for ignored deviceId %d.", deviceId);
return;
}
// 調用InputDevice的process處理
device->process(rawEvents, count);
}
void InputDevice::process(const RawEvent* rawEvents, size_t count) {
// Process all of the events in order for each mapper.
// We cannot simply ask each mapper to process them in bulk because mappers may
// have side-effects that must be interleaved. For example, joystick movement events and
// gamepad button presses are handled by different mappers but they should be dispatched
// in the order received.
size_t numMappers = mMappers.size();
for (const RawEvent* rawEvent = rawEvents; count--; rawEvent++) {
......
for (size_t i = 0; i < numMappers; i++) {
InputMapper* mapper = mMappers[i];
// 對于MotionEvent, 由MultiTouchInputMapper處理
mapper->process(rawEvent);
}
......
}
}
在分析MultiTouchInputMapper
的process()
實現之前,先簡單了解下touchscreen驅動上報的原始輸入事件的格式。
Down/Move事件類似:
1) report (EV_ABS, ABS_MT_SLOT) // 存放事件的SLOT
2) report (EV_ABS, ABS_MT_TRACKING_ID(非負)) // touch軌跡id
3) report (EV_ABS, ABS_MT_TOOL_TYPE = 0) // touch設備類型
4) report (EV_ABS, ABS_MT_POSITION_X(x坐標)) // touch區域(橢圓)的中心點的X坐標
5) report (EV_ABS, ABS_MT_POSITION_Y(Y坐標)) // touch區域(橢圓)的中心點的Y坐標
6) report (EV_SYN, SYN_REPORT) // 完整事件標示
Up事件:
1) report (EV_ABS, ABS_MT_SLOT)
2) report (EV_ABS, ABS_MT_TRACKING_ID(-1))
3) report (EV_SYN, SYN_REPORT)
更多信息請參考kernel multi-touch-protocol.txt文檔
- 不同的touchscreen驅動會有所差異
下面看process()
實現
void MultiTouchInputMapper::process(const RawEvent* rawEvent) {
// 原始事件處理
TouchInputMapper::process(rawEvent);
// 根據multi-touch protocol,解析原始事件存放到slot中
mMultiTouchMotionAccumulator.process(rawEvent);
}
void MultiTouchMotionAccumulator::process(const RawEvent* rawEvent) {
// 絕對坐標事件
if (rawEvent->type == EV_ABS) {
bool newSlot = false;
if (mUsingSlotsProtocol) {
// 獲取SLOT位置,一次Touch,Down/Move/.../Up通常使用一個SLOT存儲
if (rawEvent->code == ABS_MT_SLOT) {
mCurrentSlot = rawEvent->value;
newSlot = true;
}
} else if (mCurrentSlot < 0) {
mCurrentSlot = 0;
}
......
} else {
Slot* slot = &mSlots[mCurrentSlot];
switch (rawEvent->code) {
// 一般只有Down/Move有坐標信息
// X坐標
case ABS_MT_POSITION_X:
slot->mInUse = true;
slot->mAbsMTPositionX = rawEvent->value;
break;
// Y坐標
case ABS_MT_POSITION_Y:
slot->mInUse = true;
slot->mAbsMTPositionY = rawEvent->value;
break;
case ABS_MT_TOUCH_MAJOR:
slot->mInUse = true;
slot->mAbsMTTouchMajor = rawEvent->value;
break;
case ABS_MT_TOUCH_MINOR:
slot->mInUse = true;
slot->mAbsMTTouchMinor = rawEvent->value;
slot->mHaveAbsMTTouchMinor = true;
break;
......
case ABS_MT_TRACKING_ID:
// 通常Down/Move事件 id為非負,Up事件id = -1
if (mUsingSlotsProtocol && rawEvent->value < 0) {
// The slot is no longer in use but it retains its previous contents,
// which may be reused for subsequent touches.
// 注意對于Up事件,mInUse為false
slot->mInUse = false;
} else {
slot->mInUse = true;
slot->mAbsMTTrackingId = rawEvent->value;
}
break;
}
}
} else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_MT_REPORT) {
// MultiTouch Sync: The driver has returned all data for *one* of the pointers.
mCurrentSlot += 1;
}
}
下面看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);
}
}
void TouchInputMapper::sync(nsecs_t when) {
const RawState* last = mRawStatesPending.isEmpty() ?
&mCurrentRawState : &mRawStatesPending.top();
// Push a new state.
// 創建一個RawState
mRawStatesPending.push();
RawState* next = &mRawStatesPending.editTop();
next->clear();
next->when = when;
......
// Sync touch
// 調用MultiTouchInputMapper的syncTouch,將SLOT中的原始事件保存到next中
syncTouch(when, next);
// Assign pointer ids.
// 對于Up事件,由于pointer數為0,不分配id
if (!mHavePointerIds) {
assignPointerIds(last, next);
}
......
// 處理分發原始事件
processRawTouches(false /*timeout*/);
}
下面首先看syncTouch()
的實現,然后分析處理分發原始事件。
void MultiTouchInputMapper::syncTouch(nsecs_t when, RawState* outState) {
size_t inCount = mMultiTouchMotionAccumulator.getSlotCount();
size_t outCount = 0;
BitSet32 newPointerIdBits;
for (size_t inIndex = 0; inIndex < inCount; inIndex++) {
const MultiTouchMotionAccumulator::Slot* inSlot =
mMultiTouchMotionAccumulator.getSlot(inIndex);
// Up事件跳過
if (!inSlot->isInUse()) {
continue;
}
......
// SLOT中的原始事件信息保存到outState中
RawPointerData::Pointer& outPointer = outState->rawPointerData.pointers[outCount];
outPointer.x = inSlot->getX();
outPointer.y = inSlot->getY();
outPointer.pressure = inSlot->getPressure();
outPointer.touchMajor = inSlot->getTouchMajor();
outPointer.touchMinor = inSlot->getTouchMinor();
outPointer.toolMajor = inSlot->getToolMajor();
outPointer.toolMinor = inSlot->getToolMinor();
outPointer.orientation = inSlot->getOrientation();
outPointer.distance = inSlot->getDistance();
outPointer.tiltX = 0;
outPointer.tiltY = 0;
......
// Assign pointer id using tracking id if available.
mHavePointerIds = true;
int32_t trackingId = inSlot->getTrackingId();
int32_t id = -1;
if (trackingId >= 0) {
// 查找當前事件的trackingId在mPointerTrackingIdMap中的索引
for (BitSet32 idBits(mPointerIdBits); !idBits.isEmpty(); ) {
uint32_t n = idBits.clearFirstMarkedBit();
// mPointerTrackingIdMap用于根據id快速訪問trackingId
if (mPointerTrackingIdMap[n] == trackingId) {
id = n;
}
}
if (id < 0 && !mPointerIdBits.isFull()) {
id = mPointerIdBits.markFirstUnmarkedBit();
mPointerTrackingIdMap[id] = trackingId;
}
}
if (id < 0) {
mHavePointerIds = false;
outState->rawPointerData.clearIdBits();
newPointerIdBits.clear();
} else {
// 記錄id(single pointer時通常為0)
outPointer.id = id;
outState->rawPointerData.idToIndex[id] = outCount;
// 標記id掩碼
outState->rawPointerData.markIdBit(id, isHovering);
newPointerIdBits.markBit(id);
}
outCount += 1;
}
// pointer數這里為1
outState->rawPointerData.pointerCount = outCount;
// 更新全局id掩碼
mPointerIdBits = newPointerIdBits;
mMultiTouchMotionAccumulator.finishSync();
}
- 對于Down/Move事件,SLOT中的原始事件信息保存到
outState
中,但是對于Up事件,outState
處于初始狀態
下面分析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++) {
const RawState& next = mRawStatesPending[count];
// A failure to assign the stylus id means that we're waiting on stylus data
// and so should defer the rest of the pipeline.
if (assignExternalStylusId(next, timeout)) {
break;
}
// All ready to go.
clearStylusDataPendingFlags();
// 原始事件信息拷貝至mCurrentRawState
mCurrentRawState.copyFrom(next);
if (mCurrentRawState.when < mLastRawState.when) {
mCurrentRawState.when = mLastRawState.when;
}
// 校準分發事件
cookAndDispatch(mCurrentRawState.when);
}
if (count != 0) {
// 移除處理完成的事件
mRawStatesPending.removeItemsAt(0, count);
}
......
}
下面看cookAndDispatch()
的實現
void TouchInputMapper::cookAndDispatch(nsecs_t when) {
// Always start with a clean state.
mCurrentCookedState.clear();
......
// Cook pointer data. This call populates the mCurrentCookedState.cookedPointerData structure
// with cooked pointer data that has the same ids and indices as the raw data.
// The following code can use either the raw or cooked data, as needed.
// 校準原始事件數據存放到mCurrentCookedState, Up事件,pointer數為0無需校準
cookPointerData();
......
if (mDeviceMode == DEVICE_MODE_POINTER) {
......
} else {
......
if (!mCurrentMotionAborted) {
dispatchButtonRelease(when, policyFlags);
dispatchHoverExit(when, policyFlags);
// 分發Touch事件
dispatchTouches(when, policyFlags);
dispatchHoverEnterAndMove(when, policyFlags);
dispatchButtonPress(when, policyFlags);
}
}
......
// Copy current touch to last touch in preparation for the next cycle.
// 當前事件處理完成,拷貝至mLastRawState及mLastCookedState
mLastRawState.copyFrom(mCurrentRawState);
mLastCookedState.copyFrom(mCurrentCookedState);
}
void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) {
// 當前事件的id掩碼
BitSet32 currentIdBits = mCurrentCookedState.cookedPointerData.touchingIdBits;
// 先前的事件的id掩碼
BitSet32 lastIdBits = mLastCookedState.cookedPointerData.touchingIdBits;
int32_t metaState = getContext()->getGlobalMetaState();
int32_t buttonState = mCurrentCookedState.buttonState;
if (currentIdBits == lastIdBits) {
if (!currentIdBits.isEmpty()) {
// id掩碼相等且非零,那么current為Move事件
// No pointer id changes so this is a move event.
// The listener takes care of batching moves so we don't have to deal with that here.
dispatchMotion(when, policyFlags, mSource,
AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState,
AMOTION_EVENT_EDGE_FLAG_NONE,
mCurrentCookedState.cookedPointerData.pointerProperties,
mCurrentCookedState.cookedPointerData.pointerCoords,
mCurrentCookedState.cookedPointerData.idToIndex,
currentIdBits, -1,
mOrientedXPrecision, mOrientedYPrecision, mDownTime);
}
} else {
// There may be pointers going up and pointers going down and pointers moving
// all at the same time.
// 考慮single pointer事件
// 1) Up事件(lastIdBits.value非0,currentIdBits.value為0)
// 2) Down事件(lastIdBits.value為0,currentIdBits.value非0)
BitSet32 upIdBits(lastIdBits.value & ~currentIdBits.value);
BitSet32 downIdBits(currentIdBits.value & ~lastIdBits.value);
BitSet32 moveIdBits(lastIdBits.value & currentIdBits.value);
BitSet32 dispatchedIdBits(lastIdBits.value);
......
// Dispatch pointer up events.
// 分發Up事件,這里注意Up事件信息使用mLastCookedState(例如,Up事件的坐標是前驅事件的坐標)
while (!upIdBits.isEmpty()) {
uint32_t upId = upIdBits.clearFirstMarkedBit();
dispatchMotion(when, policyFlags, mSource,
AMOTION_EVENT_ACTION_POINTER_UP, 0, 0, metaState, buttonState, 0,
mLastCookedState.cookedPointerData.pointerProperties,
mLastCookedState.cookedPointerData.pointerCoords,
mLastCookedState.cookedPointerData.idToIndex,
dispatchedIdBits, upId, mOrientedXPrecision, mOrientedYPrecision, mDownTime);
dispatchedIdBits.clearBit(upId);
}
......
// Dispatch pointer down events using the new pointer locations.
// 分發Down事件
while (!downIdBits.isEmpty()) {
uint32_t downId = downIdBits.clearFirstMarkedBit();
dispatchedIdBits.markBit(downId);
if (dispatchedIdBits.count() == 1) {
// First pointer is going down. Set down time.
mDownTime = when;
}
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);
}
}
}
下面看dispatchMotion()
的實現
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]);
if (changedId >= 0 && id == uint32_t(changedId)) {
action |= pointerCount << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
}
pointerCount += 1;
}
......
if (changedId >= 0 && pointerCount == 1) {
// Replace initial down and final up action.
// We can compare the action without masking off the changed pointer index
// because we know the index is 0.
// 修改single pointer Down/Up事件的action
if (action == AMOTION_EVENT_ACTION_POINTER_DOWN) {
action = AMOTION_EVENT_ACTION_DOWN;
} else if (action == AMOTION_EVENT_ACTION_POINTER_UP) {
action = AMOTION_EVENT_ACTION_UP;
} else {
// Can't happen.
ALOG_ASSERT(false);
}
}
// 向監聽者(QueuedInputListener)發送事件
NotifyMotionArgs args(when, getDeviceId(), source, policyFlags,
action, actionButton, flags, metaState, buttonState, edgeFlags,
mViewport.displayId, pointerCount, pointerProperties, pointerCoords,
xPrecision, yPrecision, downTime);
getListener()->notifyMotion(&args);
}
// NotifyMotionArgs存放到mArgsQueue容器中
void QueuedInputListener::notifyMotion(const NotifyMotionArgs* args) {
mArgsQueue.push(new NotifyMotionArgs(*args));
}
- PointerCoords 保存指尖坐標數據
- PointerProperties 保存指尖屬性信息
- NotifyMotionArgs 描述一個Motion事件,采用命令模式
這里QueuedInputListener
只是將事件封裝成NotifyArgs
存放到容器中。回到InputReader
的loopOnce()
中,驅動上報的事件都放到容器中后,QueuedInputListener
調用flush()
分發給InputDispatcher
。
void QueuedInputListener::flush() {
size_t count = mArgsQueue.size();
for (size_t i = 0; i < count; i++) {
NotifyArgs* args = mArgsQueue[i];
// mInnerListener為InputDispatcher
// 這里args為NotifyMotionArgs
args->notify(mInnerListener);
delete args;
}
mArgsQueue.clear();
}
void NotifyMotionArgs::notify(const sp<InputListenerInterface>& listener) const {
// 調用InputDispatcher的notifyMotion
listener->notifyMotion(this);
}
下面分析InputDispatcher
的notifyMotion()
void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) {
// 檢查MotionEvent是否合法
if (!validateMotionEvent(args->action, args->actionButton,
args->pointerCount, args->pointerProperties)) {
return;
}
uint32_t policyFlags = args->policyFlags;
policyFlags |= POLICY_FLAG_TRUSTED;
// mPolicy為NativeInputManager
// 檢查系統是否需要攔截事件
mPolicy->interceptMotionBeforeQueueing(args->eventTime, /*byref*/ policyFlags);
bool needWake;
{ // acquire lock
mLock.lock();
......
// Just enqueue a new motion event.
MotionEntry* newEntry = new MotionEntry(args->eventTime,
args->deviceId, args->source, policyFlags,
args->action, args->actionButton, args->flags,
args->metaState, args->buttonState,
args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime,
args->displayId,
args->pointerCount, args->pointerProperties, args->pointerCoords, 0, 0);
// MotionEntry放入InboundQueue中
needWake = enqueueInboundEventLocked(newEntry);
mLock.unlock();
} // release lock
if (needWake) {
// 喚醒InputDispatcher處理事件
mLooper->wake();
}
}
bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {
bool needWake = mInboundQueue.isEmpty();
// 事件放入InboundQueue tail
mInboundQueue.enqueueAtTail(entry);
// 更新systrace中iq信息
traceInboundQueueLengthLocked();
......
}
最終,InputReader
線程將事件放入InboundQueue中,如果有必要,喚醒InputDispatcher
線程處理事件。
小結
InputDispatcher發送MotionEvent到應用的過程
下面從InputDispatcher
的dispatchOnce()
開始分析
void InputDispatcher::dispatchOnce() {
nsecs_t nextWakeupTime = LONG_LONG_MAX;
{ // acquire lock
AutoMutex _l(mLock);
mDispatcherIsAliveCondition.broadcast();
// Run a dispatch loop if there are no pending commands.
// The dispatch loop might enqueue commands to run afterwards.
// 如果沒有待處理的命令,分發事件(此過程中可能產生命令)
if (!haveCommandsLocked()) {
dispatchOnceInnerLocked(&nextWakeupTime);
}
......
}
// Wait for callback or timeout or wake. (make sure we round up, not down)
nsecs_t currentTime = now();
int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime);
// 如果被喚醒,從此返回
mLooper->pollOnce(timeoutMillis);
}
下面看dispatchOnceInnerLocked()
的實現
void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
nsecs_t currentTime = now();
......
// If dispatching is frozen, do not process timeouts or try to deliver any new events.
// 事件分發凍住直接返回
if (mDispatchFrozen) {
#if DEBUG_FOCUS
ALOGD("Dispatch frozen. Waiting some more.");
#endif
return;
}
// Optimize latency of app switches.
// Essentially we start a short timeout when an app switch key (HOME / ENDCALL) has
// been pressed. When it expires, we preempt dispatch and drop all other pending events.
// 檢查app switch key處理是否超時
bool isAppSwitchDue = mAppSwitchDueTime <= currentTime;
if (mAppSwitchDueTime < *nextWakeupTime) {
*nextWakeupTime = mAppSwitchDueTime;
}
// Ready to start a new event.
// If we don't already have a pending event, go grab one.
if (! mPendingEvent) {
if (mInboundQueue.isEmpty()) {
......
} else {
// Inbound queue has at least one entry.
// 從InboundQueue中取出一個事件
mPendingEvent = mInboundQueue.dequeueAtHead();
// 更新systrace中iq信息
traceInboundQueueLengthLocked();
}
// Poke user activity for this event.
if (mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER) {
// 通知PowerManagerService更新電源狀態
pokeUserActivityLocked(mPendingEvent);
}
// Get ready to dispatch the event.
// 重置等待輸入目標超時信息
resetANRTimeoutsLocked();
}
......
switch (mPendingEvent->type) {
......
case EventEntry::TYPE_MOTION: {
MotionEntry* typedEntry = static_cast<MotionEntry*>(mPendingEvent);
if (dropReason == DROP_REASON_NOT_DROPPED && isAppSwitchDue) {
// app switch key事件處理超時,丟棄后續事件
dropReason = DROP_REASON_APP_SWITCH;
}
if (dropReason == DROP_REASON_NOT_DROPPED
&& isStaleEventLocked(currentTime, typedEntry)) {
// 丟棄已經超時失效的事件
dropReason = DROP_REASON_STALE;
}
if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) {
// 丟棄將要發送給不響應的應用的事件
dropReason = DROP_REASON_BLOCKED;
}
// 分發事件
done = dispatchMotionLocked(currentTime, typedEntry,
&dropReason, nextWakeupTime);
break;
}
......
}
if (done) {
// 分發結束清理
if (dropReason != DROP_REASON_NOT_DROPPED) {
dropInboundEventLocked(mPendingEvent, dropReason);
}
mLastDropReason = dropReason;
releasePendingEventLocked();
*nextWakeupTime = LONG_LONG_MIN; // force next poll to wake up immediately
}
}
下面分析dispatchMotionLocked()
實現
bool InputDispatcher::dispatchMotionLocked(
nsecs_t currentTime, MotionEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) {
// Preprocessing.
if (! entry->dispatchInProgress) {
// 標記正在分發事件
entry->dispatchInProgress = true;
logOutboundMotionDetailsLocked("dispatchMotion - ", entry);
}
// Clean up if dropping the event.
if (*dropReason != DROP_REASON_NOT_DROPPED) {
// 由于某種原因需要丟棄事件
setInjectionResultLocked(entry, *dropReason == DROP_REASON_POLICY
? INPUT_EVENT_INJECTION_SUCCEEDED : INPUT_EVENT_INJECTION_FAILED);
return true;
}
bool isPointerEvent = entry->source & AINPUT_SOURCE_CLASS_POINTER;
// Identify targets.
Vector<InputTarget> inputTargets;
bool conflictingPointerActions = false;
int32_t injectionResult;
if (isPointerEvent) {
// Pointer event. (eg. touchscreen)
// 查找InputTarget
// findTouchedWindowTargetsLocked的實現與WindowManagerService關系密切,這里
// 暫不詳細討論,另外它也處理應用不響應輸入ANR的情況
injectionResult = findTouchedWindowTargetsLocked(currentTime,
entry, inputTargets, nextWakeupTime, &conflictingPointerActions);
} else {
......
}
......
// 分發事件給inputTargets
dispatchEventLocked(currentTime, entry, inputTargets);
return true;
}
- InputTarget 描述如何將事件分發到特定的窗口,它包含目標窗口的InputChannel以及控制標志等
下面看dispatchEventLocked()
的實現
void InputDispatcher::dispatchEventLocked(nsecs_t currentTime,
EventEntry* eventEntry, const Vector<InputTarget>& inputTargets) {
#if DEBUG_DISPATCH_CYCLE
ALOGD("dispatchEventToCurrentInputTargets");
#endif
ALOG_ASSERT(eventEntry->dispatchInProgress); // should already have been set to true
pokeUserActivityLocked(eventEntry);
for (size_t i = 0; i < inputTargets.size(); i++) {
const InputTarget& inputTarget = inputTargets.itemAt(i);
ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel);
if (connectionIndex >= 0) {
// 通過InputChannel找到Connection
sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
// 分發事件
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().string());
#endif
}
}
}
void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) {
......
// Skip this event if the connection status is not normal.
// We don't want to enqueue additional outbound events if the connection is broken.
// 如果Connection的狀態異常,跳過事件
if (connection->status != Connection::STATUS_NORMAL) {
#if DEBUG_DISPATCH_CYCLE
ALOGD("channel '%s' ~ Dropping event because the channel status is %s",
connection->getInputChannelName(), connection->getStatusLabel());
#endif
return;
}
......
// Not splitting. Enqueue dispatch entries for the event as is.
// 分發事件
enqueueDispatchEntriesLocked(currentTime, connection, eventEntry, inputTarget);
}
void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime,
const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) {
bool wasEmpty = connection->outboundQueue.isEmpty();
......
// 事件封裝成DispatchEntry,放入Connection的OutboundQueue中,更新systrace中oq信息
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_IS);
......
// If the outbound queue was previously empty, start the dispatch cycle going.
// 如果之前Connection的OutboundQueue為空,啟動分發事件
if (wasEmpty && !connection->outboundQueue.isEmpty()) {
startDispatchCycleLocked(currentTime, connection);
}
}
下面看startDispatchCycleLocked()
的實現
void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
const sp<Connection>& connection) {
#if DEBUG_DISPATCH_CYCLE
ALOGD("channel '%s' ~ startDispatchCycle",
connection->getInputChannelName());
#endif
while (connection->status == Connection::STATUS_NORMAL
&& !connection->outboundQueue.isEmpty()) {
DispatchEntry* dispatchEntry = connection->outboundQueue.head;
dispatchEntry->deliveryTime = currentTime;
// Publish the event.
status_t status;
EventEntry* eventEntry = dispatchEntry->eventEntry;
switch (eventEntry->type) {
......
case EventEntry::TYPE_MOTION: {
MotionEntry* motionEntry = static_cast<MotionEntry*>(eventEntry);
PointerCoords scaledCoords[MAX_POINTERS];
const PointerCoords* usingCoords = motionEntry->pointerCoords;
......
// Publish the motion event.
// 通過socket將事件分發給應用
status = connection->inputPublisher.publishMotionEvent(dispatchEntry->seq,
motionEntry->deviceId, motionEntry->source,
dispatchEntry->resolvedAction, motionEntry->actionButton,
dispatchEntry->resolvedFlags, motionEntry->edgeFlags,
motionEntry->metaState, motionEntry->buttonState,
xOffset, yOffset, motionEntry->xPrecision, motionEntry->yPrecision,
motionEntry->downTime, motionEntry->eventTime,
motionEntry->pointerCount, motionEntry->pointerProperties,
usingCoords);
break;
}
default:
ALOG_ASSERT(false);
return;
}
......
// Re-enqueue the event on the wait queue.
// 從Connection的OutboundQueue中刪除事件
connection->outboundQueue.dequeue(dispatchEntry);
// 更新systrace中oq信息
traceOutboundQueueLengthLocked(connection);
// 事件添加到WaitQueue中
connection->waitQueue.enqueueAtTail(dispatchEntry);
// 更新systrace中wq信息
traceWaitQueueLengthLocked(connection);
}
}
至此,輸入事件從InputDispatcher
已經分發到應用。