Input event -- InputManagerServie

输入事件派发内容比较多,只记其大概; 分两篇,本篇是InputManagerService相关,另外一篇是事件在View体系中的派发。
本篇分四部分:

  1. InputManagerService的启动
  2. InputReaderThread 和 InputDispatcherThread
  3. InputChannel
  4. Input event的拦截

1. InputManagerService的启动

SystemServer启动的时候会在startOtherServices方法中创建InputManagerService对象,调用addService@ServiceManager方法将这个对象作为“input”系统服务的server端,并调用start@InputManagerService方法开启服务。
相关代码如下:

            ......
            traceBeginAndSlog("StartInputManagerService");
            inputManager = new InputManagerService(context);//构造InputManagerService对象
            traceEnd();

            traceBeginAndSlog("StartWindowManagerService");
            // WMS needs sensor service ready
            ConcurrentUtils.waitForFutureNoInterrupt(mSensorServiceStart, START_SENSOR_SERVICE);
            mSensorServiceStart = null;
            wm = WindowManagerService.main(context, inputManager,
                    mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
                    !mFirstBoot, mOnlyCore, new PhoneWindowManager());
            ServiceManager.addService(Context.WINDOW_SERVICE, wm, /* allowIsolated= */ false,
                    DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PROTO);//添加到ServiceManager中。
            ServiceManager.addService(Context.INPUT_SERVICE, inputManager,
                    /* allowIsolated= */ false, DUMP_FLAG_PRIORITY_CRITICAL);
            traceEnd();

            ......
            
            inputManager.setWindowManagerCallbacks(wm.getInputMonitor());//设置CallBack: InputMonitor
            inputManager.start();

下面是与代码相对应的流程图,也包括了WindowManagerService注册InputChannel的流程。
在这里插入图片描述
先看第一部分InputManagerService的初始化。InputManagerService的构造函数会调用nativeInit(…)方法,对应的JNI层方法是com_android_server_input_InputManagerService.cpp中的nativeInit(…)
JNI层的*nativeInit(…)*方法会构造NativeInputManager对象,而后者会构造EventHub和InputManager对象。InputManager会构造InputDispatcher,InputReader,InputDispatcherThread以及InputReaderThread对象。


2. InputReaderThread 和 InputDispatcherThread

如上图第三部分所示,当SystemServer调用了新构造InputManagerService对象的start方法后,InputReaderThread和InputDispatcherThread两个线程就开始运行,分别负责完成对输入事件的读取和派发工作。
InputReaderThreadInputDispatcherThread都继承了Thread,这个Thread类的定义是在"
system/core/libutils/Threads.cpp",InputReaderThread和InputDispatcherThread都覆盖了Thread.cpp中的threadLoop方法。[email protected]方法会调用InputReaderThread和InputDispatcherThread的run方法,在Thread.cpp中run方法会调用_threadLoop方法,这个方法有个do{}while循环,threadLoop方法会在循环体中被调用,InputReaderThread和InputDispatcherThread通过重写threadLoop方法实现各自的功能; threadLoop@InputReaderThread调用了loopOnce@InputReader方法,threadLoop@InputDispatcherThread调用了dispatchOnce@InputDispatcher方法。

2.1 loopOnce@InputReader方法

InputReader的loopOnce方法如下:

void InputReader::loopOnce() {
    int32_t oldGeneration;
    int32_t timeoutMillis;
    bool inputDevicesChanged = false;
    Vector<InputDeviceInfo> inputDevices;
    { // acquire lock
      AutoMutex _l(mLock);
      //省略部分代码,这部分代码用于获取时间等操作。
      ......
    } // release lock

    //获取event数量
    size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);

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

        if (count) {//如果有event,那么调用processEventsLocked方法进行处理。
            processEventsLocked(mEventBuffer, count);
        }
        //省略部分代码
        ......
        
        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);
    }

    //下面这句代码用于通知Listener InputDispatcher,InputDispatcher的notifyKey/notifyMotion方法会被调用。
    // 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();
}

InputReader的loopOnce方法会从EventHub中获取Event数量,如果有event需要处理,那么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) {//普通的输入event
            int32_t deviceId = rawEvent->deviceId;
            while (batchSize < count) {
                if (rawEvent[batchSize].type >= EventHubInterface::FIRST_SYNTHETIC_EVENT
                        || rawEvent[batchSize].deviceId != deviceId) {
                    break;
                }
                batchSize += 1;
            }
#if DEBUG_RAW_EVENTS
            ALOGD("BatchSize: %zu Count: %zu", batchSize, count);
#endif
            processEventsForDeviceLocked(deviceId, rawEvent, batchSize);
        } else {//输入设备相关的event
            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;
    }
}

