android底层Input事件传递流程

android事件分发机制一文中介绍了应用层Touch事件的分发,那么Touch事件从哪里来的呢?

本文基于android9源码进行分析。

一、IMS

首先,触摸事件肯定需要驱动去接收,android是在/dev/input节点获取事件。由于WindowManagerService.java(后面简称WMS)负责界面窗口的管理,既然是屏幕事件那么肯定和WMS有关了,WMS是在SystemServer.java的startOtherServices方法中启动的,WMS的构造参数有InputManagerService(后面简称IMS)的实例,这样就把事件的生产者和消费者联系了起来。

//SystemServer.java

private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
    ……
    t.traceBegin("StartInputManagerService");
inputManager = new InputManagerService(context); //输入事件管理器
t.traceEnd();

t.traceBegin("StartWindowManagerService");
// WMS needs sensor service ready
ConcurrentUtils.waitForFutureNoInterrupt(mSensorServiceStart, START_SENSOR_SERVICE);
mSensorServiceStart = null;
//创建WindowManagerService
wm = WindowManagerService.main(context, inputManager, !mFirstBoot, mOnlyCore,
        new PhoneWindowManager(), mActivityManagerService.mActivityTaskManager);
ServiceManager.addService(Context.WINDOW_SERVICE, wm, /* allowIsolated= */ false,
        DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PROTO);//添加到路由器中,后面方便调用
ServiceManager.addService(Context.INPUT_SERVICE, inputManager,
        /* allowIsolated= */ false, DUMP_FLAG_PRIORITY_CRITICAL);//添加到路由器中,后面方便调用
t.traceEnd();

t.traceBegin("SetWindowManagerService");
mActivityManagerService.setWindowManager(wm); //WMS实例传入到AMS中
t.traceEnd();
    ……
}

先看下事件生产者IMS,根据代码注释知道IMS其实是InputManager.cpp的包装,IMS里面有很多native方法,其实就是调用InputManager.cpp本地方法的,jni调用方法在com_android_server_input_InputManagerService.cpp

//InputManagerService.java

/*
 * Wraps the C++ InputManager and provides its callbacks.
 */
public class InputManagerService extends IInputManager.Stub
        implements Watchdog.Monitor {
        ……
        public void start() {
    Slog.i(TAG, "Starting input manager");
    nativeStart(mPtr); //调用native的方法

    // Add ourself to the Watchdog monitors.
    Watchdog.getInstance().addMonitor(this);

    registerPointerSpeedSettingObserver();
    registerShowTouchesSettingObserver();
    registerAccessibilityLargePointerSettingObserver();
    registerLongPressTimeoutObserver();

    mContext.registerReceiver(new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            updatePointerSpeedFromSettings();
            updateShowTouchesFromSettings();
            updateAccessibilityLargePointerFromSettings();
            updateDeepPressStatusFromSettings("user switched");
        }
    }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mHandler);

    updatePointerSpeedFromSettings();
    updateShowTouchesFromSettings();
    updateAccessibilityLargePointerFromSettings();
    updateDeepPressStatusFromSettings("just booted");
}
 ……               
}
///frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp

NativeInputManager::NativeInputManager(jobject contextObj,
        jobject serviceObj, const sp<Looper>& looper) :
        mLooper(looper), mInteractive(true) {
    JNIEnv* env = jniEnv();
……
    sp<EventHub> eventHub = new EventHub(); //事件中心,获取/dev/input下的事件
    mInputManager = new InputManager(eventHub, this, this); //创建native层InputManager
}

看下InputManager.cpp,构造函数中有两个成员变量-事件分发者mDispatcher和事件输入者mReader、一个初始化方法initialize()。mDispatcher的构造函数参数有mDispatcher,这样生产者就持有消费者的引用,后面有输入事件了就可以调取消费者进行事件消费了。initialize()方法用于针对事件分发与事件输入分别创建了一个子线程,start()方法则去启动这两个子线程。

// /frameworks/native/services/inputflinger/InputManager.cpp
InputManager::InputManager(
        const sp<EventHubInterface>& eventHub,
        const sp<InputReaderPolicyInterface>& readerPolicy,
        const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
    mDispatcher = new InputDispatcher(dispatcherPolicy); //事件分发
    mReader = new InputReader(eventHub, readerPolicy, mDispatcher); //事件输入
    initialize(); //初始化
}
……
void InputManager::initialize() {
    mReaderThread = new InputReaderThread(mReader); //创建子线程
    mDispatcherThread = new InputDispatcherThread(mDispatcher); //创建子线程
}

status_t InputManager::start() {
    status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);
    if (result) {
        ALOGE("Could not start InputDispatcher thread due to error %d.", result);
        return result;
    }

    result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);
    if (result) {
        ALOGE("Could not start InputReader thread due to error %d.", result);

        mDispatcherThread->requestExit();
        return result;
    }

    return OK;
}

可以看出InputManager.cpp也就开启了两个子线程,并在子线程中去处理事件的生产和消费,实际上InputReaderThread和InputDispatcherThread分别定义在InputReader.cpp和InputDispatcher.cpp中。

二、InputReader

先看下事件生产者InputReader,当InputReaderThread开始启动的时候,就会调用InputReader.loopOnce()方法。

// /frameworks/native/services/inputflinger/InputReader.cpp --- InputReaderThread ---

InputReaderThread::InputReaderThread(const sp<InputReaderInterface>& reader) :
        Thread(/*canCallJava*/ true), mReader(reader) {
}

InputReaderThread::~InputReaderThread() {
}

bool InputReaderThread::threadLoop() {
    mReader->loopOnce(); //开始循环处理消息
    return true;
}

那就看下mReader->loopOnce()的具体实现,loopOnce()根据mEventHub->getEvents取到输入事件,然后调用mQueuedListener->flush()通知消费者。

///frameworks/native/services/inputflinger/InputReader.cpp

void InputReader::loopOnce() {
    int32_t oldGeneration;
    int32_t timeoutMillis;
    bool inputDevicesChanged = false;
    Vector<InputDeviceInfo> inputDevices;
    { // acquire lock
        AutoMutex _l(mLock);
……
    size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);

    { // acquire lock
        AutoMutex _l(mLock);
        mReaderIsAliveCondition.broadcast();

        if (count) {
            processEventsLocked(mEventBuffer, count);
        }

        if (mNextTimeout != LLONG_MAX) {
            nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
            if (now >= mNextTimeout) {
#if DEBUG_RAW_EVENTS
                ALOGD("Timeout expired, latency=%0.3fms", (now - mNextTimeout) * 0.000001f);
#endif
                mNextTimeout = LLONG_MAX;
                timeoutExpiredLocked(now);
            }
        }

        if (oldGeneration != mGeneration) {
            inputDevicesChanged = true;
            getInputDevicesLocked(inputDevices);
        }
    } // release lock

    // Send out a message that the describes the changed input devices.
    if (inputDevicesChanged) {
        mPolicy->notifyInputDevicesChanged(inputDevices);
    }

    // Flush queued events out to the listener.
    // This must happen outside of the lock because the listener could potentially call
    // back into the InputReader's methods, such as getScanCodeState, or become blocked
    // on another thread similarly waiting to acquire the InputReader lock thereby
    // resulting in a deadlock.  This situation is actually quite plausible because the
    // listener is actually the input dispatcher, which calls into the window manager,
    // which occasionally calls into the input reader.
    mQueuedListener->flush(); //通知消费者
}

EventHub.cpp就是从"/dev/input"获取各种设备输入事件并计数。