processEventsLocked中if{}else{}将处理逻辑分成了两大部分:
一部分处理普通的输入event。
另外一部分处理输入设备相关的event(输入设备增加、移除和scan)。
InputReader会先收到输入设备相关的event,并添加/移除对应的设备对象InputDevice,然后将后续收到的输入event交给InputDevice处理。
InputReader收到新输入设备增加的"EventHubInterface::DEVICE_ADDED"后,会调用addDeviceLocked方法,此方法会调用createDeviceLocked方法构造InputDevice对象,并根据收到的设备属性为InputDevice对象构造InputMapper,有KeyboardInputMapper、SingleTouchInputMapper等,这些InputMapper对象会被存放到InputDevice对象的成员集合mMappers中保存; 新得到的InputDevice对象会放到InputReader的成员集合mDevices中保存(Map集合,deviceId做Key)。
InputReader收到普通输入事件后会调用processEventsForDeviceLocked方法进行处理,该方法会遍历mDevices,调用InputDevice的process方法处理event。 InputDevice的process方法会遍历mMappers,调用InputMapper的process方法处理event。不同InputMapper的process的方法处理逻辑不同,但是正常情况都会调用到Listener的notifyKey/notifyMotion方法,即InputDispatcher的notifyKey/notifyMotion 方法(InputDispatcher间接继承了InputListenerInterface类,构造InputReader对象时,InputDispatcher对象会作为一个参数(Listener)传入InputReader中)。 notifyKey/notifyMotion方法会调用enqueueInboundEventLocked方法将event加入到mInboundQueue队列中,如果有需要还会唤醒Looper; 另外nofifyKey方法在将event放进队列之前会调用NativeInputManager的interceptKeyBeforeQueueing方法,notifyMotion会调用NativeInputManager的interceptMotionBeforeQueueing方法。

2.2. dispatchOnce@InputDispatcher方法

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

        // 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);
}
  • 如果没有pending commands,那么就调用dispatchOnceInnerLocked方法,该方法最终通过InputPublisher调用InputChannel的sendMessage方法。
  • 如果有pending commands,那么会先运行commands;这些commands是什么呢?
    pending commands存放在mCommandQueue中,其中元素是CommandEntry类型的指针,指向的都是函数地址,这样就可以通过指针调用函数,比如doInterceptKeyBeforeDispatchingLockedInterruptible函数就是以这种方式调用的。如果command被执行,那么Loop中的pollOnce方法会立即被调用。

InputDispatcher派发过程中调用的主要方法如下:

dispatchOnceInnerLocked
|-->dispatchMotionLocked/dispatchKeyLocked
   |-->dispatchEventLocked
      |-->prepareDispatchCycleLocked
         |-->enqueueDispatchEntriesLocked
            |-->startDispatchCycleLocked

但是这些event要派发给那些Window呢,这是InputDispatcher要解决的问题?
新窗口添加的时候,[email protected]方法会构建WindowState对象,后者会构建InputWindowHandle对象,这个对象会通过openInputChannel@WindowState方法注册到InputDispatcher中,如下:

    void openInputChannel(InputChannel outInputChannel) {
        ......
        InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
        mInputChannel = inputChannels[0];
        mClientChannel = inputChannels[1];
        mInputWindowHandle.inputChannel = inputChannels[0];
        ......
        mService.mInputManager.registerInputChannel(mInputChannel, mInputWindowHandle);
    }

另外,[email protected]方法会调用InputMonitor.java的updateInputWindowsLw方法,后者会调用"mUpdateInputForAllWindowsConsumer.updateInputWindows(inDrag)";
mUpdateInputForAllWindowsConsumer是UpdateInputForAllWindowsConsumer类型的对象,updateInputWindows方法会调用InputManagerService的setInputWindows方法,如下:

private void updateInputWindows(boolean inDrag) {
     //...省略...
     // Send windows to native code.
     mService.mInputManager.setInputWindows(mInputWindowHandles, mFocusedInputWindowHandle);
     clearInputWindowHandlesLw();
}

setInputWindows@InputManagerService方法会调用nativeSetInputWindows方法将InputWindowHandle添加到InputDispatcher中。InputDispatcher在派发input event的时候可以通过InputWindowHandle找到对应的Connection和InputChannel,然后通过Connection内的InputPublisher进行派发。

InputDispatcher中的InputWindowHandle很多,InputDispatcher如何确定哪些InputWindowHandle适合处理要进行派发的event?

  • 对于Key 事件,findFocusedWindowTargetsLocked(…)@@InputDispatcher方法用来确认InputWindowHandle,该方法只是用来确认"mFocusedWindowHandle"是否可以接收事件。“mFocusedWindowHandle"的值是在setInputWindows@InputDispatcher方法中更新的,也就是当有新window添加时,InputDispatcher会遍历所有的Handler,将持有焦点Window的Handle赋值给"mFocusedWindowHandle”。
  • 对于Motion 事件,findTouchedWindowTargetsLocked@InputDispatcher方法用来确认InputWindowHandler, 该方法将down和up event分开处理。不过用来查找合适的InputWindowHandler的是findTouchedWindowAtLocked@InputDispatcher方法,筛选InputWindowHandler的关键点:
    • 1)是否可见
    • 2)是否可以触摸,是否可以有焦点
    • 3)Window的可触摸区域是否包含触摸点。

3.InputChannel

InputChannel 对应了一个文件描述符,这个文件描述符被另外一个进程用来向window中发送input event。InputChannel.java是java侧的类,实现了Parcelable类,这样它就可以被发送到接收input event的进程。
input event的派发过程可以用下面的图简单表示:
在这里插入图片描述
图中的"Dispatcher Thread"是派发进程,运行在system_server进程中; "UI Thread"是某一进程的主线程,也可能是system_server的主线程。这两个线程需要通过一对socket来通信,图中底端用类似管道的方式表示了这对socket。"socket[0]"和"socket[1]"都有对应的文件描述符,“inputChannel”对象会持有对应的描述符,这样通过inputChannel便可以找到文件描述符,然后发送消息。
橙色 的线表示发送input event的过程; 蓝色的线表示对input event处理结果的反馈。

下面以WindowManagerService注册InputChannel的过程为例说说InputChannel的创建和注册。
第一幅图的第二部分展示的是WindowManagerService创建时注册InputChannel的过程,现在我们把它单拉出来:
在这里插入图片描述

SystemServer启动的时候会用InputManagerService对象为参数调用main@WindowManagerService方法创建WindowManagerService对象; 在WindowManagerService的构造函数中InputManagerService对象的monitorInput@InputManagerService方法会被调用。monitorInput@InputManagerService方法会调用
InputChannel.java中的静态方法openInputChannelPair来创建新的"input channel pair",此方法会调用nativeOpenInputChannelPair。nativeOpenInputChannelPair对应的是android_view_inputchannel.cpp中的android_view_InputChannel_nativeOpenInputChannelPair方法,此方法会调用InputChannel(定义在InputTransport.cpp中)的openInputChannelPair方法创建两个InputChannel对象,然后利用这两个对象创建两个NativeInputChannel对象以及两个Inputchannel.java对象。
下面是Native层InputChannel的openInputChannelPair方法:

status_t InputChannel::openInputChannelPair(const std::string& name,
        sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) {
    int sockets[2];
    //socketpair创建一对socket,并将文件描述符存到数组socket中。
    //可以将这对socket类比成管道,不同的是这对socket可同时收发。
    if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) {
        status_t result = -errno;
        ALOGE("channel '%s' ~ Could not create socket pair.  errno=%d",
                name.c_str(), errno);
        outServerChannel.clear();
        outClientChannel.clear();
        return result;
    }

    int bufferSize = SOCKET_BUFFER_SIZE;
    setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));
    setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));
    setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));
    setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));

    std::string serverChannelName = name;
    serverChannelName += " (server)";
    outServerChannel = new InputChannel(serverChannelName, sockets[0]);//使用socket[0]中的文件描述符为参数创建InputChannel对象。

    std::string clientChannelName = name;
    clientChannelName += " (client)";
    outClientChannel = new InputChannel(clientChannelName, sockets[1]);//使用socket[1]中的文件描述符为参数创建InputChannel对象。
    return OK;
}