///frameworks/native/services/inputflinger/EventHub.cpp
……
static const char *WAKE_LOCK_ID = "KeyEvents";
static const char *DEVICE_PATH = "/dev/input";
……
EventHub::EventHub(void) :
        mBuiltInKeyboardId(NO_BUILT_IN_KEYBOARD), mNextDeviceId(1), mControllerNumbers(),
        mOpeningDevices(0), mClosingDevices(0),
        mNeedToSendFinishedDeviceScan(false),
        mNeedToReopenDevices(false), mNeedToScanDevices(true),
        mPendingEventCount(0), mPendingEventIndex(0), mPendingINotify(false) {
    acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);

    mEpollFd = epoll_create(EPOLL_SIZE_HINT);
    LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance.  errno=%d", errno);

    mINotifyFd = inotify_init();
    int result = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE);
    LOG_ALWAYS_FATAL_IF(result < 0, "Could not register INotify for %s.  errno=%d",
            DEVICE_PATH, errno);

    struct epoll_event eventItem;
    memset(&eventItem, 0, sizeof(eventItem));
    eventItem.events = EPOLLIN;
    eventItem.data.u32 = EPOLL_ID_INOTIFY;
    result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem);
……
}
……
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 (;;) {
       nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);

       // Reopen input devices if needed.
       if (mNeedToReopenDevices) {
           mNeedToReopenDevices = false;

           ALOGI("Reopening all input devices due to a configuration change.");

           closeAllDevicesLocked();
           mNeedToScanDevices = true;
           break; // return to the caller before we actually rescan
       }

       // Report any devices that had last been added/removed.
       while (mClosingDevices) {  
           Device* device = mClosingDevices;
           ALOGV("Reporting device closed: id=%d, name=%s\n",
                device->id, device->path.string());
           mClosingDevices = device->next;
           event->when = now;
           event->deviceId = device->id == mBuiltInKeyboardId ? BUILT_IN_KEYBOARD_ID : device->id;
           event->type = DEVICE_REMOVED;  //关闭设备类型
           event += 1;
           delete device;
           mNeedToSendFinishedDeviceScan = true;
           if (--capacity == 0) {
               break;
           }
       }

 ……
}

 

再看下刚才通知mQueuedListener->flush()的具体实现,实际上就是通过命令模式根据不同种类的通知命令去调用对应的方法。本文研究的是触摸事件,就会调用触摸的通知,listener->notifyMotion(this)就会调用到InputDispatcher.cpp中的notifyMotion方法。

///frameworks/native/services/inputflinger/InputListener.cpp
……
// --- NotifyMotionArgs ---手势触摸事件

NotifyMotionArgs::NotifyMotionArgs(nsecs_t eventTime, int32_t deviceId, uint32_t source,
        uint32_t policyFlags,
        int32_t action, int32_t actionButton, int32_t flags, int32_t metaState,
        int32_t buttonState, int32_t edgeFlags, int32_t displayId, uint32_t deviceTimestamp,
        uint32_t pointerCount,
        const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
        float xPrecision, float yPrecision, nsecs_t downTime) :
        eventTime(eventTime), deviceId(deviceId), source(source), policyFlags(policyFlags),
        action(action), actionButton(actionButton),
        flags(flags), metaState(metaState), buttonState(buttonState),
        edgeFlags(edgeFlags), displayId(displayId), deviceTimestamp(deviceTimestamp),
        pointerCount(pointerCount),
        xPrecision(xPrecision), yPrecision(yPrecision), downTime(downTime) {
    for (uint32_t i = 0; i < pointerCount; i++) {
        this->pointerProperties[i].copyFrom(pointerProperties[i]);
        this->pointerCoords[i].copyFrom(pointerCoords[i]);
    }
}

NotifyMotionArgs::NotifyMotionArgs(const NotifyMotionArgs& other) :
        eventTime(other.eventTime), deviceId(other.deviceId), source(other.source),
        policyFlags(other.policyFlags),
        action(other.action), actionButton(other.actionButton), flags(other.flags),
        metaState(other.metaState), buttonState(other.buttonState),
        edgeFlags(other.edgeFlags), displayId(other.displayId),
        deviceTimestamp(other.deviceTimestamp), pointerCount(other.pointerCount),
        xPrecision(other.xPrecision), yPrecision(other.yPrecision), downTime(other.downTime) {
    for (uint32_t i = 0; i < pointerCount; i++) {
        pointerProperties[i].copyFrom(other.pointerProperties[i]);
        pointerCoords[i].copyFrom(other.pointerCoords[i]);
    }
}

void NotifyMotionArgs::notify(const sp<InputListenerInterface>& listener) const {
    listener->notifyMotion(this);
}


// --- NotifySwitchArgs ---开关事件

NotifySwitchArgs::NotifySwitchArgs(nsecs_t eventTime, uint32_t policyFlags,
        uint32_t switchValues, uint32_t switchMask) :
        eventTime(eventTime), policyFlags(policyFlags),
        switchValues(switchValues), switchMask(switchMask) {
}

NotifySwitchArgs::NotifySwitchArgs(const NotifySwitchArgs& other) :
        eventTime(other.eventTime), policyFlags(other.policyFlags),
        switchValues(other.switchValues), switchMask(other.switchMask) {
}

void NotifySwitchArgs::notify(const sp<InputListenerInterface>& listener) const {
    listener->notifySwitch(this);
}
……
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();
}

三、InputDispatcher

上面通过listener->notifyMotion(this)调用到InputDispatcher中来了,之前说过在InputManager.cpp中会创建InputDispatcher实例以及InputDispatcherThread实例并启动该子线程。和InputReaderThread类似,InputDispatcherThread启动后会调用对应的InputDispatcher的loopOnce()方法。

///frameworks/native/services/inputflinger/InputDispatcher.cpp --- InputDispatcherThread ---

InputDispatcherThread::InputDispatcherThread(const sp<InputDispatcherInterface>& dispatcher) :
        Thread(/*canCallJava*/ true), mDispatcher(dispatcher) {
}

InputDispatcherThread::~InputDispatcherThread() {
}

bool InputDispatcherThread::threadLoop() {
    mDispatcher->dispatchOnce();
    return true;
}

再看下mDispatcher->dispatchOnce()的具体实现,可以看到如果没有命令需要执行则去进行事件分发。dispatchOnceInnerLocked方法中省略的部分是一些条件判断,然后对不同的事件类型进行处理,本文只保留了TYPE_MOTION事件。

///frameworks/native/services/inputflinger/InputDispatcher.cpp
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); //事件分发
        }

        // Run all pending commands if there are any.
        // If any commands were run then force the next poll to wake up immediately.
        if (runCommandsLockedInterruptible()) {
            nextWakeupTime = LONG_LONG_MIN;
        }
    } // release lock

    // 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);
}

void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
    nsecs_t currentTime = now();

 ……

    case EventEntry::TYPE_MOTION: {
        MotionEntry* typedEntry = static_cast<MotionEntry*>(mPendingEvent);
        if (dropReason == DROP_REASON_NOT_DROPPED && isAppSwitchDue) {
            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;
    }

……
}

继续看下dispatchMotionLocked方法,先去获取事件窗口(触摸窗口或者焦点窗口),然后将事件分发给对应的窗口。

///frameworks/native/services/inputflinger/InputDispatcher.cpp
bool InputDispatcher::dispatchMotionLocked(
        nsecs_t currentTime, MotionEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) {
    ……
    if (isPointerEvent) {
        // Pointer event.  (eg. touchscreen)
        injectionResult = findTouchedWindowTargetsLocked(currentTime,
                entry, inputTargets, nextWakeupTime, &conflictingPointerActions);  //获取触摸窗口
    } else {
        // Non touch event.  (eg. trackball)
        injectionResult = findFocusedWindowTargetsLocked(currentTime,
                entry, inputTargets, nextWakeupTime); //获取焦点窗口
    }
 ……
    dispatchEventLocked(currentTime, entry, inputTargets);
    return true;
}

看下获取触摸窗口方法findTouchedWindowTargetsLocked的具体实现,实际上就是根据不同的事件类型获取新的窗口,这里注意到有一个成员变量mWindowHandles,mWindowHandles从何而来呢?