openInputChannel@WindowState方法调用openInputChannelPair获取到"inputchannel pair"之后,会调用"inputChannel[1]"的transferTo方法,将"inputChannel[1]"中指向NativeInputChannel对象的"mPtr"设置到调用者生成的InputChannel.java对象之中,即addWindow@WindowManagerService方法的InputChannel参数引用的对象之中。
下面是openInputChannel@WindowState方法:

    void openInputChannel(InputChannel outInputChannel) {
        if (mInputChannel != null) {
            throw new IllegalStateException("Window already has an input channel.");
        }
        String name = getName();
        InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
        mInputChannel = inputChannels[0];
        mClientChannel = inputChannels[1];
        mInputWindowHandle.inputChannel = inputChannels[0];
        if (outInputChannel != null) {
            mClientChannel.transferTo(outInputChannel);//调用inputChannel[1]对象的transfer方法。
            mClientChannel.dispose();
            mClientChannel = null;
        } else {
            // If the window died visible, we setup a dummy input channel, so that taps
            // can still detected by input monitor channel, and we can relaunch the app.
            // Create dummy event receiver that simply reports all events as handled.
            mDeadWindowEventReceiver = new DeadWindowEventReceiver(mClientChannel);
        }
        mService.mInputManager.registerInputChannel(mInputChannel, mInputWindowHandle);//注册inputChannel[0]
    }

这个方法除了将"inputChannel[1]" “转换”为InputChannel.java对象之外,还将"inputChannel[0]"保存到InputWindowHandle,并注册到InputManagerService中。registerInputChannel@InputManagerService方法会调用nativeRegisterInputChannel方法。
这个native调用对应的是com_android_server_InputManagerService.java中的nativeRegisterInputChannel方法,下面是该方法的代码:

static void nativeRegisterInputChannel(JNIEnv* env, jclass /* clazz */,
        jlong ptr, jobject inputChannelObj, jobject inputWindowHandleObj, jboolean monitor) {
    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);//找到NativeInputManager对象

    sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,
            inputChannelObj);//找到Native层的InputChannel对象。
    if (inputChannel == NULL) {
        throwInputChannelNotInitialized(env);
        return;
    }
    sp<InputWindowHandle> inputWindowHandle =
            android_server_InputWindowHandle_getHandle(env, inputWindowHandleObj);//找到Native层的InputWindowHandler对象。

    status_t status = im->registerInputChannel(
            env, inputChannel, inputWindowHandle, monitor);//注册InputChannel,注意参数是"inputChannel"和"inputWindowHandle"
    if (status) {
        std::string message;
        message += StringPrintf("Failed to register input channel.  status=%d", status);
        jniThrowRuntimeException(env, message.c_str());
        return;
    }
    if (! monitor) {
        android_view_InputChannel_setDisposeCallback(env, inputChannelObj,
                handleInputChannelDisposed, im);
    }
}

该方法的第一个参数(第三个开始算)是"ptr",是InputManagerService对象中保存的NativeInputManager对象的地址; 第二个参数是InputChannel对象; 第三个参数是InputWindowHandler对象。首先根据这些参数,找到对应的Native对象,然后调用NativeInputManager的registerInputChannel方法,这个方法会调用到InputDispatcher的registerInputChannel方法, 下面是该方法的部分代码:

status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel,
        const sp<InputWindowHandle>& inputWindowHandle, bool monitor) {
#if DEBUG_REGISTRATION
    ALOGD("channel '%s' ~ registerInputChannel - monitor=%s", inputChannel->getName().c_str(),
            toString(monitor));
#endif

    { // acquire lock
        AutoMutex _l(mLock);
       //省略......
       
        sp<Connection> connection = new Connection(inputChannel, inputWindowHandle, monitor);
        int fd = inputChannel->getFd();
        mConnectionsByFd.add(fd, connection);

        if (monitor) {
            mMonitoringChannels.push(inputChannel);
        }
        mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
    } // release lock

    // Wake the looper because some connections have changed.
    mLooper->wake();
    return OK;
}

上面的方法会用InputChannel和InputWindowHandler做参数构造Connection对象,然后用InputChannel中的文件描述符"Fd"做key,将新得到的connection对象存到"mConnectionsByFd"中。另外,调用"mLooper->addFd(…)"将InputChannel的文件描述符"Fd"加入到了Looper中,当然 这个Looper是线程"InputDispatcher"的Looper

"inputChannel[0]"已经注册了,那么"inputChannel[1]“呢?
我们知道"inputChannel[1]” 会“转换”为InputChannel.java对象,WindowManagerService拿到这个对象之后构造了PointerEventDispatcher对象:

        if(mInputManager != null) {
            final InputChannel inputChannel = mInputManager.monitorInput(TAG_WM);
            mPointerEventDispatcher = inputChannel != null
                    ? new PointerEventDispatcher(inputChannel) : null;
        } else {
            mPointerEventDispatcher = null;
        }