///frameworks/native/services/inputflinger/InputDispatcher.cpp
int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
        const MotionEntry* entry, Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime,
        bool* outConflictingPointerActions) {
   ……

    if (newGesture || (isSplit && maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN)) {
        /* Case 1: New splittable pointer going down, or need target for hover or scroll. */

        int32_t pointerIndex = getMotionEventActionPointerIndex(action);
        int32_t x = int32_t(entry->pointerCoords[pointerIndex].
                getAxisValue(AMOTION_EVENT_AXIS_X));
        int32_t y = int32_t(entry->pointerCoords[pointerIndex].
                getAxisValue(AMOTION_EVENT_AXIS_Y));
        sp<InputWindowHandle> newTouchedWindowHandle;
        bool isTouchModal = false;

        // Traverse windows from front to back to find touched window and outside targets.
        size_t numWindows = mWindowHandles.size();  
        for (size_t i = 0; i < numWindows; i++) {
            sp<InputWindowHandle> windowHandle = mWindowHandles.itemAt(i);  //循环获取窗口
            const InputWindowInfo* windowInfo = windowHandle->getInfo();
            if (windowInfo->displayId != displayId) {
                continue; // wrong display
            }

            int32_t flags = windowInfo->layoutParamsFlags;
            if (windowInfo->visible) {
                if (! (flags & InputWindowInfo::FLAG_NOT_TOUCHABLE)) {
                    isTouchModal = (flags & (InputWindowInfo::FLAG_NOT_FOCUSABLE
                            | InputWindowInfo::FLAG_NOT_TOUCH_MODAL)) == 0;
                    if (isTouchModal || windowInfo->touchableRegionContainsPoint(x, y)) {
                        newTouchedWindowHandle = windowHandle;
                        break; // found touched window, exit window loop
                    }
                }

                if (maskedAction == AMOTION_EVENT_ACTION_DOWN
                        && (flags & InputWindowInfo::FLAG_WATCH_OUTSIDE_TOUCH)) {
                    mTempTouchState.addOrUpdateWindow(
                            windowHandle, InputTarget::FLAG_DISPATCH_AS_OUTSIDE, BitSet32(0));
                }
            }
        }

……
}

通过查找代码可以发现是通过InputDispatcher.cpp的void InputDispatcher::setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles)方法赋值的。

ViewRootImpl.javasetView(View view, WindowManager.LayoutParams attrs, View panelParentView)方法中Session.javaaddToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame, Rect outContentInsets, Rect outStableInsets, Rect outOutsets, DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel) 方法,Session.addToDisplay方法调用了的WindowManagerService.java(后面简称WMS)的public int addWindow(Session session, IWindow client, int seq, LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame, Rect outContentInsets, Rect outStableInsets, Rect outOutsets, DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel),接着WMS. addWindow方法中调用了 InputMonitor.java的void updateInputWindowsLw(boolean force)方法,InputMonitor.updateInputWindowsLw调用了IMS的public void setInputWindows(InputWindowHandle[] windowHandles, InputWindowHandle focusedWindowHandle)方法,IMS.setInputWindows通过jni调用了com_android_server_input_InputManagerService.cpp的void NativeInputManager::setInputWindows(JNIEnv* env, jobjectArray windowHandleObjArray)方法,com_android_server_input_InputManagerService.setInputWindows调用了InputDispatcher.cpp的void InputDispatcher::setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles)方法。也就是说WMS每增加一个窗口,底层消费者InputDispatcher.cpp将窗口列表保存在成员变量mWindowHandles中,焦点窗口保存在成员变量mFocusedWindowHandle中。

findTouchedWindowTargetsLocked方法找到目标窗口后,如果目标窗口存在(getConnectionIndexLocked(inputTarget.inputChannel)>= 0),dispatchEventLocked方法会调用prepareDispatchCycleLocked方法开始分发,接着调用enqueueDispatchEntriesLocked方法,最终调用startDispatchCycleLocked方法。