PointerEventDispatcher继承了InputEventReceiver,后者的构造函数里面调用了nativeInit方法:

    public InputEventReceiver(InputChannel inputChannel, Looper looper) {
        if (inputChannel == null) {
            throw new IllegalArgumentException("inputChannel must not be null");
        }
        if (looper == null) {
            throw new IllegalArgumentException("looper must not be null");
        }

        mInputChannel = inputChannel;
        mMessageQueue = looper.getQueue();
        mReceiverPtr = nativeInit(new WeakReference<InputEventReceiver>(this),
                inputChannel, mMessageQueue);

        mCloseGuard.open("dispose");
    }

nativeInit方法的第二个参数是InputChannel对象,第三个参数是当前线程的MessageQueue对象。
nativeInit方法对应的JNI方法是android_view_InputEventReceiver中的nativeInit方法。
JNI层的nativeInit方法会找到InputChannel和MessageQueue对象对应的Native对象,然后用两个Native对象做为参数构造NativeInputEventReceiver对象,然后调用新对象的initialize方法,下面看看initialize方法:

status_t NativeInputEventReceiver::initialize() {
    setFdEvents(ALOOPER_EVENT_INPUT);
    return OK;
}
void NativeInputEventReceiver::setFdEvents(int events) {
    if (mFdEvents != events) {
        mFdEvents = events;
        int fd = mInputConsumer.getChannel()->getFd();
        if (events) {
            mMessageQueue->getLooper()->addFd(fd, 0, events, this, NULL);//CallBack设置为this
        } else {
            mMessageQueue->getLooper()->removeFd(fd);
        }
    }
}

initialize方法很简单,只是调用了setFdEvents方法,而后者会将InputChannel的文件描述符"fd"添加到Looper中,这个Looper是主线程的Looper,而且将CallBack设置为自身。
当有输入事件的时候,Looper的pollInner方法会通过下面的code调用NativeInputEventReceiver的handleEvent方法。

   int callbackResult = response.request.callback->handleEvent(fd, events, data);

handleEvent方法会调用consumeEvents,后者会调用到Java层InputEventReceiver的dispatchInputEvent方法,这是一个private方法,不能被重写,但它调用的onInputEvent是个public方法,子类可以重写这个方法来实现自己的派发逻辑来消耗输入事件,这样就完成了输入事件的派发。


4. Input event 的拦截

由第一部分我们知道com_android_server_input_InputManagerService.cpp中的nativeInit(…)方法会构造NativeInputManager对象,而后者会构造InputManager对象,InputManager相关的文件是InputManager.h和InputManager.cpp。InputManager.h文件中对InputManager的定义如下:

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

后两个参数中,第一个是"readerPolicy",第二个是"dispatcherPolicy"。 NativeInputManager继承了InputReaderPolicyInterface和InputDispatcherPolicyInterface,在构造InputManager对象时传入的后两个参数都是this,如下:

mInputManager = new InputManager(eventHub, this, this);

InputManager.cpp的构造函数会用NativeInputManager作为参数构造InputReader对象和InputDispatcher对象,代码如下:

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

InputDispatcher在派发input event之前会调用"mPolicy",即NativeInputManager的相关方法对event进行拦截,如果event被拦截掉,那么就不会进行后续派发,否则正常派发。
拦截分两类:

  • 进入派发对了执行进行拦截
  • 从派发队列中派发时进行拦截(只有key event)

相关的拦截流程这里就不细写了,简单列举一下相关的文件以及主要方法:
1.Motion event相关:

//进入队列之前的拦截
notifyMotion@InputDispatcher
|-->interceptMotionBeforeQueueing@NativeInputManager
    |-->interceptMotionBeforeQueueingNonInteractive@InputManagerService
       |-->interceptMotionBeforeQueueingNonInteractive@InputMonitor
          |-->interceptMotionBeforeQueueingNonInteractive@PhoneWindowManager

2.Key event相关:

//进入队列之前的拦截
notifyKey/injectInputEvent@InputDispatcher
|-->interceptKeyBeforeQueueing@NativeInputManager
    |-->interceptKeyBeforeQueueing@InputManagerService
       |-->interceptKeyBeforeQueueing@InputMonitor
          |-->interceptKeyBeforeQueueing@PhoneWindowManager

//从派发队列中派发时的拦截(只有key event)
dispatchKeyLocked@InputDispatcher
|-->doInterceptKeyBeforeDispatchingLockedInterruptible@InputDispatcher
   |-->interceptKeyBeforeDispatching@NativeInputManager
      |-->interceptKeyBeforeDispatching@InputManagerService
         |-->interceptKeyBeforeDispatching@InputMonitor
            |-->interceptKeyBeforeDispatching@PhoneWindowManager

结束!

猜你喜欢

转载自blog.csdn.net/Dylan_Sen/article/details/82981226