///frameworks/native/services/inputflinger/InputDispatcher.cpp
void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime,
        const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) {
……

    // If the outbound queue was previously empty, start the dispatch cycle going.
    if (wasEmpty && !connection->outboundQueue.isEmpty()) {
        startDispatchCycleLocked(currentTime, connection);
    }
}

……
void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
        const sp<Connection>& connection) {
……
        switch (eventEntry->type) {
……

        case EventEntry::TYPE_MOTION: {
            MotionEntry* motionEntry = static_cast<MotionEntry*>(eventEntry);

            PointerCoords scaledCoords[MAX_POINTERS];
            const PointerCoords* usingCoords = motionEntry->pointerCoords;

            // Set the X and Y offset depending on the input source.
            float xOffset, yOffset;
            if ((motionEntry->source & AINPUT_SOURCE_CLASS_POINTER)
                    && !(dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS)) {
                float scaleFactor = dispatchEntry->scaleFactor;
                xOffset = dispatchEntry->xOffset * scaleFactor;
                yOffset = dispatchEntry->yOffset * scaleFactor;
                if (scaleFactor != 1.0f) {
                    for (uint32_t i = 0; i < motionEntry->pointerCount; i++) {
                        scaledCoords[i] = motionEntry->pointerCoords[i];
                        scaledCoords[i].scale(scaleFactor);
                    }
                    usingCoords = scaledCoords;
                }
            } else {
                xOffset = 0.0f;
                yOffset = 0.0f;

                // We don't want the dispatch target to know.
                if (dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS) {
                    for (uint32_t i = 0; i < motionEntry->pointerCount; i++) {
                        scaledCoords[i].clear();
                    }
                    usingCoords = scaledCoords;
                }
            }

            // Publish the motion event.
            status = connection->inputPublisher.publishMotionEvent(dispatchEntry->seq,
                    motionEntry->deviceId, motionEntry->source, motionEntry->displayId,
                    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;
        }

 ……
    }
}

connection->inputPublisher.publishMotionEvent会执行到InputTransport.cpp的InputTransport.cpp方法,在该方法中封装了InputMessage对象并通过mChannel发送出去,mChannel从哪里来的呢?

///frameworks/native/libs/input/InputTransport.cpp
status_t InputPublisher::publishMotionEvent(
        uint32_t seq,
        int32_t deviceId,
        int32_t source,
        int32_t displayId,
        int32_t action,
        int32_t actionButton,
        int32_t flags,
        int32_t edgeFlags,
        int32_t metaState,
        int32_t buttonState,
        float xOffset,
        float yOffset,
        float xPrecision,
        float yPrecision,
        nsecs_t downTime,
        nsecs_t eventTime,
        uint32_t pointerCount,
        const PointerProperties* pointerProperties,
        const PointerCoords* pointerCoords) {
      ……

    InputMessage msg;
    msg.header.type = InputMessage::TYPE_MOTION;
    msg.body.motion.seq = seq;
    msg.body.motion.deviceId = deviceId;
    msg.body.motion.source = source;
    msg.body.motion.displayId = displayId;
    msg.body.motion.action = action;
    msg.body.motion.actionButton = actionButton;
    msg.body.motion.flags = flags;
    msg.body.motion.edgeFlags = edgeFlags;
    msg.body.motion.metaState = metaState;
    msg.body.motion.buttonState = buttonState;
    msg.body.motion.xOffset = xOffset;
    msg.body.motion.yOffset = yOffset;
    msg.body.motion.xPrecision = xPrecision;
    msg.body.motion.yPrecision = yPrecision;
    msg.body.motion.downTime = downTime;
    msg.body.motion.eventTime = eventTime;
    msg.body.motion.pointerCount = pointerCount;
    for (uint32_t i = 0; i < pointerCount; i++) {
        msg.body.motion.pointers[i].properties.copyFrom(pointerProperties[i]);
        msg.body.motion.pointers[i].coords.copyFrom(pointerCoords[i]);
    }
    return mChannel->sendMessage(&msg);  //mChannel发送消息
}

 通过查看InputTransport.h可以看出mChannel是一个InputChannel对象,上面在梳理获取目标窗口的流程中有提到ViewRootImpl.setView调用了Session.java的addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,

int viewVisibility, int displayId, Rect outFrame, Rect outContentInsets,

Rect outStableInsets, Rect outOutsets,

DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel) 方法,addToDisplay方法的第四个参数就有一个InputChannel对象。ViewRootImpl.setView创建了一个InputChannel对象inputChannel,将inputChannel作为参数传给Session.addToDisplay,紧接着创建了一个WindowInputEventReceiver对象mInputEventReceiver,并将inputChannel作为传给mInputEventReceiver,mInputEventReceiver实际上就是输入事件接收者。InputTransport.cpp中mChannel->sendMessage(&msg)发送的消息通过jni调用会被mInputEventReceiver的dispatchInputEvent(int seq, InputEvent event, int displayId)方法接收到,进而调用enqueueInputEvent(event, this, 0, true)方法.

四、ViewRootImpl

   ///frameworks/base/core/java/android/view/ViewRootImpl.java
    
    void enqueueInputEvent(InputEvent event,
            InputEventReceiver receiver, int flags, boolean processImmediately) {
   ……
        if (processImmediately) {
            doProcessInputEvents(); //立即执行
        } else {
            scheduleProcessInputEvents(); //异步执行
        }
    }

直接看doProcessInputEvents方法吧,该方法调用deliverInputEvent(q)方法

    ///frameworks/base/core/java/android/view/ViewRootImpl.java
    
    private void deliverInputEvent(QueuedInputEvent q) {
        Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent",
                q.mEvent.getSequenceNumber());
        if (mInputEventConsistencyVerifier != null) {
            mInputEventConsistencyVerifier.onInputEvent(q.mEvent, 0);
        }

        InputStage stage;
        if (q.shouldSendToSynthesizer()) {
            stage = mSyntheticInputStage;
        } else {
            stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
        }

        if (q.mEvent instanceof KeyEvent) {
            mUnhandledKeyManager.preDispatch((KeyEvent) q.mEvent);
        }

        if (stage != null) {
            handleWindowFocusChanged();
            stage.deliver(q);
        } else {
            finishInputEvent(q);
        }
    }

deliverInputEvent方法主要执行了stage.deliver方法,InputStage从何而来呢?在ViewRootImpl.setView方法的最后有创建不同类型的InputStage,InputStage定义了方法模板,不同种类的InputStage都有不同的实现方式与应用场景。 通过链表将不同种类的InputStage串联起来,这是一个典型的责任链模式。

        ///frameworks/base/core/java/android/view/ViewRootImpl.java
    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
	……
	                // Set up the input pipeline.
                CharSequence counterSuffix = attrs.getTitle();
                mSyntheticInputStage = new SyntheticInputStage();
                InputStage viewPostImeStage = new ViewPostImeInputStage(mSyntheticInputStage);
                InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage,
                        "aq:native-post-ime:" + counterSuffix);
                InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage);
                InputStage imeStage = new ImeInputStage(earlyPostImeStage,
                        "aq:ime:" + counterSuffix);
                InputStage viewPreImeStage = new ViewPreImeInputStage(imeStage);
                InputStage nativePreImeStage = new NativePreImeInputStage(viewPreImeStage,
                        "aq:native-pre-ime:" + counterSuffix);

                mFirstInputStage = nativePreImeStage;
                mFirstPostImeInputStage = earlyPostImeStage;
                mPendingInputEventQueueLengthCounterName = "aq:pending:" + counterSuffix;
            }
        }
    }
    ……
        /**
     * Delivers pre-ime input events to a native activity.
     * Does not support pointer events.  将未经输入法处理的事件传给native activity,不支持触摸事件
     */
    final class NativePreImeInputStage extends AsyncInputStage

    /**
     * Delivers pre-ime input events to the view hierarchy.
     * Does not support pointer events.  将未经输入法处理的事件传给视图层级,不支持触摸事件
     */
    final class ViewPreImeInputStage extends InputStage {

    /**
     * Performs early processing of post-ime input events.  后处理输入法事件
     */
    final class EarlyPostImeInputStage extends InputStage {

    /**
     * Delivers input events to the ime.
     * Does not support pointer events.  将输入事件传给输入法,,不支持触摸事件
     */
    final class ImeInputStage extends AsyncInputStage

    /**
     * Delivers post-ime input events to a native activity.  将输入法处理后的事件传给native activity
     */
    final class NativePostImeInputStage extends AsyncInputStage

    /**
     * Delivers post-ime input events to the view hierarchy.  将输入法处理后的事件传给视图层级
     */
    final class ViewPostImeInputStage extends InputStage {
    
    
 ///frameworks/base/core/java/android/view/ViewRootImpl.java
           /**
         * Delivers an event to be processed.
         */
        public final void deliver(QueuedInputEvent q) {
            if ((q.mFlags & QueuedInputEvent.FLAG_FINISHED) != 0) {
                forward(q);
            } else if (shouldDropInputEvent(q)) {
                finish(q, false);
            } else {
                apply(q, onProcess(q));
            }
        }

 

针对触摸事件我们主要还是看ViewPostImeInputStage类型吧。

 ///frameworks/base/core/java/android/view/ViewRootImpl.java
	
	/**
     * Delivers post-ime input events to the view hierarchy.
     */
    final class ViewPostImeInputStage extends InputStage {
        public ViewPostImeInputStage(InputStage next) {
            super(next);
        }

        @Override
        protected int onProcess(QueuedInputEvent q) {
            if (q.mEvent instanceof KeyEvent) {
                return processKeyEvent(q);
            } else {
                final int source = q.mEvent.getSource();
                if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
                    return processPointerEvent(q); //触摸事件
                } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
                    return processTrackballEvent(q); //轨迹球事件
                } else {
                    return processGenericMotionEvent(q);   //其他事件
                }
            }
        }
        ……
   private int processPointerEvent(QueuedInputEvent q) {
            final MotionEvent event = (MotionEvent)q.mEvent;

            mAttachInfo.mUnbufferedDispatchRequested = false;
            mAttachInfo.mHandlingPointerEvent = true;
            boolean handled = mView.dispatchPointerEvent(event); //mView一般是DecorView
            maybeUpdatePointerIcon(event);
            maybeUpdateTooltip(event);
            mAttachInfo.mHandlingPointerEvent = false;
            if (mAttachInfo.mUnbufferedDispatchRequested && !mUnbufferedInputDispatch) {
                mUnbufferedInputDispatch = true;
                if (mConsumeBatchedInputScheduled) {
                    scheduleConsumeBatchedInputImmediately();
                }
            }
            return handled ? FINISH_HANDLED : FORWARD;
        }

事件传给了DecorView的dispatchPointerEvent方法去处理,最终走到了我们熟悉的View.dispatchTouchEvent方法。

    ///frameworks/base/core/java/android/view/View.java
	/**
     * Dispatch a pointer event.
     * <p>
     * Dispatches touch related pointer events to {@link #onTouchEvent(MotionEvent)} and all
     * other events to {@link #onGenericMotionEvent(MotionEvent)}.  This separation of concerns
     * reinforces the invariant that {@link #onTouchEvent(MotionEvent)} is really about touches
     * and should not be expected to handle other pointing device features.
     * </p>
     *
     * @param event The motion event to be dispatched.
     * @return True if the event was handled by the view, false otherwise.
     * @hide
     */
    public final boolean dispatchPointerEvent(MotionEvent event) {
        if (event.isTouchEvent()) {
            return dispatchTouchEvent(event);
        } else {
            return dispatchGenericMotionEvent(event);
        }
    }

 

 

 

 

 

 

 

 

 

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值