Android R input事件分发流程

IMS初始化流程:

Android R IMS初始化流程-CSDN博客

IMS启动流程:

Android R IMS启动流程-CSDN博客

IMS问题复盘:

Android R IMS问题复盘-CSDN博客

由于流程比较繁杂,这里可以先看下input事件分发时序图,了解下大致流程:

InputChannel创建时序图

server端inputChannel注册时序图

InputChannel的创建与初始化详细流程见第5节

input事件分发流程

        这里选择从底层开始分析,当手指放到屏幕上,硬件接收到电容信号,由kernel层去将这一系列的事件添加到/dev/input下作为不同的fd,再封装到eventhub库里面。

        通过getevent命令我们也能看到/dev/input是否有对应的事件,或者dump input信息。

1. EventHub.getEvents获取事件

/frameworks/native/services/inputflinger/reader/EventHub.cpp

ize_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {

        ..............

        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.");
        // 如果存在需要reopen的设备,则先关闭所有device
        closeAllDevicesLocked();
        // 然后设置需要scan设备的标识
        mNeedToScanDevices = true;
        break; // return to the caller before we actually rescan
        }

        // Report any devices that had last been added/removed.
        // 如果存在需要关闭的设备,则遍历所有需要关闭的设备链表,
        // 删除对应的device,并构建event
        while (mClosingDevices) {
        Device* device = mClosingDevices;
        ALOGV("Reporting device closed: id=%d, name=%s\n", device->id, device->path.c_str());
        mClosingDevices = device->next;
        event->when = now;
        event->deviceId = (device->id == mBuiltInKeyboardId)
        ? ReservedInputDeviceId::BUILT_IN_KEYBOARD_ID
        : device->id;
        event->type = DEVICE_REMOVED;
        event += 1;
        delete device;
        mNeedToSendFinishedDeviceScan = true;
        if (--capacity == 0) {
        break;
        }
        }

        // 需要扫描device,则调用scanDevicesLocked方法扫描
        // 最后更新device列表
        if (mNeedToScanDevices) {
        mNeedToScanDevices = false;
        scanDevicesLocked();
        mNeedToSendFinishedDeviceScan = true;
        }

        //存在需要open的device,则更新mOpeningDevices链表
        // 并构建event
        while (mOpeningDevices != nullptr) {
        Device* device = mOpeningDevices;
        ALOGV("Reporting device opened: id=%d, name=%s\n", device->id, device->path.c_str());
        mOpeningDevices = device->next;
        event->when = now;
        event->deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
        event->type = DEVICE_ADDED;
        event += 1;
        mNeedToSendFinishedDeviceScan = true;
        if (--capacity == 0) {
        break;
        }
        }

        // 需要scanFinish事件,则构建对应event
        if (mNeedToSendFinishedDeviceScan) {
        mNeedToSendFinishedDeviceScan = false;
        event->when = now;
        event->type = FINISHED_DEVICE_SCAN;
        event += 1;
        if (--capacity == 0) {
        break;
        }
        }

        // Grab the next input event.
        bool deviceChanged = false;
        // 遍历需要处理的事件列表
        while (mPendingEventIndex < mPendingEventCount) {
        const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];
        // 如果是inotify事件,则修改对应标识,后面会扫描处理对于的变更
        if (eventItem.data.fd == mINotifyFd) {
        if (eventItem.events & EPOLLIN) {
        mPendingINotify = true;
        } else {
        ALOGW("Received unexpected epoll event 0x%08x for INotify.", eventItem.events);
        }
        continue;
        }

        // 管道事件,则设置wake为true,跳出循环继续执行
        if (eventItem.data.fd == mWakeReadPipeFd) {
        if (eventItem.events & EPOLLIN) {
        ALOGV("awoken after wake()");
        // 标识被唤醒,后面epoll就不会进入wait状态
        awoken = true;
        char buffer[16];
        ssize_t nRead;
        do {
        // 从管道中读取出消息内容
        nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer));
        } while ((nRead == -1 && errno == EINTR) || nRead == sizeof(buffer));
        } else {
        ALOGW("Received unexpected epoll event 0x%08x for wake read pipe.",
        eventItem.events);
        }
        continue;
        }

        ...........................


        // This must be an input event
        // 真正的输入事件
        if (eventItem.events & EPOLLIN) {
        // 从device中读取出事件内容
        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);
        // 出错,则关闭对应device,并标识设备发生变更
        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 {
        // 获取deviceId
        int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;

        // 遍历读取到的所有event,并构建出RawEvent
        size_t count = size_t(readSize) / sizeof(struct input_event);
        for (size_t i = 0; i < count; i++) {
        struct input_event& iev = readBuffer[i];
        event->when = processEventTimestamp(iev);
        event->deviceId = deviceId;
        event->type = iev.type;
        event->code = iev.code;
        event->value = iev.value;
        event += 1;
        capacity -= 1;
        }
        // 如果buffer满了,则break掉
        if (capacity == 0) {
        // The result buffer is full.  Reset the pending event index
        // so we will try to read the device again on the next iteration.
        mPendingEventIndex -= 1;
        break;
        }
        }
        } else if (eventItem.events & EPOLLHUP) {
        ALOGI("Removing device %s due to epoll hang-up event.",
        device->identifier.name.c_str());
        deviceChanged = true;
        closeDeviceLocked(device);
        } else {
        ALOGW("Received unexpected epoll event 0x%08x for device %s.", eventItem.events,
        device->identifier.name.c_str());
        }
        }

        // readNotify() will modify the list of devices so this must be done after
        // processing all other events to ensure that we read all remaining events
        // before closing the devices.
        if (mPendingINotify && mPendingEventIndex >= mPendingEventCount) {
        // 标识已经处理过
        mPendingINotify = false;
        // 处理inotify事件
        readNotifyLocked();
        deviceChanged = true;
        }

        // Report added or removed devices immediately.
        if (deviceChanged) {
        continue;
        }

        // Return now if we have collected any events or if we were explicitly awoken.
        if (event != buffer || awoken) {
        break;
        }

        ...............


        // 开始wait时释放锁
        mLock.unlock(); // release lock before poll

        // epoll等待唤醒
        int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis);

        // 唤醒开始执行时则加锁
        mLock.lock(); // reacquire lock after poll


        }

        // All done, return the number of events we read.
        return event - buffer;
        }

getEvents函数主要作用:

  • 查看是否有需要reopen的device并进行处理,接着处理需要close的device,然后是判断是否需要扫描设备并进行device扫描。
  •  处理新接入的设备,然后开始遍历待处理的事件,并分别处理inotify、管道以及真正的输入事件。
  • 过程中如果有event被处理则就会break掉for循环继续进行下一次处理,如果所有事件都已处理完就会走到下面的epoll_wait进入wait状态等待唤醒
  • 当driver向特定描述符写入事件后,会触发唤醒epoll起来工作,这时候eventHub通过read方法从描述符中读取原始事件,然后通过简单封装成rawEvent并传递给InputReader。
  • 返回给InputReader的值就是event - buffer的差值,这个值就是rawEvent类型的。

2. InputReader处理事件

        InputDispatcher中的事件是从InputReader中来的,InputReader从EventHub中获取到输入事件后,会通过调用InputDispatcher的notifyXxx方法来将事件传递到InuptDispatcher中。

        InputReader在其线程的threadLoop中会调用loopOnce从EventHub中获取输入事件,如果获取到事件,则继续调用processEventsLocked进行处理。接着会调用到InputDevice -> InputMapper -> InputDispatcher(InputListenerInterface),在InputDispatcher中触发notifyXxx方法,从而将事件分发出去。

2.1 InputReader.loopOnce

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

void InputReader::loopOnce() {
    int32_t oldGeneration;
    int32_t timeoutMillis;
    bool inputDevicesChanged = false;
    std::vector<InputDeviceInfo> inputDevices;
 
    ...................
    
    // 从EventHub中获取事件
    size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);

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

        if (count) {
// 获取到输入事件则调用processEventsLocked进行处理
            processEventsLocked(mEventBuffer, count);
        }

        

        ..............

    } // release lock
}

    

        processEventsLocked方法中会根据事件的type,分别处理device的变更事件以及输入事件。输入事件则继续调用processEventsForDeviceLocked来处理,device改变则同步改变mDevices。

2.2 InputReader.processEventsLocked

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

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) {
            
            ......................

#if DEBUG_RAW_EVENTS
            ALOGD("BatchSize: %zu Count: %zu", batchSize, count);
#endif
                // 这里事件类型如果不是device change事件则继续处理
            processEventsForDeviceLocked(deviceId, rawEvent, batchSize);
        } else {
            switch (rawEvent->type) {
                case EventHubInterface::DEVICE_ADDED:
                    // device接入,将device添加到全局map中(mDevices)
                    addDeviceLocked(rawEvent->when, rawEvent->deviceId);
                    break;
                case EventHubInterface::DEVICE_REMOVED:// device断开
                    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;
    }
}

        processEventsForDeviceLocked中从device的map中根据eventHubId查找device,如果找到则调用对应device的process方法继续处理。

2.3 InputReader.processEventsForDeviceLocked

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

void InputReader::processEventsForDeviceLocked(int32_t eventHubId, const RawEvent* rawEvents, size_t count) {

        // 通过eventHubId从map中查找InputDevice
    auto deviceIt = mDevices.find(eventHubId);
    if (deviceIt == mDevices.end()) {
        // 没有对应的device则直接返回
        ALOGW("Discarding event for unknown eventHubId %d.", eventHubId);
        return;
    }

    std::shared_ptr<InputDevice>& device = deviceIt->second;
        // device被忽略则返回
    if (device->isIgnored()) {
        // ALOGD("Discarding event for ignored deviceId %d.", deviceId);
        return;
    }

        // 调用InputDevice的process继续处理事件
    device->process(rawEvents, count);
}

         InputDevice的process中会遍历所有的event,并且根据event中的deviceId从mDevices中找到对应的device,然后遍历其所有的InputMapper,并调用mapper的process进行事件处理。

2.4 InputDevice.process

/frameworks/native/services/inputflinger/reader/InputDevice.cpp

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.
    for (const RawEvent* rawEvent = rawEvents; count != 0; rawEvent++) {
        
.....................
        if (mDropUntilNextSync) {
            
       .............
        // 从devices中找到对应的device,然后遍历其所有inputMapper,并调用其process方法进行处理
            for_each_mapper_in_subdevice(rawEvent->deviceId, [rawEvent](InputMapper& mapper) 
                mapper.process(rawEvent);
            });
        }
        --count;
    }
}

2.5 InputDevice.for_each_mapper_in_subdevice

/frameworks/native/services/inputflinger/reader/include/InputDevice.h

// run a function against every mapper on a specific subdevice
    inline void for_each_mapper_in_subdevice(int32_t eventHubDevice,
                                             std::function<void(InputMapper&)> f) {
        auto deviceIt = mDevices.find(eventHubDevice);
        // 查找对应的device
        if (deviceIt != mDevices.end()) {
            auto& devicePair = deviceIt->second;
            auto& mappers = devicePair.second;
        // 遍历该device的所有InputMapper,并调用函数指针f
            for (auto& mapperPtr : mappers) {
                f(*mapperPtr);
            }
        }
    }

2.6 InputReader.addDeviceLocked

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

void InputReader::addDeviceLocked(nsecs_t when, int32_t eventHubId) {
    // 根据eventHubId查找device
    if (mDevices.find(eventHubId) != mDevices.end()) {
        ALOGW("Ignoring spurious device added event for eventHubId %d.", eventHubId);
        return;
    }

    InputDeviceIdentifier identifier = mEventHub->getDeviceIdentifier(eventHubId);
    // 创建device
    std::shared_ptr<InputDevice> device = createDeviceLocked(eventHubId, identifier);
    device->configure(when, &mConfig, 0);
    device->reset(when);

    .................
}

 InputMapper在InputReader中处理device接入事件触发时会调用addDeviceLocked方法。

2.7 InputReader.createDeviceLocked

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

std::shared_ptr<InputDevice> InputReader::createDeviceLocked(
        int32_t eventHubId, const InputDeviceIdentifier& identifier) {

...................


    std::shared_ptr<InputDevice> device;
    if (deviceIt != mDevices.end()) {
        // 如果device已经存在则直接返回
        device = deviceIt->second;
    } else {
        // 否则创建出对应的InputDevice
        int32_t deviceId = (eventHubId < END_RESERVED_ID) ? eventHubId : nextInputDeviceIdLocked();
        device = std::make_shared<InputDevice>(&mContext, deviceId, bumpGenerationLocked(),
                                               identifier);
    }
    // 调用addEventHubDevice,构建出相应的mapper
    device->addEventHubDevice(eventHubId);
    return device;
}

         调用到createDeviceLocked方法来创建出对应的InputDevice,创建出device后,便调用它的addEventHubDevice来创建出相应的InputMapper并添加到全局map中。

2.8 InputDevice.addEventHubDevice

 /frameworks/native/services/inputflinger/reader/InputDevice.cpp

void InputDevice::addEventHubDevice(int32_t eventHubId, bool populateMappers) {
    if (mDevices.find(eventHubId) != mDevices.end()) {
        return;
    }
    std::unique_ptr<InputDeviceContext> contextPtr(new InputDeviceContext(*this, eventHubId));
    uint32_t classes = contextPtr->getDeviceClasses();
    std::vector<std::unique_ptr<InputMapper>> mappers;
  
    // Check if we should skip population
    if (!populateMappers) {
        mDevices.insert({eventHubId, std::make_pair(std::move(contextPtr), std::move(mappers))});
        return;
    }
  
    // Switch-like devices.
    if (classes & INPUT_DEVICE_CLASS_SWITCH) {
        mappers.push_back(std::make_unique<SwitchInputMapper>(*contextPtr));
    }
  
    // Scroll wheel-like devices.
    if (classes & INPUT_DEVICE_CLASS_ROTARY_ENCODER) {
        mappers.push_back(std::make_unique<RotaryEncoderInputMapper>(*contextPtr));
    }
  
    // Vibrator-like devices.
    if (classes & INPUT_DEVICE_CLASS_VIBRATOR) {
        mappers.push_back(std::make_unique<VibratorInputMapper>(*contextPtr));
    }
  
    // Keyboard-like devices.
    uint32_t keyboardSource = 0;
    int32_t keyboardType = AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC;
    if (classes & INPUT_DEVICE_CLASS_KEYBOARD) {
        keyboardSource |= AINPUT_SOURCE_KEYBOARD;
    }
    if (classes & INPUT_DEVICE_CLASS_ALPHAKEY) {
        keyboardType = AINPUT_KEYBOARD_TYPE_ALPHABETIC;
    }
    if (classes & INPUT_DEVICE_CLASS_DPAD) {
        keyboardSource |= AINPUT_SOURCE_DPAD;
    }
    if (classes & INPUT_DEVICE_CLASS_GAMEPAD) {
        keyboardSource |= AINPUT_SOURCE_GAMEPAD;
    }
  
    if (keyboardSource != 0) {
        mappers.push_back(
                std::make_unique<KeyboardInputMapper>(*contextPtr, keyboardSource, keyboardType));
    }
  
    // Cursor-like devices.
    if (classes & INPUT_DEVICE_CLASS_CURSOR) {
        mappers.push_back(std::make_unique<CursorInputMapper>(*contextPtr));
    }
  
    // Touchscreens and touchpad devices.
    if (classes & INPUT_DEVICE_CLASS_TOUCH_MT) {
        mappers.push_back(std::make_unique<MultiTouchInputMapper>(*contextPtr));
    } else if (classes & INPUT_DEVICE_CLASS_TOUCH) {
        mappers.push_back(std::make_unique<SingleTouchInputMapper>(*contextPtr));
    }
  
    // Joystick-like devices.
    if (classes & INPUT_DEVICE_CLASS_JOYSTICK) {
        mappers.push_back(std::make_unique<JoystickInputMapper>(*contextPtr));
    }
  
    // External stylus-like devices.
    if (classes & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) {
        mappers.push_back(std::make_unique<ExternalStylusInputMapper>(*contextPtr));
    }
  
    // insert the context into the devices set
    mDevices.insert({eventHubId, std::make_pair(std::move(contextPtr), std::move(mappers))});
}

        通过addEventHubDevice方法,可以看出针对不同的device类型,会构建出不同的mapper,最后将mapper数组添加到了mDevices的全局map中。

        这里以对touch事件的处理为例,从上面的代码判断条件可以看出对于触摸类型的输入设备,如果设备支持多点触摸,它的触摸事件由 MultiTouchInputMapper 处理,而如果只支持单点触摸,它的触摸事件由 SingleTouchInputMapper 处理。现在的手机或者车机显示屏一般都是支持多点触摸的,所以直接看MultiTouchInputMapper 。

2.9 MultiTouchInputMapper.process

/frameworks/native/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp

void MultiTouchInputMapper::process(const RawEvent* rawEvent) {
    //调用父类处理同步事件(EV_SYN SYN_REPORT)
    TouchInputMapper::process(rawEvent);

    //使用累加器收集同步事件之前的每一个手指的触控点信息
    mMultiTouchMotionAccumulator.process(rawEvent);
}

         这里我们来看看一段在触摸屏上滑动手指所产生的触摸事件序列:

/dev/input/event4: EV_ABS       ABS_MT_POSITION_X    00000336            
/dev/input/event4: EV_ABS       ABS_MT_POSITION_Y    0000017f 
​
/dev/input/event4: EV_SYN       SYN_REPORT           00000000 
​
/dev/input/event4: EV_ABS       ABS_MT_POSITION_X    00000333            
/dev/input/event4: EV_ABS       ABS_MT_POSITION_Y    00000184  
​
/dev/input/event4: EV_SYN       SYN_REPORT           00000000   
​
/dev/input/event4: EV_ABS       ABS_MT_POSITION_X    0000032f            
/dev/input/event4: EV_ABS       ABS_MT_POSITION_Y    00000188   
         
/dev/input/event4: EV_SYN       SYN_REPORT           00000000

        对于每一次的触摸事件,例如手指按下或者移动,驱动会先上报它的信息事件,例如 x, y 坐标事件,再加上一个同步事件(SYN_REPORT)。

        对应的touch事件就会使用累加器MultiTouchMotionAccumulator 收集触摸事件的信息。

2.10 收集触摸事件信息

        这里我们先理解下多点触摸协议是什么,多点触摸协议也就是 A / B 协议。A/B 协议也叫 slot 协议,下面简单介绍下这个协议。

        当第一个手指按下时,会有如下事件序列:

//事件 ABS_MT_SLOT,表明触摸信息事件,是由哪个槽(slot)进行上报的。一个手指产生的触摸事件,只能由同一个槽进行上报。
EV_ABS       ABS_MT_SLOT          00000000
//事件 ABS_MT_TRACKING_ID ,表示手指ID。手指 ID 才能唯一代表一个手指,槽的 ID 并不能代表一个手指。因为假如一个手指抬起,另外一个手指按下,这两个手指的事件可能由同一个槽进行上报,但是手指 ID 肯定是不一样的。
EV_ABS       ABS_MT_TRACKING_ID   00000000
//事件 ABS_MT_POSITION_X 和 ABS_MT_POSITION_Y 表示触摸点的 x, y 坐标值。            
EV_ABS       ABS_MT_POSITION_X    000002ea            
EV_ABS       ABS_MT_POSITION_Y    00000534
​
//事件 SYN_REPORT 是同步事件,它表示系统需要同步并处理之前的事件。
EV_SYN       SYN_REPORT           00000000 

      当第一个手指移动时,会有如下事件:

EV_ABS       ABS_MT_POSITION_X    000002ec            
EV_ABS       ABS_MT_POSITION_Y    00000526    
​
EV_SYN       SYN_REPORT           00000000 

        此时没有指定 ABS_MT_SLOT 事件和 ABS_MT_TRACKING_ID 事件,默认使用前面的值,因为此时只有一个手指。

        当第二个手指按下时,会有如下事件:

EV_ABS       ABS_MT_SLOT          00000001            
EV_ABS       ABS_MT_TRACKING_ID   00000001            
EV_ABS       ABS_MT_POSITION_X    00000470            
EV_ABS       ABS_MT_POSITION_Y    00000475       
​
EV_SYN       SYN_REPORT           00000000

        第二个手指的事件,由另外一个槽进行上报。

        当两个手指同时移动时,会有如下事件:

EV_ABS       ABS_MT_SLOT          00000000            
EV_ABS       ABS_MT_POSITION_Y    000004e0            
EV_ABS       ABS_MT_SLOT          00000001            
EV_ABS       ABS_MT_POSITION_X    0000046f            
EV_ABS       ABS_MT_POSITION_Y    00000414   
​
EV_SYN       SYN_REPORT           00000000 

        通过指定槽,就可以清晰看到事件由哪个槽进行上报,从而就可以区分出两个手指产生的事件。

        当其中一个手指抬起时,会有如下事件:

EV_ABS       ABS_MT_SLOT          00000000  
// 注意,ABS_MT_TRACKING_ID 的值为 -1
EV_ABS       ABS_MT_TRACKING_ID   ffffffff            
EV_ABS       ABS_MT_SLOT          00000001            
EV_ABS       ABS_MT_POSITION_Y    000003ee  
​
EV_SYN       SYN_REPORT           00000000 

        当一个手指抬起时,ABS_MT_TRACKING_ID 事件的值为 -1,也就是十六进制的 ffffffff。通过槽事件,可以知道是第一个手指抬起了。

        如果最后一个手指也抬起了,会有如下事件:

EV_ABS       ABS_MT_TRACKING_ID   ffffffff     

// 同步事件,不属于触摸事件 
EV_SYN       SYN_REPORT           00000000 

        通过 ABS_MT_TRACKING_ID 事件可知,手指是抬起了,但是哪个手指抬起了呢?由于抬起的是最后一个手指,因此省略了槽事件。

        现在让来看看累加器 MultiTouchMotionAccumulator 是如何收集这个协议上报的数据的:

2.10.1 MultiTouchMotionAccumulator.process

 /frameworks/native/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp

void MultiTouchMotionAccumulator::process(const RawEvent* rawEvent) {
    if (rawEvent->type == EV_ABS) {
        bool newSlot = false;
        if (mUsingSlotsProtocol) {
            // slot协议,使用 ABS_MT_SLOT 事件获取索引
            if (rawEvent->code == ABS_MT_SLOT) {
                mCurrentSlot = rawEvent->value;
                newSlot = true;
            }
        } else if (mCurrentSlot < 0) {
            // 非slot协议 : 初始上报的事件,默认 slot 为 0
            mCurrentSlot = 0;
        }
​
        if (mCurrentSlot < 0 || size_t(mCurrentSlot) >= mSlotCount) {
            // ...
        } else {
            //根据索引,获取slot数组的元素,并填充信息
            Slot* slot = &mSlots[mCurrentSlot];
​
            if (!mUsingSlotsProtocol) {
                slot->mInUse = true;
            }
            
            switch (rawEvent->code) {
                case ABS_MT_POSITION_X:
                    slot->mAbsMTPositionX = rawEvent->value;
                    break;
                case ABS_MT_POSITION_Y:
                    slot->mAbsMTPositionY = rawEvent->value;
                    break;
                // ...
                case ABS_MT_TRACKING_ID:
                    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.
                        // slot协议: ABS_MT_TRACKING_ID 事件的值小于0,表示当前 slot 不再使用。
                        slot->mInUse = false;
                    } else {
                        // slot协议 : ABS_MT_TRACKING_ID 事件的值为非负值,表示当前 slot 正在使用。
                        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.
        // 非 slot协议 : EV_SYN + SYN_MT_REPORT 事件,分割手指的触控点信息
        mCurrentSlot += 1;
    }
}

        收集 slot 协议上报的数据的过程如下:

  • 首先根据 ABS_MT_SLOT 事件,获取数组索引。如果上报的数据中没有指定 ABS_MT_SLOT 事件,那么默认用最近一次的 ABS_MT_SLOT 事件的值。
  • 根据索引,从数组 mSlots 获取 Slot 元素,并填充数据。

        就是用 Slot 数组的不同元素,收集不同手指所产生的事件信息。

2.11 TouchInputMapper.process处理同步事件

/frameworks/native/services/inputflinger/reader/mapper/TouchInputMapper.cpp

void TouchInputMapper::process(const RawEvent* rawEvent) {
        //记录mouse或touch pad按键状态
        mCursorButtonAccumulator.process(rawEvent);
        //记录cursor scrolling motions
        mCursorScrollAccumulator.process(rawEvent);
        //记录touch、BTN_STYLUS、 tool buttons状态
        mTouchButtonAccumulator.process(rawEvent);

        // 处理同步事件
        if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
        sync(rawEvent->when);
        }
        }

void TouchInputMapper::sync(nsecs_t when, nsecs_t readTime) {
    // Push a new state.
    // 添加一个空的元素
    mRawStatesPending.emplace_back();

    // 获取刚刚添加的元素
    RawState& next = mRawStatesPending.back();
    
    next.clear();
    next.when = when;
    next.readTime = readTime;

    // ...

    //同步累加器中的数据到 next 中
    // syncTouch()由子类实现
    syncTouch(when, &next);

    // ...

    // 处理数据
    processRawTouches(false /*timeout*/);
}

            处理同步事件的过程如下:

  • 调用 syncTouch() 把累加器收集到数据,同步到 mRawStatesPending 最后一个元素中。
  • 同步过来的数据,基本上还是元数据,因此需要对它加工,最终要生成高级事件,并分发出去。

2.12 MultiTouchInputMapper.syncTouch

 /frameworks/native/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp

void MultiTouchInputMapper::syncTouch(nsecs_t when, RawState* outState) {
    ...........

    for (size_t inIndex = 0; inIndex < inCount; inIndex++) {
        // 从收集器中获取 Slot 数组的元素
        const MultiTouchMotionAccumulator::Slot* inSlot =
                mMultiTouchMotionAccumulator.getSlot(inIndex);

        // 如果 tracking id 为负值,槽就会不再使用
        if (!inSlot->isInUse()) {
            continue;
        }

        .................

        // 把累加器的Slot数组的数据同步到 RawState::rawPointerData 中
        RawPointerData::Pointer& outPointer = outState->rawPointerData.pointers[outCount];
        

        ..................

        // Assign pointer id using tracking id if available.
        if (mHavePointerIds) {
            int32_t trackingId = inSlot->getTrackingId();
            int32_t id = -1;
            // 把 tracking id 转化为 id
            if (trackingId >= 0) {
                // mPointerIdBits 保存的是手指的所有 id
                // mPointerTrackingIdMap 是建立 id 到 trackingId 的映射
                // 这里就是根据 trackingId 找到 id
                for (BitSet32 idBits(mPointerIdBits); !idBits.isEmpty();) {
                    uint32_t n = idBits.clearFirstMarkedBit();
                    if (mPointerTrackingIdMap[n] == trackingId) {
                        id = n;
                    }
                }

                // id < 0 表示从缓存中,根据 trackingId, 没有获取到 id
                if (id < 0 && !mPointerIdBits.isFull()) {
                    // 从 mPointerIdBits 生成一个 id 
                    id = mPointerIdBits.markFirstUnmarkedBit();
                    // mPointerTrackingIdMap 建立 id 到 trackingId 映射
                    mPointerTrackingIdMap[id] = trackingId;
                }
            }
            
            // id < 0,表示手指抬起
            if (id < 0) {
                mHavePointerIds = false;
                // 清除对应的数据
                outState->rawPointerData.clearIdBits();
                newPointerIdBits.clear();
            } else { // 有 id
                // 保存id
                outPointer.id = id;
                // 保存 id -> index 映射
                // index 是数组 RawPointerData::pointers 的索引
                outState->rawPointerData.idToIndex[id] = outCount;
                outState->rawPointerData.markIdBit(id, isHovering);
                newPointerIdBits.markBit(id);
            }
        }
        outCount += 1;
    }

    // 保存手指的数量
    outState->rawPointerData.pointerCount = outCount;
    // 保存所有的手指 id
    mPointerIdBits = newPointerIdBits;

    // 对于 SLOT 协议,同步的收尾工作不做任何事
    mMultiTouchMotionAccumulator.finishSync();
}

         累加器收集的数据是由驱动直接上报的元数据,这里把元数据同步到 RawState::rawPointerData,它的类型为 RawPointerData ,结构体定义如下:

/frameworks/native/services/inputflinger/reader/mapper/TouchInputMapper.h

/* Raw data for a collection of pointers including a pointer id mapping table. */
struct RawPointerData {
    struct Pointer {
        uint32_t id; // 手指的 ID
        int32_t x;
        int32_t y;
        // ...
    };

    // 手指的数量
    uint32_t pointerCount;
    // 用 Pointer 数组保存触摸事件的所有信息
    Pointer pointers[MAX_POINTERS];
    // touchingIdBits 保存所有手指的ID
    BitSet32 hoveringIdBits, touchingIdBits, canceledIdBits;
    // 建立手指ID到数组索引的映射
    uint32_t idToIndex[MAX_POINTER_ID + 1];

    // ...
};

     这里需要注意的是:

  • 只有手指 ID 才能唯一代表一个手指。
  • index 只能作为数据的索引,来获取手指的触摸事件信息。
  • 如果你知道了手指ID,那么就可以通过 idToIndex 获取索引,然后根据索引获取手指对应的触摸事件信息。

2.13 TouchInputMapper.processRawTouches处理同步后的数据

        现在数据已经同步到 mRawStatesPending 最后一个元素中,但是这些数据基本上是元数据,是比较晦涩的,接下来看看如何处理这些数据:

  /frameworks/native/services/inputflinger/reader/mapper/TouchInputMapper.cpp

void TouchInputMapper::processRawTouches(bool timeout) {
    
............

    // 现在开始处理同步过来的数据
    const size_t N = mRawStatesPending.size();
    size_t count;
    for (count = 0; count < N; count++) {
        // 获取数据
        const RawState& next = mRawStatesPending[count];

        ...

        //mCurrentRawState 保存当前正在处理的元数据
        mCurrentRawState.copyFrom(next);
        
        if (mCurrentRawState.when < mLastRawState.when) {
            mCurrentRawState.when = mLastRawState.when;
            mCurrentRawState.readTime = mLastRawState.readTime;
        }

        //加工以及分发
        cookAndDispatch(mCurrentRawState.when, mCurrentRawState.readTime);
    }

    // 成功处理完数据,就从 mRawStatesPending 从擦除
    if (count != 0) {
        mRawStatesPending.erase(mRawStatesPending.begin(), mRawStatesPending.begin() + count);
    }

    ......
}

         开始处理元数据之前,首先使用 mCurrentRawState 复制了当前正在处理的数据,后面会使用它进行前后两次的数据对比,生成高级事件,例如 DOWN, MOVE, UP 事件。

2.14 TouchInputMapper.cookAndDispatch对数据进行加工和分发

   /frameworks/native/services/inputflinger/reader/mapper/TouchInputMapper.cpp

void TouchInputMapper::cookAndDispatch(nsecs_t when, nsecs_t readTime) {
    // 加工完的数据保存到 mCurrentCookedState
    mCurrentCookedState.clear();

    ................

    //加工事件
    cookPointerData();

    ..........

    // 此时的 device mode 为 DIRECT,表示直接分发
    if (mDeviceMode == DeviceMode::POINTER) {
        .....
    } else {
        updateTouchSpots();

        if (!mCurrentMotionAborted) {
            dispatchButtonRelease(when, readTime, policyFlags);
            dispatchHoverExit(when, readTime, policyFlags);

            //2. 分发触摸事件
            dispatchTouches(when, readTime, policyFlags);

            dispatchHoverEnterAndMove(when, readTime, policyFlags);
            dispatchButtonPress(when, readTime, policyFlags);
        }

        ........
    }

    .........

    // 保存上一次的元数据和上一次的加工后的数据
    mLastRawState.copyFrom(mCurrentRawState);
    mLastCookedState.copyFrom(mCurrentCookedState);
}

         加工和分发事件的过程如下:

  • 使用 cookPointerData() 进行加工事件。加工什么呢?例如,由于手指是在输入设备上触摸的,因此需要把输入设备的坐标转换为显示屏的坐标,这样窗口就能接收到正确的坐标事件。
  • 使用 dispatchTouches() 进行分发事件。底层上报的数据毕竟晦涩难懂,因此需要包装成 DOWN/MOVE/UP 事件进行分发

2.15 TouchInputMapper.cookPointerData加工数据

 /frameworks/native/services/inputflinger/reader/mapper/TouchInputMapper.cpp

void TouchInputMapper::cookPointerData() {
    
    ........

    // Walk through the the active pointers and map device coordinates onto
    // surface coordinates and adjust for display orientation.
    for (uint32_t i = 0; i < currentPointerCount; i++) {
        const RawPointerData::Pointer& in = mCurrentRawState.rawPointerData.pointers[i];

        // Size
        ...

        // Pressure
        ...

        // Distance
        ...

        // Coverage
        ...

        // Adjust X,Y coords for device calibration
        float xTransformed = in.x, yTransformed = in.y;
        mAffineTransform.applyTo(xTransformed, yTransformed);
        //把输入设备的坐标,转换为显示设备坐标
        //转换后的坐标,保存到 xTransformed 和 yTransformed 中
        rotateAndScale(xTransformed, yTransformed);

        
        ............省略若干代码...........
    }
}

        加工的元数据保存到了 CookedState::cookedPointerData 中,它的类型为 CookedPointerData ,结构体定义如下:

/frameworks/native/services/inputflinger/reader/mapper/TouchInputMapper.h

struct CookedPointerData {
    uint32_t pointerCount;
    PointerProperties pointerProperties[MAX_POINTERS];
    // 保存坐标数据
    PointerCoords pointerCoords[MAX_POINTERS];
    BitSet32 hoveringIdBits, touchingIdBits, canceledIdBits, validIdBits;
    uint32_t idToIndex[MAX_POINTER_ID + 1];

    ...
};

2.16 TouchInputMapper.rotateAndScale坐标点转换

/frameworks/native/services/inputflinger/reader/mapper/TouchInputMapper.cpp

// Transform raw coordinate to surface coordinate
void TouchInputMapper::rotateAndScale(float& x, float& y) {
    // Scale to surface coordinate.
    //根据x,y的缩放比例,计算触摸点在显示设备的缩放坐标
    const float xScaled = float(x - mRawPointerAxes.x.minValue) * mXScale;
    const float yScaled = float(y - mRawPointerAxes.y.minValue) * mYScale;

    const float xScaledMax = float(mRawPointerAxes.x.maxValue - x) * mXScale;
    const float yScaledMax = float(mRawPointerAxes.y.maxValue - y) * mYScale;

    // Rotate to surface coordinate.
    // 0 - no swap and reverse.
    // 90 - swap x/y and reverse y.
    // 180 - reverse x, y.
    // 270 - swap x/y and reverse x.
    // 根据旋转方向计算最终的显示设备的x,y坐标值
    switch (mSurfaceOrientation) {
        case DISPLAY_ORIENTATION_0:
            x = xScaled + mXTranslate;
            y = yScaled + mYTranslate;
            break;
        case DISPLAY_ORIENTATION_90:
            y = xScaledMax - (mRawSurfaceWidth - mSurfaceRight);
            x = yScaled + mYTranslate;
            break;
        case DISPLAY_ORIENTATION_180:
            x = xScaledMax - (mRawSurfaceWidth - mSurfaceRight);
            y = yScaledMax - (mRawSurfaceHeight - mSurfaceBottom);
            break;
        case DISPLAY_ORIENTATION_270:
            y = xScaled + mXTranslate;
            x = yScaledMax - (mRawSurfaceHeight - mSurfaceBottom);
            break;
        default:
            assert(false);
    }
}

        主要过程如下:

  • 首先根据坐标轴的缩放比例 mXScale 和 mYScale,计算触摸屏的坐标点在显示屏的坐标系中的x, y轴的缩放值。
  • 根据显示屏 x, y 轴的偏移量,以及旋转角度,最终计算出显示屏上的坐标点。

2.17 TouchInputMapper.dispatchTouches分发事件

 /frameworks/native/services/inputflinger/reader/mapper/TouchInputMapper.cpp

void TouchInputMapper::dispatchTouches(nsecs_t when, nsecs_t readTime, uint32_t policyFlags) {
    ........
    if (currentIdBits == lastIdBits) {
        if (!currentIdBits.isEmpty()) {
            // 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.
            // 如果前后两次数据的手指数没有变化,并且当前的手指数不为0,那么此时事件肯定是移动事件,需要分发 AMOTION_EVENT_ACTION_MOVE 事件
            dispatchMotion(when, readTime, 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.
        BitSet32 upIdBits(lastIdBits.value & ~currentIdBits.value);
        BitSet32 downIdBits(currentIdBits.value & ~lastIdBits.value);
        BitSet32 moveIdBits(lastIdBits.value & currentIdBits.value);
        BitSet32 dispatchedIdBits(lastIdBits.value);

        // Update last coordinates of pointers that have moved so that we observe the new
        // pointer positions at the same time as other pointers that have just gone up.
        // 参数 moveIdBits 表示有移动的手指,这里检测移动的手指,前后两次数据有变化,那么表示需要分发一个移动事件
        bool moveNeeded =
                updateMovedPointers(mCurrentCookedState.cookedPointerData.pointerProperties,
                                    mCurrentCookedState.cookedPointerData.pointerCoords,
                                    mCurrentCookedState.cookedPointerData.idToIndex,
                                    mLastCookedState.cookedPointerData.pointerProperties,
                                    mLastCookedState.cookedPointerData.pointerCoords,
                                    mLastCookedState.cookedPointerData.idToIndex, moveIdBits);
        if (buttonState != mLastCookedState.buttonState) {
            moveNeeded = true;
        }

        // Dispatch pointer up events.
        while (!upIdBits.isEmpty()) {
            ........
            // 有手指抬起,分发 AMOTION_EVENT_ACTION_POINTER_UP 事件
            dispatchMotion(when, readTime, policyFlags, mSource, AMOTION_EVENT_ACTION_POINTER_UP, 0,
                           isCanceled ? AMOTION_EVENT_FLAG_CANCELED : 0, metaState, buttonState, 0,
                           mLastCookedState.cookedPointerData.pointerProperties,
                           mLastCookedState.cookedPointerData.pointerCoords,
                           mLastCookedState.cookedPointerData.idToIndex, dispatchedIdBits, upId,
                           mOrientedXPrecision, mOrientedYPrecision, mDownTime);
            dispatchedIdBits.clearBit(upId);
            mCurrentCookedState.cookedPointerData.canceledIdBits.clearBit(upId);
        }

        // Dispatch move events if any of the remaining pointers moved from their old locations.
        // Although applications receive new locations as part of individual pointer up
        // events, they do not generally handle them except when presented in a move event.
        // 如果移动的手指前后两次数据有变化,那么分发移动事件
        if (moveNeeded && !moveIdBits.isEmpty()) {
            ALOG_ASSERT(moveIdBits.value == dispatchedIdBits.value);
            dispatchMotion(when, readTime, policyFlags, mSource, AMOTION_EVENT_ACTION_MOVE, 0, 0,
                           metaState, buttonState, 0,
                           mCurrentCookedState.cookedPointerData.pointerProperties,
                           mCurrentCookedState.cookedPointerData.pointerCoords,
                           mCurrentCookedState.cookedPointerData.idToIndex, dispatchedIdBits, -1,
                           mOrientedXPrecision, mOrientedYPrecision, mDownTime);
        }

        // Dispatch pointer down events using the new pointer locations.
        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;
            }

            // 有手指按下,分发 AMOTION_EVENT_ACTION_POINTER_DOWN
            dispatchMotion(when, readTime, 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);
        }
    }
}

         分发事件的过程,其实就是对比前后两次的数据,生成高级事件 AMOTION_EVENT_ACTION_POINTER_DOWN, AMOTION_EVENT_ACTION_MOVE, AMOTION_EVENT_ACTION_POINTER_UP,然后调用 dispatchMotion() 分发这些高级事件。

2.18 TouchInputMapper.dispatchMotion分发高级事件

  /frameworks/native/services/inputflinger/reader/mapper/TouchInputMapper.cpp

void TouchInputMapper::dispatchMotion(nsecs_t when, nsecs_t readTime, 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) {
    ..........

        // action 添加索引
        // action 中前8位表示手指索引,后8位表示ACTION
        if (changedId >= 0 && id == uint32_t(changedId)) {
            action |= pointerCount << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
        }

        pointerCount += 1;
    }

    ALOG_ASSERT(pointerCount != 0);

    // 当只有一个手指按下,发送 AMOTION_EVENT_ACTION_DOWN 事件。
    // 但最后一个手指抬起时,发送 AMOTION_EVENT_ACTION_UP 事件。
    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.
        if (action == AMOTION_EVENT_ACTION_POINTER_DOWN) {
            action = AMOTION_EVENT_ACTION_DOWN;
        } else if (action == AMOTION_EVENT_ACTION_POINTER_UP) {
            if ((flags & AMOTION_EVENT_FLAG_CANCELED) != 0) {
                action = AMOTION_EVENT_ACTION_CANCEL;
            } else {
                action = AMOTION_EVENT_ACTION_UP;
            }
        } else {
            // Can't happen.
            ALOG_ASSERT(false);
        }
    }

    ...............

    // 把数据包装成 NotifyMotionArgs,并加入到 QueuedInputListener 队列
    NotifyMotionArgs args(getContext()->getNextId(), when, readTime, deviceId, source, displayId,
                          policyFlags, action, actionButton, flags, metaState, buttonState,
                          MotionClassification::NONE, edgeFlags, pointerCount, pointerProperties,
                          pointerCoords, xPrecision, yPrecision, xCursorPosition, yCursorPosition,
                          downTime, std::move(frames));
    getListener()->notifyMotion(&args);
}

可以看到,数据最终被包装成 NotifyMotionArgs 分发到下一环 InputClassifier

但是,在这之前,还对 action 做了如下处理:

  • 为 action 添加一个 index。由于 index 是元数据数组的索引,因此 action 也就是绑定了触摸事件的数据。
  • 如果是第一个手指按下,把 AMOTION_EVENT_ACTION_POINTER_DOWN 转换为 AMOTION_EVENT_ACTION_DOWN
  • 如果是最后一个手指抬起,把 AMOTION_EVENT_ACTION_POINTER_UP 转换成 AMOTION_EVENT_ACTION_UP

2.19 小结

  • 首先每次一个touchEvent获取Slot,在没有收到EV_SYN之前对应的Slot都是相同的,然后依次处理x,y,pressure,touch_major,这些值初始化slot的各个变量。
  • 当收到ev.type== EV_SYN并且ev.code = SYN_MT_REPORT那么当前的slot的index加1,给下一次触摸事件去记录,同时sync函数处理这次触摸事件。
  • 然后调用cookAndDispatch、cookPointerData进行加工和分发数据,对应的不同事件,调用dispatchMotion生成高级事件,数据最终被包装成 NotifyMotionArgs 分发到,分发到InputDispatcher的notifyMotion。

3. InputDispatcher分发事件

        第二章说到了InputReader 对触摸事件的处理流程,最终的结果是把触摸事件包装成 NotifyMotionArgs,然后加入到 QueuedInputListener 的缓存队列,QueuedInputListener 会把缓存队列中的所有事件,分发给 InputClassifier。

3.1 InputDispatcher.notifyMotion收到触摸事件

/frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp

void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) {
    if (!validateMotionEvent(args->action, args->actionButton, args->pointerCount,
                             args->pointerProperties)) {
        return;
    }

    uint32_t policyFlags = args->policyFlags;
    //来自InputReader/InputClassifier的 motion 事件,都是受信任的
    policyFlags |= POLICY_FLAG_TRUSTED;

    android::base::Timer t;
    // 对触摸事件执行截断策略
    // 触摸事件入队前,查询截断策略,查询的结果保存到参数 policyFlags
    mPolicy->interceptMotionBeforeQueueing(args->displayId, args->eventTime, /*byref*/ policyFlags);
    if (t.duration() > SLOW_INTERCEPTION_THRESHOLD) {
        ALOGW("Excessive delay in interceptMotionBeforeQueueing; took %s ms",
              std::to_string(t.duration().count()).c_str());
    }

    bool needWake;
    { // acquire lock
        mLock.lock();

        if (shouldSendMotionToInputFilterLocked(args)) {
             ...
        }

        // 包装成 MotionEntry
        // Just enqueue a new motion event.
        std::unique_ptr<MotionEntry> newEntry =
                std::make_unique<MotionEntry>(args->id, args->eventTime, args->deviceId,
                                              args->source, args->displayId, policyFlags,
                                              args->action, args->actionButton, args->flags,
                                              args->metaState, args->buttonState,
                                              args->classification, args->edgeFlags,
                                              args->xPrecision, args->yPrecision,
                                              args->xCursorPosition, args->yCursorPosition,
                                              args->downTime, args->pointerCount,
                                              args->pointerProperties, args->pointerCoords, 0, 0);

        //把触摸事件加入收件箱
        needWake = enqueueInboundEventLocked(std::move(newEntry));
        mLock.unlock();
    } // release lock

    //如果有必要,唤醒线程处理触摸事件
    if (needWake) {
        mLooper->wake();
    }
}

3.2 NativeInputManager.interceptMotionBeforeQueueing截断策略查询

/frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp

void NativeInputManager::interceptMotionBeforeQueueing(const int32_t displayId, nsecs_t when,
        uint32_t& policyFlags) {

    bool interactive = mInteractive.load();
    if (interactive) {
        policyFlags |= POLICY_FLAG_INTERACTIVE;
    }
    // 受信任,并且是非注入的事件
    if ((policyFlags & POLICY_FLAG_TRUSTED) && !(policyFlags & POLICY_FLAG_INJECTED)) {
        if (policyFlags & POLICY_FLAG_INTERACTIVE) {
            // 设备处于交互状态下,受信任且非注入的事件,直接发送给用户,而不经过截断策略处理
            policyFlags |= POLICY_FLAG_PASS_TO_USER;
        } else {
            // 只有设备处于非交互状态,触摸事件才需要执行截断策略
            JNIEnv* env = jniEnv();
            jint wmActions = env->CallIntMethod(mServiceObj,
                        gServiceClassInfo.interceptMotionBeforeQueueingNonInteractive,
                        displayId, when, policyFlags);
            if (checkAndClearExceptionFromCallback(env,
                    "interceptMotionBeforeQueueingNonInteractive")) {
                wmActions = 0;
            }

            handleInterceptActions(wmActions, when, /*byref*/ policyFlags);
        }
    } else { // 注入事件,或者不受信任事件
        // 只有在交互状态下,才传递给用户
        // 注意,这里还有另外一层意思: 非交互状态下,不发送给用户
        if (interactive) {
            policyFlags |= POLICY_FLAG_PASS_TO_USER;
        }
    }
}

void NativeInputManager::handleInterceptActions(jint wmActions, nsecs_t when,
        uint32_t& policyFlags) {
    if (wmActions & WM_ACTION_PASS_TO_USER) {
        policyFlags |= POLICY_FLAG_PASS_TO_USER;
    }
}

         一个触摸事件,必须满足下面三种情况,才执行截断策略:

  • 触摸事件是受信任的。来自输入设备的触摸事件都是受信任的。
  • 触摸事件是非注入的。monkey 的原理就是注入触摸事件,因此它的事件是不需要经过截断策略处理的。
  • 设备处于非交互状态。一般来说,非交互状态指的就是显示屏处于灭屏状态。

        另外还需要关注的是,事件在什么时候是不需要经过截断策略,有两种情况:

  • 对于受信任且非注入的触摸事件,如果设备处于交互状态,直接发送给用户。 也就是说,如果显示屏处于亮屏状态,输入设备产生的触摸事件一定会发送给窗口。
  • 对于不受信任,或者注入的触摸事件,如果设备处于交互状态,也是直接发送给用户。也就是说,如果显示屏处于亮屏状态,monkey 注入的触摸事件,也是直接发送给窗口的。 

        最后还要注意一件事,如果一个触摸事件是不受信任的事件,或者是注入事件,当设备处于非交互状态下(通常指灭屏),那么它不经过截断策略,也不会发送给用户,也就是会被丢弃。

        在实际工作中处理的触摸事件,通常都是来自输入设备,它肯定是受信任的,而且非注入的,因此它只有在设备处于非交互状态下(一般指灭屏)下,非会执行截断策略,而如果设备处于交互状态(通常指亮屏),会被直接分发给窗口。

3.2.1 PhoneWindowManager.interceptMotionBeforeQueueingNonInteractive截断策略实现

/frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java

 public int interceptMotionBeforeQueueingNonInteractive(int displayId, long whenNanos,
            int policyFlags) {
        // 如果策略要求唤醒屏幕,那么截断这个触摸事件
        // 一般来说,唤醒屏幕的策略取决于设备的配置文件
        if ((policyFlags & FLAG_WAKE) != 0) {
            if (wakeUp(whenNanos / 1000000, mAllowTheaterModeWakeFromMotion,
                    PowerManager.WAKE_REASON_WAKE_MOTION, "android.policy:MOTION")) {
                // 返回 0,表示截断触摸事件
                return 0;
            }
        }

        // 判断非交互状态下,是否截断事件
        if (shouldDispatchInputWhenNonInteractive(displayId, KEYCODE_UNKNOWN)) {
            // 返回这个值,表示不截断事件,也就是事件分发给用户
            return ACTION_PASS_TO_USER;
        }

        // 忽略 theater mode
        if (isTheaterModeEnabled() && (policyFlags & FLAG_WAKE) != 0) {
            wakeUp(whenNanos / 1000000, mAllowTheaterModeWakeFromMotionWhenNotDreaming,
                    PowerManager.WAKE_REASON_WAKE_MOTION, "android.policy:MOTION");
        }

        // 默认截断触摸事件
        // 返回0,表示截断事件
        return 0;
    }

    private boolean shouldDispatchInputWhenNonInteractive(int displayId, int keyCode) {
        // Apply the default display policy to unknown displays as well.
        final boolean isDefaultDisplay = displayId == DEFAULT_DISPLAY
                || displayId == INVALID_DISPLAY;
        final Display display = isDefaultDisplay
                ? mDefaultDisplay
                : mDisplayManager.getDisplay(displayId);
        final boolean displayOff = (display == null
                || display.getState() == STATE_OFF);

        if (displayOff && !mHasFeatureWatch) {
            return false;
        }

        // displayOff 表示屏幕处于 off 状态,但是非 off 状态,并不表示一定是亮屏状态
        // 对于 doze 状态,屏幕处于 on 状态,但是屏幕可能仍然是黑的
        // 因此,只要屏幕处于 on 状态,并且显示了锁屏,触摸事件不会截断
        if (isKeyguardShowingAndNotOccluded() && !displayOff) {
            return true;
        }

        // 对于触摸事件,keyCode 的值为 KEYCODE_UNKNOWN
        if (mHasFeatureWatch && (keyCode == KeyEvent.KEYCODE_BACK
                || keyCode == KeyEvent.KEYCODE_STEM_PRIMARY
                || keyCode == KeyEvent.KEYCODE_STEM_1
                || keyCode == KeyEvent.KEYCODE_STEM_2
                || keyCode == KeyEvent.KEYCODE_STEM_3)) {
            return false;
        }

        // 对于默认屏幕,如果设备处于梦境状态,那么触摸事件不截断
        // 因为 doze 组件需要接收触摸事件,可能会唤醒屏幕
        if (isDefaultDisplay) {
            IDreamManager dreamManager = getDreamManager();
            try {
                if (dreamManager != null && dreamManager.isDreaming()) {
                    return true;
                }
            } catch (RemoteException e) {
                Slog.e(TAG, "RemoteException when checking if dreaming", e);
            }
        }

        // Otherwise, consume events since the user can't see what is being
        // interacted with.
        return false;
    }    

         截断策略是否截断触摸事件,取决于策略的返回值,有两种情况:

  1.  返回 0,表示截断触摸事件。
  2.  返回 ACTION_PASS_TO_USER ,表示不截断触摸事件,也就是把触摸事件分发给用户/窗口。

        下面列举触摸事件截断与否的情况,但是要注意一个前提,设备处于非交互状态(一般就是指灭屏状态):

  • 事件会被传递给用户,也就是不截断,情况如下:
    • 有锁屏,并且显示屏处于非 off 状态。注意,非 off 状态,并不是表示屏幕处于 on(亮屏) 状态,也可能是 doze 状态(屏幕处于低电量状态),doze 状态屏幕也是黑的。
    • 梦境状态。因为梦境状态下会运行 doze 组件。
  • 事件被截断,情况如下:
    • 策略标志位包含 FLAG_WAKE ,它会导致屏幕被唤醒,因此需要截断触摸事件。FLAG_WAKE 一般来自于输入设备的配置文件。
    • 没有锁屏,没有梦境,也没有 FLAG_WAKE,默认就会截断。

        从上面的分析可以总结出了两条结论:

  1.  如果系统有组件在运行,例如,锁屏、doze组件,那么触摸事件需要分发到这些组件,因此不会被截断。
  2.  如果没有组件运行,触摸事件都会被截断。触摸事件由于需要唤醒屏幕,而导致被截断,只是其中一个特例。

        注意:这里的所有操作,不是发生在 InputDispatcher 线程,而是发生在 InputReader 线程,这个线程是负责不断地读取事件,因此这里的查询策略是否截断事件的过程,时间不能太长,否则影响了输入系统读取事件。

3.3 InputDispatcher.enqueueInboundEventLocked 收件箱接收事件

 /frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp

  bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {
    // mInboundQueue 队列为空,需要唤醒 InputDispatcher 线程来处理事件
      bool needWake = mInboundQueue.empty();
    // 加入到 mInboundQueue 中
      mInboundQueue.push_back(entry);
      traceInboundQueueLengthLocked();
  
      switch (entry->type) {
          ..........
  
          case EventEntry::Type::MOTION: {
            // 判断传入的动作事件之前的事件是否应该被丢弃
              if (shouldPruneInboundQueueLocked(static_cast<MotionEntry&>(*entry))) {
                  mNextUnblockedEvent = entry;
                  needWake = true;
              }
              break;
          }
          ...............
      }
  
      return needWake;
       }

         InputDispatcher::mInboundQueue 是 InputDispatcher 的事件收件箱,所有的事件,包括注入事件,都会加入这个收件箱。就好像收件箱接收到"邮件"后,就需要唤醒 InputDispatcher 线程来处理"邮件"

3.4 InputDispatcher.dispatchOnce分发触摸事件

   /frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp

void InputDispatcher::dispatchOnce() {
    nsecs_t nextWakeupTime = LONG_LONG_MAX;
    { // acquire lock
        std::scoped_lock _l(mLock);
        mDispatcherIsAlive.notify_all();

        if (!haveCommandsLocked()) {
            // 分发一个触摸事件
            dispatchOnceInnerLocked(&nextWakeupTime);
        }

        // 触摸事件的分发过程不会产生命令
        if (runCommandsLockedInterruptible()) {
            nextWakeupTime = LONG_LONG_MIN;
        }

        // 计算线程下次唤醒的时间点,以便处理 anr
        const nsecs_t nextAnrCheck = processAnrsLocked();
        nextWakeupTime = std::min(nextWakeupTime, nextAnrCheck);

        if (nextWakeupTime == LONG_LONG_MAX) {
            mDispatcherEnteredIdle.notify_all();
        }
    } // release lock

    // 线程休眠指定的时长
    nsecs_t currentTime = now();
    int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime);
    mLooper->pollOnce(timeoutMillis);
}

  一次线程循环处理触摸事件的过程如下: 

  • 分发一个触摸事件。
  • 当事件分发给窗口后,会计算一个窗口反馈的超时时间,利用这个时间,计算线程下次唤醒的时间点。
  • 利用上一步计算出的线程唤醒的时间点,计算出线程最终需要休眠多长时间。当线程被唤醒后,会检查接收触摸时间的窗口,是否反馈超时,如果超时,会引发 ANR。

3.5 InputDispatcher.dispatchOnceInnerLocked

 /frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp

void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
   .............
    // 这里是优化 app 切换的延迟
    // mAppSwitchDueTime 是 app 切换的超时时间,如果小于当前时间,那么表明app切换超时了
    // 如果app切换超时,那么在app切换按键事件之前的未处理的事件,都将会被丢弃
    bool isAppSwitchDue = mAppSwitchDueTime <= currentTime;
    if (mAppSwitchDueTime < *nextWakeupTime) {
        *nextWakeupTime = mAppSwitchDueTime;
    }

    // mPendingEvent 表示正在处理的事件
    if (!mPendingEvent) {
        if (mInboundQueue.empty()) {
            // ...
        } else {
            // 从收件箱队列中取出事件
            mPendingEvent = mInboundQueue.front();
            mInboundQueue.pop_front();
            traceInboundQueueLengthLocked();
        }

        // 如果这个事件需要传递给用户,那么需要同上层的 PowerManagerService,此时有用户行为,这个作用就是延长亮屏的时间
        if (mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER) {
            pokeUserActivityLocked(*mPendingEvent);
        }
    }

    ALOG_ASSERT(mPendingEvent != nullptr);
    bool done = false;
    // 检测丢弃事件的原因
    DropReason dropReason = DropReason::NOT_DROPPED;
    if (!(mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER)) {
        // 被截断策略截断
        dropReason = DropReason::POLICY;
    } else if (!mDispatchEnabled) {
        // 一般是由于系统正在系统或者正在关闭
        dropReason = DropReason::DISABLED;
    }

    .....

    switch (mPendingEvent->type) {
        // ....

        case EventEntry::Type::MOTION: {
            std::shared_ptr<MotionEntry> motionEntry =
                    std::static_pointer_cast<MotionEntry>(mPendingEvent);
            if (dropReason == DropReason::NOT_DROPPED && isAppSwitchDue) {
                // app 切换超时,导致触摸事件被丢弃
                dropReason = DropReason::APP_SWITCH;
            }
            if (dropReason == DropReason::NOT_DROPPED && isStaleEvent(currentTime, *motionEntry)) {
                // 10s 之前的事件,已经过期
                dropReason = DropReason::STALE;
            }
            // 这里是优化应用无响应的一个措施,会丢弃mNextUnblockedEvent之前的所有触摸事件
            if (dropReason == DropReason::NOT_DROPPED && mNextUnblockedEvent) {
                dropReason = DropReason::BLOCKED;
            }
            // 分发触摸事件
            done = dispatchMotionLocked(currentTime, motionEntry, &dropReason, nextWakeupTime);
            break;
        }

     ...
    }

    // 如果事件被处理,重置一些状态,例如 mPendingEvent
    // 返回 true,就表示已经处理了事件
    // 事件被丢弃,或者发送完毕,都会返回 true
    // 返回 false,表示暂时不知道如何处理事件,因此线程会休眠
    // 然后,线程再次被唤醒时,再来处理这个事件
    if (done) {
        if (dropReason != DropReason::NOT_DROPPED) {
            dropInboundEventLocked(*mPendingEvent, dropReason);
        }
        mLastDropReason = dropReason;
        // 重置 mPendingEvent
        releasePendingEventLocked();
        // 立即唤醒,处理下一个事件
        *nextWakeupTime = LONG_LONG_MIN; // force next poll to wake up immediately
    }
}

 3.6 InputDispatcher.dispatchMotionLocked

  /frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp

bool InputDispatcher::dispatchMotionLocked(nsecs_t currentTime, std::shared_ptr<MotionEntry> entry,
                                           DropReason* dropReason, nsecs_t* nextWakeupTime) {
    .........
    // 触摸事件有原因需要丢弃,那么不走后面的分发流程
    if (*dropReason != DropReason::NOT_DROPPED) {
        setInjectionResult(*entry,
                           *dropReason == DropReason::POLICY ? InputEventInjectionResult::SUCCEEDED
                                                             : InputEventInjectionResult::FAILED);
        return true;
    }

    bool isPointerEvent = entry->source & AINPUT_SOURCE_CLASS_POINTER;

    std::vector<InputTarget> inputTargets;

    bool conflictingPointerActions = false;
    InputEventInjectionResult injectionResult;
    if (isPointerEvent) {
        // 寻找触摸的窗口,窗口保存到 inputTargets
        // 为触摸事件,寻找触摸的窗口
        // 触摸的窗口保存到 inputTargets 中
        injectionResult =
                findTouchedWindowTargetsLocked(currentTime, *entry, inputTargets, nextWakeupTime,
                                               &conflictingPointerActions);
    } else {
      ...
    }
    
    if (injectionResult == InputEventInjectionResult::PENDING) {
        // 返回 false,表示暂时不知道如何处理这个事件,这会导致线程休眠
        // 等线程下次被唤醒时,再来处理这个事件
        return false;
    }
    
    // 走到这里,表示触摸事件已经被处理,因此保存处理的结果
    // 只要返回的不是 InputEventInjectionResult::PENDING
    // 都表示事件被处理,无论是权限拒绝还是失败,或是成功
    setInjectionResult(*entry, injectionResult);
    
    if (injectionResult == InputEventInjectionResult::PERMISSION_DENIED) {
        ALOGW("Permission denied, dropping the motion (isPointer=%s)", toString(isPointerEvent));
        return true;
    }
    if (injectionResult != InputEventInjectionResult::SUCCEEDED) {
        CancelationOptions::Mode mode(isPointerEvent
                                              ? CancelationOptions::CANCEL_POINTER_EVENTS
                                              : CancelationOptions::CANCEL_NON_POINTER_EVENTS);
        CancelationOptions options(mode, "input event injection failed");
        synthesizeCancelationEventsForMonitorsLocked(options);
        return true;
    }
    
    // 走到这里,表示触摸事件已经成功找到触摸的窗口

    // Add monitor channels from event's or focused display.
    // 触摸事件找到了触摸窗口,在分发给窗口前,保存 global monitor 到 inputTargets 中
    // 开发者选项中的 Show taps 和 Pointer location,利用的 global monitor
    addGlobalMonitoringTargetsLocked(inputTargets, getTargetDisplayId(*entry));

    if (isPointerEvent) {
        // ... portal window 处理的代码
    }

    if (conflictingPointerActions) {
        // ...
    }

    // 分发事件给 inputTargets 中的所有窗口
    dispatchEventLocked(currentTime, entry, inputTargets);
    return true;
}

 3.7 InputDispatcher.findTouchedWindowTargetsLocked寻找触摸的窗口

  /frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp

int32_t InputDispatcher::findTouchedWindowTargetsLocked(
        nsecs_t currentTime, const MotionEntry& entry, std::vector<InputTarget>& inputTargets,
        nsecs_t* nextWakeupTime, bool* outConflictingPointerActions) {
   ...
    
    // 对于非 DOWN 事件,获取已经 DOWN 事件保存的 TouchState
    // TouchState 保存了接收 DOWN 事件的窗口
    const TouchState* oldState = nullptr;
    TouchState tempTouchState;
    std::unordered_map<int32_t, TouchState>::iterator oldStateIt =
            mTouchStatesByDisplay.find(displayId);
    if (oldStateIt != mTouchStatesByDisplay.end()) {
        oldState = &(oldStateIt->second);
        tempTouchState.copyFrom(*oldState);
    }
    
    ...

    // 第一个条件 newGesture 表示第一个手指按下
    // 后面一个条件,表示当前窗口支持 split motion,并且此时有另外一个手指按下
    if (newGesture || (isSplit && maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN)) {
        /* Case 1: New splittable pointer going down, or need target for hover or scroll. */

        // 触摸点的获取 x, y 坐标
        int32_t x;
        int32_t y;
        int32_t pointerIndex = getMotionEventActionPointerIndex(action);
        if (isFromMouse) {
            // ...
        } else {
            x = int32_t(entry.pointerCoords[pointerIndex].getAxisValue(AMOTION_EVENT_AXIS_X));
            y = int32_t(entry.pointerCoords[pointerIndex].getAxisValue(AMOTION_EVENT_AXIS_Y));
        }

        // 这里检测是否是第一个手指按下
        bool isDown = maskedAction == AMOTION_EVENT_ACTION_DOWN;

        // 对于 DOWN 事件,根据触摸事件的x,y坐标,寻找触摸窗口
        // 参数 addOutsideTargets 表示,只有在第一个手指按下时,如果没有找到触摸的窗口,
        // 那么需要保存那些可以接受 OUTSIZE 事件的窗口到 tempTouchState
        newTouchedWindowHandle =
                findTouchedWindowAtLocked(displayId, x, y, &tempTouchState,
                                          isDown /*addOutsideTargets*/, true /*addPortalWindows*/);


        // ... 处理窗口异常的情况 ...

        // 获取所有的 getsture monitor
        const std::vector<TouchedMonitor> newGestureMonitors = isDown
                ? selectResponsiveMonitorsLocked(
                          findTouchedGestureMonitorsLocked(displayId, tempTouchState.portalWindows))
                : tempTouchState.gestureMonitors;

        // 既没有找到触摸点所在的窗口,也没有找到 gesture monitor,那么此次寻找触摸窗口的任务就失败了
        if (newTouchedWindowHandle == nullptr && newGestureMonitors.empty()) {
            ALOGI("Dropping event because there is no touchable window or gesture monitor at "
                  "(%d, %d) in display %" PRId32 ".",
                  x, y, displayId);
            injectionResult = InputEventInjectionResult::FAILED;
            goto Failed;
        }

        // 走到这里,表示找到了触摸的窗口,或者找到 gesture monitor

        if (newTouchedWindowHandle != nullptr) {
            // 马上要保存窗口了,现在获取窗口的 flag
            int32_t targetFlags = InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS;
            if (isSplit) {
                targetFlags |= InputTarget::FLAG_SPLIT;
            }
            if (isWindowObscuredAtPointLocked(newTouchedWindowHandle, x, y)) {
                targetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED;
            } else if (isWindowObscuredLocked(newTouchedWindowHandle)) {
                targetFlags |= InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
            }

            // Update hover state.
            if (maskedAction == AMOTION_EVENT_ACTION_HOVER_EXIT) {
                newHoverWindowHandle = nullptr;
            } else if (isHoverAction) {
                newHoverWindowHandle = newTouchedWindowHandle;
            }

            // Update the temporary touch state.
            // 如果窗口支持 split,那么用 tempTouchState 保存窗口的时候,要特别保存 pointer id
            BitSet32 pointerIds;
            if (isSplit) {
                uint32_t pointerId = entry.pointerProperties[pointerIndex].id;
                pointerIds.markBit(pointerId);
            }
            
            // tempTouchState 保存找到的触摸的窗口
            // 如果是真的找到的触摸窗口,那么这里就是保存,如果是找到可以接受 OUTSIDE 的窗口,那么这里是更新
            tempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds);
        } else if (tempTouchState.windows.empty()) {
            // If no window is touched, set split to true. This will allow the next pointer down to
            // be delivered to a new window which supports split touch.
            tempTouchState.split = true;
        }
        if (isDown) {
            // tempTouchState 保存所有的 gesture monitor
            // 第一个手指按下时,tempTouchState 保存 gesture monitor
            tempTouchState.addGestureMonitors(newGestureMonitors);
        }
    } else {
        ...
    }

    if (newHoverWindowHandle != mLastHoverWindowHandle) {
        ....
    }

    {
        // 权限检测 ...
    }

    // 保存接收 AMOTION_EVENT_ACTION_OUTSIDE 的窗口
    if (maskedAction == AMOTION_EVENT_ACTION_DOWN) {
        // ...
    }

    
    // 第一个手指按下时,保存壁纸窗口
    if (maskedAction == AMOTION_EVENT_ACTION_DOWN) { // 
        // ...
    }
    
    // 走到这里,表示没有异常情况了

    injectionResult = InputEventInjectionResult::SUCCEEDED;

    // 把 tempTouchState 保存了触摸窗口和gesture monitor,保存到 inputTargets 中
    for (const TouchedWindow& touchedWindow : tempTouchState.windows) {
        addWindowTargetLocked(touchedWindow.windowHandle, touchedWindow.targetFlags,
                              touchedWindow.pointerIds, inputTargets);
    }
    for (const TouchedMonitor& touchedMonitor : tempTouchState.gestureMonitors) {
        addMonitoringTargetLocked(touchedMonitor.monitor, touchedMonitor.xOffset,
                                  touchedMonitor.yOffset, inputTargets);
    }

    // Drop the outside or hover touch windows since we will not care about them
    // in the next iteration.
    tempTouchState.filterNonAsIsTouchWindows();

Failed:
    // ...
    
    // 缓存 tempTouchState
    if (maskedAction != AMOTION_EVENT_ACTION_SCROLL) {
        if (tempTouchState.displayId >= 0) {
            mTouchStatesByDisplay[displayId] = tempTouchState;
        } else {
            mTouchStatesByDisplay.erase(displayId);
        }
    } 

    return injectionResult;
}

 对于 DOWN 事件   

  • 根据 x,y 坐标寻找触摸的窗口。
  • 获取所有的 gesture monitor 窗口 。
  • 把触摸窗口保存到 tempTouchState 中。
  • 把所有的 gesture monitor 窗口保存到 tempTouchState 中。
  • 为 tempTouchState 保存所有窗口,创建 InputTarget 对象,并保存到参数 inputTargets 中。
  • 使用 mTouchStatesByDisplay 缓存 tempTouchState。

gesture monitor 是为了实现手势功能而添加的一个窗口。什么是手势功能? 例如在屏幕的左边/右边,向屏幕中央滑动,会触发返回手势。

对于非 DOWN 事件,一般为 MOVE, UP 事件:

  • 获取 DOWN 事件缓存的 tempTouchState。 因为 tempTouchState 保存了处理 DOWN 事件的触摸窗口和 gesture monitor,非 DOWN 事件,也会发送给这些窗口。
  • 重复 DOWN 事件的第5步。

 这个方法代码量很庞大,主要作用就是为触摸事件寻找触摸窗口,最终的结果就是把找到的窗口保存到参数 inputTargets 中,后面会把事件分发给 inputTargets 保存的窗口。

3.8 InputDispatcher.findTouchedWindowAtLocked根据坐标找到触摸窗口

/frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp

// addOutsideTargets 在第一个手指按下是为 true
// addPortalWindows 值为 true
// ignoreDragWindow 默认为 false
sp<InputWindowHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t displayId, int32_t x,
                                                                 int32_t y, TouchState* touchState,
                                                                 bool addOutsideTargets,
                                                                 bool addPortalWindows,
                                                                 bool ignoreDragWindow) {
    if ((addPortalWindows || addOutsideTargets) && touchState == nullptr) {
        LOG_ALWAYS_FATAL(
                "Must provide a valid touch state if adding portal windows or outside targets");
    }
    // Traverse windows from front to back to find touched window.
    // 从前到后,遍历窗口
    const std::vector<sp<InputWindowHandle>>& windowHandles = getWindowHandlesLocked(displayId);
    for (const sp<InputWindowHandle>& windowHandle : windowHandles) {
        // ignoreDragWindow 默认为 false
        if (ignoreDragWindow && haveSameToken(windowHandle, mDragState->dragWindow)) {
            continue;
        }
        // 获取窗口信息
        const InputWindowInfo* windowInfo = windowHandle->getInfo();
        // 匹配属于特定屏幕的窗口
        if (windowInfo->displayId == displayId) {
            auto flags = windowInfo->flags;

            // 窗口要可见
            if (windowInfo->visible) {
                // 窗口要可触摸
                if (!flags.test(InputWindowInfo::Flag::NOT_TOUCHABLE)) {
                    // 检测是否为触摸模型: 可获取焦点,并且不允许窗口之外的触摸事件发送到它后面的窗口
                    bool isTouchModal = !flags.test(InputWindowInfo::Flag::NOT_FOCUSABLE) &&
                            !flags.test(InputWindowInfo::Flag::NOT_TOUCH_MODAL);
                    // 窗口是触摸模型,或者触摸的坐标点落在窗口上
                    if (isTouchModal || windowInfo->touchableRegionContainsPoint(x, y)) {
                        int32_t portalToDisplayId = windowInfo->portalToDisplayId;

                        // 如果是 portal window
                        if (portalToDisplayId != ADISPLAY_ID_NONE &&
                            portalToDisplayId != displayId) {
                            if (addPortalWindows) {
                                // For the monitoring channels of the display.
                                // touchState 保存 portal window
                                touchState->addPortalWindow(windowHandle);
                            }
                            // 递归调用,获取 portal display id 下的触摸窗口
                            return findTouchedWindowAtLocked(portalToDisplayId, x, y, touchState,
                                                             addOutsideTargets, addPortalWindows);
                        }

                        // 不是 portal window,直接返回找到的窗口
                        return windowHandle;
                    }
                }

                // 走到这里,表示没有找到触摸窗口。也就是说,既没有找到触摸模型的窗口,也没有找到包含触摸点的窗口

                // 当第一个手指按下是,addOutsideTargets 值为 true
                // NOT_TOUCH_MODAL 和 WATCH_OUTSIDE_TOUCH 一起使用,当第一个手指按下时,如果落在窗口之外
                // 窗口会收到 MotionEvent.ACTION_OUTSIDE 事件
                if (addOutsideTargets && flags.test(InputWindowInfo::Flag::WATCH_OUTSIDE_TOUCH)) {
                    touchState->addOrUpdateWindow(windowHandle,
                                                  InputTarget::FLAG_DISPATCH_AS_OUTSIDE,
                                                  BitSet32(0));
                }
            }
        }
    }
    return nullptr;
}

 寻找触摸点所在的窗口,其实就是从上到下遍历所有窗口,然后找到满足条件的窗口。

窗口首先要满足前置条件:

  • 窗口要在指定屏幕上。
  • 窗口要可见。
  • 窗口要可触摸。

满足了所有的前置条件后,只要满足以下任意一个条件,那么就找到了触摸点所在的窗口:

  • 是触摸模型的窗口: 可获取焦点,并且不允许窗口之外的触摸事件发送到它后面的窗口。
  • 触摸点的 x,y 坐标落在窗口坐标系中。

3.9 InputDispatcher.addWindowTargetLocked保存窗口

/frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp 

void InputDispatcher::addWindowTargetLocked(const sp<InputWindowHandle>& windowHandle,
                                            int32_t targetFlags, BitSet32 pointerIds,
                                            std::vector<InputTarget>& inputTargets) {
    std::vector<InputTarget>::iterator it =
            std::find_if(inputTargets.begin(), inputTargets.end(),
                         [&windowHandle](const InputTarget& inputTarget) {
                             return inputTarget.inputChannel->getConnectionToken() ==
                                     windowHandle->getToken();
                         });

    const InputWindowInfo* windowInfo = windowHandle->getInfo();

    // 创建 InputTarget,并保存到参数 inputTargets
    if (it == inputTargets.end()) {
        InputTarget inputTarget;
        std::shared_ptr<InputChannel> inputChannel =
                getInputChannelLocked(windowHandle->getToken());
        if (inputChannel == nullptr) {
            ALOGW("Window %s already unregistered input channel", windowHandle->getName().c_str());
            return;
        }
        inputTarget.inputChannel = inputChannel;
        inputTarget.flags = targetFlags;
        inputTarget.globalScaleFactor = windowInfo->globalScaleFactor;
        inputTarget.displaySize =
                int2(windowHandle->getInfo()->displayWidth, windowHandle->getInfo()->displayHeight);
        inputTargets.push_back(inputTarget);
        it = inputTargets.end() - 1;
    }

    ALOG_ASSERT(it->flags == targetFlags);
    ALOG_ASSERT(it->globalScaleFactor == windowInfo->globalScaleFactor);

    // 保存 InputTarget 后,在保存窗口的坐标转换参数,
    // 这个参数可以把显示屏的坐标,转换为窗口的坐标
    it->addPointers(pointerIds, windowInfo->transform);
}

// InputDispatcher 保存 gesture monitor
void InputDispatcher::addMonitoringTargetLocked(const Monitor& monitor, float xOffset,
                                                float yOffset,
                                                std::vector<InputTarget>& inputTargets) {
    InputTarget target;
    target.inputChannel = monitor.inputChannel;
    target.flags = InputTarget::FLAG_DISPATCH_AS_IS;
    ui::Transform t;
    t.set(xOffset, yOffset);
    target.setDefaultPointerTransform(t);
    inputTargets.push_back(target);
}

         对于触摸事件,无论是触摸窗口,还是 gesture monitor,都会被转化为 InputTarget,然后保存到参数 inputTargets 中。当后面启动分发循环后,触摸事件就会发送到 inputTargets 保存的窗口中。

3.10 InputDispatcher.dispatchEventLocked分发事件给目标窗口

        现在,处理触摸事件的焦点窗口已经找到,并且已经保存到 inputTargets,是时候来分发按键事件了:

/frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp

void InputDispatcher::dispatchEventLocked(nsecs_t currentTime,
                                          std::shared_ptr<EventEntry> eventEntry,
                                          const std::vector<InputTarget>& inputTargets) {
    updateInteractionTokensLocked(*eventEntry, inputTargets);

    pokeUserActivityLocked(*eventEntry);

    for (const InputTarget& inputTarget : inputTargets) {
        // 获取目标窗口的连接
        sp<Connection> connection =
                getConnectionLocked(inputTarget.inputChannel->getConnectionToken());
        if (connection != nullptr) {
            // 准备分发循环
            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().c_str());
            }
        }
    }
}

        焦点窗口只有一个,为何需要一个 inputTargets 集合来保存所有的目标窗口?因为根据前面的分析,除了焦点窗口以外,还有一个全局的监听事件的输入目标。

        WindowManagerService 会在创建窗口时,创建一个连接,其中一端给窗口,另外一端给输入系统。当输入系统需要发送事件给窗口时,就会通过这个连接进行发送。   

        找到这个窗口的连接后,就准备分发循环 ? 问题来了,什么是分发循环 ? InputDispatcher 把一个事件发送给窗口,窗口处理完事件,然后返回结果为 InputDispatcher,这就是一个循环。但是注意,分发事件给窗口,窗口返回处理事件结果,这两个是互为异步过程。

3.11 InputDispatcher.prepareDispatchCycleLocked分发循环之前的准备

/frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp

void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
                                                 const sp<Connection>& connection,
                                                 std::shared_ptr<EventEntry> eventEntry,
                                                 const InputTarget& inputTarget) {
     ...

    // 连接处理异常状态,丢弃事件
    if (connection->status != Connection::STATUS_NORMAL) {
#if DEBUG_DISPATCH_CYCLE
        ALOGD("channel '%s' ~ Dropping event because the channel status is %s",
              connection->getInputChannelName().c_str(), connection->getStatusLabel());
#endif
        return;
    }

    // Split a motion event if needed.
    // 针对触摸事件的split
    if (inputTarget.flags & InputTarget::FLAG_SPLIT) {
         ...
    }

    // 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,
                                                   std::shared_ptr<EventEntry> eventEntry,
                                                   const InputTarget& inputTarget) {
     ...

    bool wasEmpty = connection->outboundQueue.empty();

    // Enqueue dispatch entries for the requested modes.
    // 保存事件到连接的发件箱 Connection::outboundQueue 
    // 注意最后一个参数,它的窗口的分发模式,定义了事件如何分发到指定窗口
    // 根据前面的代码分析,目前保存的目标窗口的分发模式只支持下面列举的 InputTarget::FLAG_DISPATCH_AS_IS 
    // InputTarget::FLAG_DISPATCH_AS_IS 表示事件按照原样进行发送
    enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
                               InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT);
    enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
                               InputTarget::FLAG_DISPATCH_AS_OUTSIDE);
    enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
                               InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER);
    enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
                               InputTarget::FLAG_DISPATCH_AS_IS);
    enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
                               InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT);
    enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
                               InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER);

    // If the outbound queue was previously empty, start the dispatch cycle going.
    // 连接的发件箱突然有事件了,那得启动分发循环,把事件发送到指定窗口
    if (wasEmpty && !connection->outboundQueue.empty()) {
        // 启动分发循环
        startDispatchCycleLocked(currentTime, connection);
    }
}

           分发循环前的准备工作,其实就是根据窗口所支持的分发模式(dispatche mode),调用enqueueDispatchEntryLocked() 创建并保存事件到连接的收件箱。前面分析过,焦点窗口的的分发模式为 InputTarget::FLAG_DISPATCH_AS_IS | InputTarget::FLAG_FOREGROUND,而此时只用到了InputTarget::FLAG_DISPATCH_AS_IS

        如果连接的收件箱之前没有事件,那么证明连接没有处于发送事件的状态中,而现在有事件了,那就启动分发循环来发送事件。

3.12 InputDispatcher.enqueueDispatchEntryLocked根据分发模式,添加事件到连接收件箱

/frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp 

void InputDispatcher::enqueueDispatchEntryLocked(const sp<Connection>& connection,
                                                 std::shared_ptr<EventEntry> eventEntry,
                                                 const InputTarget& inputTarget,
                                                 int32_t dispatchMode) {
    ...

    // 前面保存的 InputTarget,它的 flags 为 InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS
    int32_t inputTargetFlags = inputTarget.flags;

    // 窗口不支持请求的dispatcher mode,那么不添加事件到连接的发件箱中
    // 对于按键事件,dispatchMode 只能是 InputTarget::FLAG_DISPATCH_AS_IS
    if (!(inputTargetFlags & dispatchMode)) {
        return;
    }

    // 为每一个窗口所支持的 dispatche mode,创建一个 DispatchEntry
    inputTargetFlags = (inputTargetFlags & ~InputTarget::FLAG_DISPATCH_MASK) | dispatchMode;
    std::unique_ptr<DispatchEntry> dispatchEntry =
            createDispatchEntry(inputTarget, eventEntry, inputTargetFlags);

    // Use the eventEntry from dispatchEntry since the entry may have changed and can now be a
    // different EventEntry than what was passed in.
    EventEntry& newEntry = *(dispatchEntry->eventEntry);
    // Apply target flags and update the connection's input state.
    switch (newEntry.type) {
         case EventEntry::Type::MOTION: {

              break;
         }
        }

        ...
    }

    // Remember that we are waiting for this dispatch to complete.
    // 检测事件是否正在发送到前台窗应用,根据前面的代码分析,目标窗口的flags包括 FLAG_FOREGROUND
    // 因此,条件成立
    if (dispatchEntry->hasForegroundTarget()) {
        // EventEntry::injectionState::pendingForegroundDispatches +1
        incrementPendingForegroundDispatches(newEntry);
    }

    //把 DispatchEntry 加入到连接的发件箱中
    connection->outboundQueue.push_back(dispatchEntry.release());
    traceOutboundQueueLength(*connection);
}

根据前面创建 InputTarget 的代码可知,InputTarget::flags 的值为 InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS

InputTarget::FLAG_FOREGROUND 表明事件正在发送给前台应用,InputTarget::FLAG_DISPATCH_AS_IS 表示事件按照原样进行发送。

3.13 InputDispatcher.startDispatchCycleLocked启动分发循环

/frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp 

void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
                                               const sp<Connection>& connection) {
    ...

    // 遍历连接发件箱中的所有事件,逐个发送给目标窗口
    while (connection->status == Connection::STATUS_NORMAL && !connection->outboundQueue.empty()) {
        DispatchEntry* dispatchEntry = connection->outboundQueue.front();
        dispatchEntry->deliveryTime = currentTime;
        // 计算事件分发的超时时间
        const std::chrono::nanoseconds timeout =
                getDispatchingTimeoutLocked(connection->inputChannel->getConnectionToken());
        dispatchEntry->timeoutTime = currentTime + timeout.count();

        // Publish the event.
        status_t status;
        const EventEntry& eventEntry = *(dispatchEntry->eventEntry);
        switch (eventEntry.type) {
            case EventEntry::Type::MOTION: {
                MotionEntry* motionEntry = static_cast<MotionEntry*>(eventEntry);
                std::array<uint8_t, 32> hmac = getSignature(keyEntry, *dispatchEntry);
                ....
                // 1. 发送触摸事件
                status = connection->inputPublisher
                                 .publishMotionEvent(.......);
                break;
            }

             ...
        }

        // Check the result.
        if (status) {
            // 发送异常
            if (status == WOULD_BLOCK) {
                ...
            }
            return;
        }
        
        // 走到这里,表示事件发送成功

        // 事件发送成功,那么从连接的发件箱中移除
        connection->outboundQueue.erase(std::remove(connection->outboundQueue.begin(),
                                                    connection->outboundQueue.end(),
                                                    dispatchEntry));
        traceOutboundQueueLength(*connection);
        // 3把已经发送的事件,加入到连接的等待队列中 Connection::waitQueue
        // 连接在等待什么呢?当然是等到窗口的处理结果
        connection->waitQueue.push_back(dispatchEntry);

        // 连接可响应,那么会记录事件处理的超时时间,一旦超时,会引发 ANR
        // 因为我们不可能无限等待窗口处理完事件,后面还有好多事件要处理呢
        // 用 AnrTracker 记录事件处理的超时时间
        if (connection->responsive) {
            mAnrTracker.insert(dispatchEntry->timeoutTime,
                               connection->inputChannel->getConnectionToken());
        }
        traceWaitQueueLength(*connection);
    }
}

 事件分发循环的过程如下:

  1. 通过窗口连接,把事件发送给窗口,并从连接的发件箱 Connection::outboundQueue 中移除。
  2. 把刚刚发送的事件,保存到连接的等待队列 Connection::waitQueue。连接在等待什么呢?当然是等到窗口的处理结果。
  3. 用 AnrTracker 记录事件处理的超时时间,如果事件处理超时,会引发 ANR。

3.14 InputPublisher.publishMotionEvent

/frameworks/native/libs/input/InputTransport.cpp

status_t InputPublisher::publishMotionEvent(
        uint32_t seq, int32_t eventId, int32_t deviceId, int32_t source, int32_t displayId,
        std::array<uint8_t, 32> hmac, int32_t action, int32_t actionButton, int32_t flags,
        int32_t edgeFlags, int32_t metaState, int32_t buttonState,
        MotionClassification classification, float xScale, float yScale, float xOffset,
        float yOffset, float xPrecision, float yPrecision, float xCursorPosition,
        float yCursorPosition, nsecs_t downTime, nsecs_t eventTime, uint32_t pointerCount,
        const PointerProperties* pointerProperties, const PointerCoords* pointerCoords) {
    ...................
        
    // 根据event信息构建InputMessage
    InputMessage msg;
    msg.header.type = InputMessage::Type::MOTION;
    msg.body.motion.seq = seq;
    msg.body.motion.eventId = eventId;
    msg.body.motion.deviceId = deviceId;
    msg.body.motion.source = source;
    msg.body.motion.displayId = displayId;
    msg.body.motion.hmac = std::move(hmac);
    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.classification = classification;
    .................

    // 通过InputChannel的sendMessage方法将event发送出去
    return mChannel->sendMessage(&msg);
}

 3.15 InputChannel.sendMessage

 /frameworks/native/libs/input/InputTransport.cpp

status_t InputChannel::sendMessage(const InputMessage* msg) {
    const size_t msgLength = msg->size();
    InputMessage cleanMsg;
    // copy一份msg
    msg->getSanitizedCopy(&cleanMsg);
    ssize_t nWrite;
    do {
        // 通过socket循环写入msg
        nWrite = ::send(mFd.get(), &cleanMsg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL);
    } while (nWrite == -1 && errno == EINTR);
    ..........
    return OK;
}

         sendMessage主要就是先copy一份事件msg,然后调用send将msg循环写入socket,从而实现输入事件的分发。

3.16 小结

  • InputReader 线程把事件加入到 InputDispatcher 的收件箱之前,会询问截断策略,如果策略截断了,那么事件最终不会发送给窗口。
  • InputDispatcher 通过一次线程循环来发送事件
  • 事件在发送之前,会循环分发策略。
  • 如果截断策略和分发策略都不截断事件,那么会寻找能处理事件的焦点窗口。
  • 焦点窗口找到了,那么会把事件加入到窗口连接的发件箱中。
  • 执行分发循环,从窗口连接的发件箱中获取事件,然后发送给窗口。然后把事件从发件箱中移除,并加入到连接的等待队列中。最后,记录 ANR 时间。
  • 窗口返回事件的处理结果,InputDispatcher 会读取结果,然后把事件从连接的等待队列中移除,然后解除 ANR 的触发。(这部分后面分析,应用进程处理完事件之后,也就是对应的view消费了事件之后会返回结果到inputDispatcher线程去处理)
  • 继续发送连接中的事件,并重复上述过程,直至连接中没有事件为止。

4. InputChannel的创建与初始化

         看完第三节的内容可以看到最后3.15小结会调用InputChannel里面的sendMessage会将消息发送给应用进程,里面的fd很关键,当fd 写入消息的时候,会唤醒处于epoll_wait 状态的线程(原理跟handler一样),接下来我们看看它是如何跟应用端的fd绑定的。

        InputChannel会作为句柄传递到下层,后面分发事件的时候会通过它来进行。而且这里会创建出两个,一个作为server端注册到InputManagerService,最终会注册到InputDispatcher中去,另一个则作为client端来接收server端的事件。

4.1 ViewRootImpl.setView创建InputChannel

 /frameworks/base/core/java/android/view/ViewRootImpl.java

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,
        int userId) {
    synchronized (this) {
        if (mView == null) {
            // .....
            InputChannel inputChannel = null;
            if ((mWindowAttributes.inputFeatures
                    & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
                inputChannel = new InputChannel();
            }
            // ...
            // 调用Session的addToDisplayAsUser方法来添加window,
            // 会初始化InputChannel
            res = mWindowSession.addToDisplayAsUser(mWindow, mSeq, mWindowAttributes,
                    getHostVisibility(), mDisplay.getDisplayId(), userId, mTmpFrame,
                    mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                    mAttachInfo.mDisplayCutout, inputChannel,
                    mTempInsets, mTempControls);
            // ...
            if (inputChannel != null) {
                if (mInputQueueCallback != null) {
                    mInputQueue = new InputQueue();
                    mInputQueueCallback.onInputQueueCreated(mInputQueue);
                }
                // 将InputChannel传入InputEventReceiver
                // 创建app端监听,即WindowInputEventReceiver 作为事件的接收端
                mInputEventReceiver = new WindowInputEventReceiver(inputChannel,
                        Looper.myLooper());
            }
            // ...
        }
    }
}

4.2 Session.addToDisplayAsUser

 /frameworks/base/services/core/java/com/android/server/wm/Session.java

public int addToDisplayAsUser(IWindow window, int seq, WindowManager.LayoutParams attrs,
        int viewVisibility, int displayId, int userId, Rect outFrame,
        Rect outContentInsets, Rect outStableInsets,
        DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,
        InsetsState outInsetsState, InsetsSourceControl[] outActiveControls) {
    // 直接调用WindowManagerService的addWindow方法
    return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outFrame,
            outContentInsets, outStableInsets, outDisplayCutout, outInputChannel,
            outInsetsState, outActiveControls, userId);
}

 4.3 WindowManagerService.addWindow

/frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java 

public int addWindow(Session session, IWindow client, int seq,
        LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame,
        Rect outContentInsets, Rect outStableInsets,
        DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,
        InsetsState outInsetsState, InsetsSourceControl[] outActiveControls,
        int requestUserId) {
    // ...
    final WindowState win = new WindowState(this, session, client, token, parentWindow,
            appOp[0], seq, attrs, viewVisibility, session.mUid, userId,
            session.mCanAddInternalSystemWindow);
    // ...
    final boolean openInputChannels = (outInputChannel != null
            && (attrs.inputFeatures & INPUT_FEATURE_NO_INPUT_CHANNEL) == 0);
    if  (openInputChannels) {
        // 这里会调用WindowState的openInputChannel来打开inputChannel
        win.openInputChannel(outInputChannel);
    }
    // ...
    return res;
}

 addWindow方法中会调用WindowState打开InputChannel。

4.4 WindowState.openInputChannel

 /frameworks/base/services/core/java/com/android/server/wm/WindowState.java

void openInputChannel(InputChannel outInputChannel) {
    if (mInputChannel != null) {
        throw new IllegalStateException("Window already has an input channel.");
    }
    String name = getName();
    // 通过openInputChannelPair方法创建出两个InputChannel
    InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
    mInputChannel = inputChannels[0];
    mClientChannel = inputChannels[1];
    // 注册server端的InputChannel到InputManagerService中
    mWmService.mInputManager.registerInputChannel(mInputChannel);
    mInputWindowHandle.token = mInputChannel.getToken();
    if (outInputChannel != null) {
        // 将client端的InputChannel设置到outInputChannel
        mClientChannel.transferTo(outInputChannel);
        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);
    }
    mWmService.mInputToWindowMap.put(mInputWindowHandle.token, this);
}

         首先会通过调用InputChannel的静态方法openInputChannelPair来创建两个InputChannel,一个作为client一个作为server;然后还会调用InputManagerService的registerInputChannel来注册server端的InputChannel;最后将client端的InputChannel设置到outInputChannel中。

4.5 InputChannel.openInputChannelPair

/frameworks/base/core/java/android/view/InputChannel.java

public static InputChannel[] openInputChannelPair(String name) {
    if (name == null) {
        throw new IllegalArgumentException("name must not be null");
    }
  
    if (DEBUG) {
        Slog.d(TAG, "Opening input channel pair '" + name + "'");
    }
    // 继续调用natvie方法创建出两个InputChannel
    return nativeOpenInputChannelPair(name);
}

         上述openInputChannelPair方法中会直接调用InputChannel的native方法nativeOpenInputChannelPair来创建出一对InputChannel。

 4.6 android_view_InputChannel.android_view_InputChannel_nativeOpenInputChannelPair

/frameworks/base/core/jni/android_view_InputChannel.cpp

static jobjectArray android_view_InputChannel_nativeOpenInputChannelPair(JNIEnv* env,
        jclass clazz, jstring nameObj) {
    ScopedUtfChars nameChars(env, nameObj);
    std::string name = nameChars.c_str();
  
    sp<InputChannel> serverChannel;
    sp<InputChannel> clientChannel;
    // 创建出server端和client端的InputChannel
    status_t result = InputChannel::openInputChannelPair(name, serverChannel, clientChannel);
    // ...
    // 添加到数组中,然后返回给上层
    env->SetObjectArrayElement(channelPair, 0, serverChannelObj);
    env->SetObjectArrayElement(channelPair, 1, clientChannelObj);
    return channelPair;
}

        jni方法nativeOpenInputChannelPair中会继续调用InputChannel的openInputChannelPair静态方法。然后将创建出的两个inputChannel分别添加到数组中,然后返回给上层。

4.7 InputChannel.openInputChannelPair

/frameworks/native/libs/input/InputTransport.cpp 

status_t InputChannel::openInputChannelPair(const std::string& name,
        sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) {
    int sockets[2];
    // 创建一对相互连接的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;
    }
  
    // 分别设置两个socket的可读可写buffer
    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));
  
    sp<IBinder> token = new BBinder();
  
    std::string serverChannelName = name + " (server)";
    android::base::unique_fd serverFd(sockets[0]);
    // 创建出server端InputChannel,并于socket关联
    outServerChannel = InputChannel::create(serverChannelName, std::move(serverFd), token);
  
    std::string clientChannelName = name + " (client)";
    android::base::unique_fd clientFd(sockets[1]);
    // 创建出client端InputChannel,并于socket关联
    outClientChannel = InputChannel::create(clientChannelName, std::move(clientFd), token);
    return OK;
}

         openInputChannelPair方法中会首先通过socketpair创建一对相互连接的套接字,然后分别给socket设置相应的选项值;然后通过InputChannel的create方法创建出两个分别与socket关联的inuptChannel。

4.8 InputChannel.create

 /frameworks/native/libs/input/InputTransport.cpp 

sp<InputChannel> InputChannel::create(const std::string& name, android::base::unique_fd fd,
                                      sp<IBinder> token) {
    // 设置文件描述符fd的状态属性为O_NONBLOCK
    const int result = fcntl(fd, F_SETFL, O_NONBLOCK);
    if (result != 0) {
        LOG_ALWAYS_FATAL("channel '%s' ~ Could not make socket non-blocking: %s", name.c_str(),
                         strerror(errno));
        return nullptr;
    }
    // 创建出InputChannel并返回
    return new InputChannel(name, std::move(fd), token);
}

         通过InputChannel的create方法构建出InputChannel并返回。

        至此,InputChannel便创建并关联上socket上了。并且通过前面的介绍,我们知道了获取输入事件时是从client端的socket中读取消息并进行事件封装,然后传递到上层。但是这里我们发现有一个问题,就是client端socket中的数据是从哪里来的呢?我们继续看一下WindowState的openInputChannel方法。见4.4节

        server端的InputChannel被注册到了InputManagerService中去了。

4.9 InputManagerService.registerInputChannel server端InputChannel的注册

/frameworks/base/services/core/java/com/android/server/input/InputManagerService.java

public void registerInputChannel(InputChannel inputChannel) {
    if (inputChannel == null) {
        throw new IllegalArgumentException("inputChannel must not be null.");
    }
    // 调用native方法继续注册
    nativeRegisterInputChannel(mPtr, inputChannel);
}

         在InputManagerService的registerInputChannel方法中直接调用了native方法nativeRegisterInputChannel。

4.10 com_android_server_input_ InputManagerService.nativeRegisterInputChannel

/frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp

static void nativeRegisterInputChannel(JNIEnv* env, jclass /* clazz */,
        jlong ptr, jobject inputChannelObj) {
    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
    // 获取InputChannel
    sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,
            inputChannelObj);
    if (inputChannel == nullptr) {
        throwInputChannelNotInitialized(env);
        return;
    }
    // 将inputChannel注册到NativeInputManager中
    status_t status = im->registerInputChannel(env, inputChannel);
    // 设置dispose的callback,在inputChannel
    // dispose之后会调用函数指针handleInputChannelDisposed
    // 来调用NativeInputManager的unregisterInputChannel
    // 解注册inputChannel
    android_view_InputChannel_setDisposeCallback(env, inputChannelObj,
            handleInputChannelDisposed, im);
}

         在native方法中,先调用了NativeInputManager的registerInputChannel方法注册inputChannel,然后会给inputChannel设置dispose callback,并且callback中执行了inputChannel的解注册。在NativeInputManager的registerInputChannel方法中,会获取InputDispatcher,并将inputChannel注册到其中去。

4.11 com_android_server_input_ InputManagerService.registerInputChannel

 /frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp

status_t NativeInputManager::registerInputChannel(JNIEnv* /* env */,
        const sp<InputChannel>& inputChannel) {
    ATRACE_CALL();
    return mInputManager->getDispatcher()->registerInputChannel(inputChannel);
}

 4.12 InputDispatcher.registerInputChannel

/frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp 

status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel) {
#if DEBUG_REGISTRATION
    ALOGD("channel '%s' ~ registerInputChannel", inputChannel->getName().c_str());
#endif
  
    { // acquire lock
        std::scoped_lock _l(mLock);
        // ...
        // 创建connection并添加的注册列表中
        sp<Connection> connection = new Connection(inputChannel, false /*monitor*/, mIdGenerator);
        int fd = inputChannel->getFd();
        mConnectionsByFd[fd] = connection;
        mInputChannelsByToken[inputChannel->getConnectionToken()] = inputChannel;
        // 将inputChannel的fd添加到looper中,并且对应的event是ALOOPER_EVENT_INPUT
        // 传入的looper callback为handleReceiveCallback方法,
        // 因此当事件到来时,会触发此callback
        mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
    } // release lock
  
    // Wake the looper because some connections have changed.
    mLooper->wake();
    return OK;
}

         在InputDispatcher的registerInputChannel方法中,会通过InputChannel构建出Connection,然后将其添加到注册列表当中。

        到了这里,server端的inputChannel最终被注册到了InputDispatcher的注册列表中去了,所以InputDispatcher中就可以通过向server端的socket中写入消息,然后client端就可以读取到了。但是这里还有一个问题,server端写入事件消息后,怎么通知到client去开始处理呢?这里我们回过头来看看4.1小结的内容,在setView方法中会创建app端的监听也就是WindowInputReceiver,并且把inputChannel传入进去。这里我们直接看WindowInputReceiver的父类,InputEventReceiver。

4.13 client端InputChannel读取事件并传递

/frameworks/base/core/java/android/view/InputEventReceiver.java

public InputEventReceiver(InputChannel inputChannel, Looper looper) {
    // ...
    mInputChannel = inputChannel;
    mMessageQueue = looper.getQueue();
    // 将Java层的inputChannel向下层传递
    mReceiverPtr = nativeInit(new WeakReference<InputEventReceiver>(this),
            inputChannel, mMessageQueue);
    mCloseGuard.open("dispose");
}

         在InputEventReceiver的构造方法中调用了native方法nativeInit进行native层的初始化

4.14 android_view_InputEventReceiver.nativeInit

/frameworks/base/core/jni/android_view_InputEventReceiver.cpp

static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,
        jobject inputChannelObj, jobject messageQueueObj) {
    // ...
    sp<NativeInputEventReceiver> receiver = new NativeInputEventReceiver(env,
            receiverWeak, inputChannel, messageQueue);
    // 初始化Receiver
    status_t status = receiver->initialize();
    // ...
    return reinterpret_cast<jlong>(receiver.get());
}

         在NativeInputEventReceiver初始化时,会将inputChannel的文件描述符fd添加到looper中去,并且添加了looper callback为NativeInputEventReceiver实例自身,所以,当server端写入事件消息时,就会触发callback,于是便调用到NativeInputEventReceiver的handleEvent方法。

4.15 Looper.pollInner

/system/core/libutils/Looper.cpp

int Looper::pollInner(int timeoutMillis) {
      ....
      int callbackResult = response.request.callback->handleEvent(fd, events, data);
      if (callbackResult == 0) {
        removeFd(fd, response.request.seq);
      }
      ....
}

        looper callback为NativeInputEventReceiver实例自身,所以这里回调到NativeInputEventReceiver的handleEvent 方法。

4.16 android_view_InputEventReceiver.handleEvent

/frameworks/base/core/jni/android_view_InputEventReceiver.cpp

int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) {
    // ...
    // 接收添加的ALOOPER_EVENT_INPUT事件
    if (events & ALOOPER_EVENT_INPUT) {
        JNIEnv* env = AndroidRuntime::getJNIEnv();
        // 调用consumeEvents方法处理事件
        status_t status = consumeEvents(env, false /*consumeBatches*/, -1, nullptr);
        mMessageQueue->raiseAndClearException(env, "handleReceiveCallback");
        return status == OK || status == NO_MEMORY ? 1 : 0;
    }
    // ...
    return 1;
}

         consumeEvents方法在其内部会通过jni的方式将事件向Java层传递到InputEventReceiver的dispatchInputEvent,从而便实现了事件的分发。

4.17 小结

        InputDispatcher是如果通过InputChannel将事件向上层进行分发的整个过程。首先是创建一对InputChannel,并且会开启一对相互连接的socket作为事件传递的媒介。server端的InputChannel会注册到InputDispatcher中去以完成事件的分发,并且会将其fd添加到looper中,而client端的InputChannel会在InputEventReceiver初始化时也会将其fd添加到looper中,并传入callback类接收server端写入的事件,这样整个过程便串联起来了。

5. InputConsumer处理事件

5.1 android_view_InputEventReceiver.consumeEvents

 /frameworks/base/core/jni/android_view_InputEventReceiver.cpp

status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,
        bool consumeBatches, nsecs_t frameTime, bool* outConsumedBatch) {
    if (kDebugDispatchCycle) {
        ALOGD("channel '%s' ~ Consuming input events, consumeBatches=%s, frameTime=%" PRId64,
              getInputChannelName().c_str(), toString(consumeBatches), frameTime);
    }
    // .....
    // 这里通过InputConsumer的consume方法获取到inputevent
    status_t status = mInputConsumer.consume(&mInputEventFactory,
            consumeBatches, frameTime, &seq, &inputEvent,
            &motionEventType, &touchMoveNum, &flag);
    // 省略若干行
    if (inputEventObj) {
        if (kDebugDispatchCycle) {
            ALOGD("channel '%s' ~ Dispatching input event.", getInputChannelName().c_str());
        }
        // 此处通过jni调用InputEventReceiver的dispatchInputEvent方法进行事件的分发,
        // 从而将input事件传递到java层
        env->CallVoidMethod(receiverObj.get(),
                gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj);
        if (env->ExceptionCheck()) {
            ALOGE("Exception dispatching input event.");
            skipCallbacks = true;
        }
        env->DeleteLocalRef(inputEventObj);
    } else {
        ALOGW("channel '%s' ~ Failed to obtain event object.",
                getInputChannelName().c_str());
        skipCallbacks = true;
    }
  
    if (skipCallbacks) {
        mInputConsumer.sendFinishedSignal(seq, false);
    }
}

         consume方法中主要是从InputChannel获取输入事件的信息,然后根据消息中获取的事件类型构造出对应的event,并将消息中的事件信息赋值给event对象。在NativeInputEventReceiver的consumeEvents方法中,会循环调用InputConsumer的consume方法获取事件并进行处理。InputConsumer的consume方法中会通过InputChannel从socket中通过recv系统调用获取下层传递的事件,获取到事件后就会通过jni向Java层传递。

5.2 InputConsumer.consume

/frameworks/native/libs/input/InputTransport.cpp

status_t InputConsumer::consume(InputEventFactoryInterface* factory, bool consumeBatches,
                                nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent,
                                int* motionEventType, int* touchMoveNumber, bool* flag) {
    // ...
    *outSeq = 0;
    *outEvent = nullptr;
    // Fetch the next input message.
    // Loop until an event can be returned or no additional events are received.
    while (!*outEvent) {
        if (mMsgDeferred) {
            // mMsg contains a valid input message from the previous call to consume
            // that has not yet been processed.
            mMsgDeferred = false;
        } else {
            // Receive a fresh message.
            // 这里通过调用InputChannel的receiveMessage来获取消息
            status_t result = mChannel->receiveMessage(&mMsg);
            // .....
        }
        // 根据消息的类型生成不同的Event
        switch (mMsg.header.type) {
            ......
  
            case InputMessage::Type::MOTION: {
                // 构造一个MotionEvent
                MotionEvent* motionEvent = factory->createMotionEvent();
                if (!motionEvent) return NO_MEMORY;
                updateTouchState(mMsg);
                // 从msg中获取事件的各属性,并赋值给构造出的Event对象
                initializeMotionEvent(motionEvent, &mMsg);
                *outSeq = mMsg.body.motion.seq;
                *outEvent = motionEvent;
  
                if (DEBUG_TRANSPORT_ACTIONS) {
                    ALOGD("channel '%s' consumer ~ consumed motion event, seq=%u",
                          mChannel->getName().c_str(), *outSeq);
                }
                break;
            }
            // ....
  
        }
    }
    return OK;
}

 5.3 event的构造和初始化

/frameworks/native/include/input/Input.h

class PreallocatedInputEventFactory : public InputEventFactoryInterface {
public:
    PreallocatedInputEventFactory() { }
    virtual ~PreallocatedInputEventFactory() { }
    virtual KeyEvent* createKeyEvent() override { return &mKeyEvent; }
    // 可以看到这里返回的是全局变量的地址
    virtual MotionEvent* createMotionEvent() override { return &mMotionEvent; }
    virtual FocusEvent* createFocusEvent() override { return &mFocusEvent; }
  
private:
    // 这里定义不同类型的事件变量
    KeyEvent mKeyEvent;
    MotionEvent mMotionEvent;
    FocusEvent mFocusEvent;
};

 5.3.1 event的初始化

/frameworks/native/libs/input/InputTransport.cpp

// 对motion事件进行初始化
void InputConsumer::initializeMotionEvent(MotionEvent* event, const InputMessage* msg) {
    // 省略若干行
    event->initialize(msg->body.motion.eventId, msg->body.motion.deviceId, msg->body.motion.source,
                      msg->body.motion.displayId, msg->body.motion.hmac, msg->body.motion.action,
                      msg->body.motion.actionButton, msg->body.motion.flags,
                      msg->body.motion.edgeFlags, msg->body.motion.metaState,
                      msg->body.motion.buttonState, msg->body.motion.classification,
                      msg->body.motion.xScale, msg->body.motion.yScale, msg->body.motion.xOffset,
                      msg->body.motion.yOffset, msg->body.motion.xPrecision,
                      msg->body.motion.yPrecision, msg->body.motion.xCursorPosition,
                      msg->body.motion.yCursorPosition, msg->body.motion.downTime,
                      msg->body.motion.eventTime, pointerCount, pointerProperties, pointerCoords);
}

这里主要是从msg中获取对应事件的详细信息然后赋值给对应的event对象上。

5.4 InputChannel.receiveMessage读取消息

/frameworks/native/libs/input/InputTransport.cpp

status_t InputChannel::receiveMessage(InputMessage* msg) {
    ssize_t nRead;
    do {
        // 这里通过recv系统调用从socket中读取消息
        nRead = ::recv(mFd.get(), msg, sizeof(InputMessage), MSG_DONTWAIT);
    } while (nRead == -1 && errno == EINTR);
    // .....
    return OK;
}

 这个方法主要是从socket中读取消息,而socket的建立见第4节

接收到消息之后我们回过头来看看5.1小结的内容,获取到消息之后通过jni调用InputEventReceiver中的dispatchInputEvent方法进行事件分发,从而将input事件传递到java层。

 6. java层接收input事件进行分发

 6.1 InputEventReceiver.dispatchInputEvent

/frameworks/base/core/java/android/view/InputEventReceiver.java

private void dispatchInputEvent(int seq, InputEvent event) {
    mSeqMap.put(event.getSequenceNumber(), seq);
    // 直接调用onInputEvent
    onInputEvent(event);
}

         在InputEventReceiver中的dispatchInputEvent方法中会调用onInputEvent方法进行事件的处理,InputEventReceiver是抽象类,它的一个子类WindowInputEventReceiver是用来处理input事件的,WindowInputEventReceiver是frameworks/base/core/java/android/view/ViewRootImpl.java的内部类,它复写了onInputEvent方法,该方法中会调用enqueueInputEvent方法对事件进行入队。

6.2 WindowInputEventReceiver.onInputEvent

 /frameworks/base/core/java/android/view/ViewRootImpl.java

@Override
public void onInputEvent(InputEvent event) {
    Trace.traceBegin(Trace.TRACE_TAG_VIEW, "processInputEventForCompatibility");
    List<InputEvent> processedEvents;
    try {
        // 这块儿主要是对低版本进行兼容性处理
        processedEvents =
            mInputCompatProcessor.processInputEventForCompatibility(event);
    } finally {
        Trace.traceEnd(Trace.TRACE_TAG_VIEW);
    }
    if (processedEvents != null) {
        // 安卓M及以下版本,在这里处理
        if (processedEvents.isEmpty()) {
            // InputEvent consumed by mInputCompatProcessor
            finishInputEvent(event, true);
        } else {
            for (int i = 0; i < processedEvents.size(); i++) {
                enqueueInputEvent(
                        processedEvents.get(i), this,
                        QueuedInputEvent.FLAG_MODIFIED_FOR_COMPATIBILITY, true);
            }
        }
    } else {
        // 这里对事件进行入队
        enqueueInputEvent(event, this, 0, true);
    }
}

         onInputEvent方法中首先调用InputCompatProcessor的processInputEventForCompatibility方法对事件进行兼容性处理,这个方法中会判断应用的targetSdkVersion如果小于M并且是motion事件则进行兼容处理并返回,否则返回null;然后会调用enqueueInputEvent方法对事件进行入队。

6.3 InputCompatProcessor.processInputEventForCompatibility

/frameworks/base/core/java/android/view/InputEventCompatProcessor.java

public InputEventCompatProcessor(Context context) {
    mContext = context;
    // 获取应用的targetsdk版本
    mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
    mProcessedEvents = new ArrayList<>();
}
  
public List<InputEvent> processInputEventForCompatibility(InputEvent e) {
    // 小于M并且是motion事件则进行兼容处理
    if (mTargetSdkVersion < Build.VERSION_CODES.M && e instanceof MotionEvent) {
        mProcessedEvents.clear();
        MotionEvent motion = (MotionEvent) e;
        final int mask =
                MotionEvent.BUTTON_STYLUS_PRIMARY | MotionEvent.BUTTON_STYLUS_SECONDARY;
        final int buttonState = motion.getButtonState();
        final int compatButtonState = (buttonState & mask) >> 4;
        if (compatButtonState != 0) {
            motion.setButtonState(buttonState | compatButtonState);
        }
        mProcessedEvents.add(motion);
        return mProcessedEvents;
    }
    return null;
}

 6.4 转变事件类型并加入队列

/frameworks/base/core/java/android/view/ViewRootImpl.java

void enqueueInputEvent(InputEvent event,
        InputEventReceiver receiver, int flags, boolean processImmediately) {
    // 转变为QueuedInputEvent
    QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);
  
    // 将事件插入到链表的末尾
    QueuedInputEvent last = mPendingInputEventTail;
    if (last == null) {
        mPendingInputEventHead = q;
        mPendingInputEventTail = q;
    } else {
        last.mNext = q;
        mPendingInputEventTail = q;
    }
    mPendingInputEventCount += 1;
    Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
            mPendingInputEventCount);
  
    if (processImmediately) {
        // 调用doProcessInputEvents继续处理
        doProcessInputEvents();
    } else {
        scheduleProcessInputEvents();
    }
}

         此方法主要是将InputEvent转变为QueuedInputEvent并将其放到链表的末尾,然后调用doProcessInputEvents方法进行处理。

6.5 循环事件链并进行分发

/frameworks/base/core/java/android/view/ViewRootImpl.java

void doProcessInputEvents() {
    // 遍历整个链表,对事件进行分发
    while (mPendingInputEventHead != null) {
        QueuedInputEvent q = mPendingInputEventHead;
        mPendingInputEventHead = q.mNext;
        if (mPendingInputEventHead == null) {
            mPendingInputEventTail = null;
        }
        q.mNext = null;
        // .....
        // 分发事件
        deliverInputEvent(q);
    }
}

此方法中会遍历整个事件链表,对每个事件调用deliverInputEvent方法进行分发。

 6.6 将事件分发到InputStage

/frameworks/base/core/java/android/view/ViewRootImpl.java

private void deliverInputEvent(QueuedInputEvent q) {
    // .....
    try {
        // .....
        InputStage stage;
        if (q.shouldSendToSynthesizer()) {
            // flag包含FLAG_UNHANDLED会走这里
            stage = mSyntheticInputStage;
        } else {
            // 是否跳过输入法窗口进行分发
            stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
        }
        // ............
        if (stage != null) {
            // 处理窗口焦点变更
            handleWindowFocusChanged();
            // 分发事件
            stage.deliver(q);
        } else {
            finishInputEvent(q);
        }
    } finally {
        Trace.traceEnd(Trace.TRACE_TAG_VIEW);
    }
}

         此方法中会根据flag获取InputStage,然后调用InputStage的deliver方法分发事件,它主要是用来将事件的处理分成多个阶段进行。

 6.6.1 InputStage是什么?

        InputStage主要是用来将事件的处理分成若干个阶段(stage)进行,事件依次经过每一个stage,如果该事件没有被处理(标识为FLAG_FINISHED),则该stage就会调用onProcess方法处理,然后调用forward执行下一个stage的处理;如果该事件被标识为处理则直接调用forward,执行下一个stage的处理,直到没有下一个stage(也就是最后一个SyntheticInputStage)。这里一共有7种stage,各个stage间串联起来,形成一个链表,各个stage的处理过程大致如下图所示:

         先来看下这些stage是如何串起来的,所有的Stage都继承于InputStage,而InputStage是抽象类,它的定义如下:

6.6.2 InputStage构造函数

 /frameworks/base/core/java/android/view/ViewRootImpl.java

abstract class InputStage {
    private final InputStage mNext;
    /**
        * Creates an input stage.
        * @param next The next stage to which events should be forwarded.
        */
    public InputStage(InputStage next) {
        // 从构成函数的定义能够看到,传入的next会赋值给当前实例的next,
        // 因此,先插入的就会是最后一个节点(头插法),最终会形成一个链表
        mNext = next;
    }
}

在ViewRootImpl的setView方法中有以下代码段:

6.6.3 ViewRootImpl.setView

/frameworks/base/core/java/android/view/ViewRootImpl.java 

// 如下创建出来的7个实例会串在一起形成一个链表,
// 链表的头是最后创建出来的nativePreImeStage,
// 链表的尾是首先构造出来的mSyntheticInputStage
// Set up the input pipeline.
mSyntheticInputStage = new SyntheticInputStage();
InputStage viewPostImeStage = new ViewPostImeInputStage(mSyntheticInputStage);
InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage,
        "aq:native-post-ime:" + counterSuffix);
InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage);
// 输入法对应的stage
InputStage imeStage = new ImeInputStage(earlyPostImeStage,
        "aq:ime:" + counterSuffix);
InputStage viewPreImeStage = new ViewPreImeInputStage(imeStage);
InputStage nativePreImeStage = new NativePreImeInputStage(viewPreImeStage,
        "aq:native-pre-ime:" + counterSuffix);
// 第一个处理事件的stage为NativePreImeInputStage
mFirstInputStage = nativePreImeStage;
mFirstPostImeInputStage = earlyPostImeStage;

6.7 ViewRootImpl.deliver分发传递事件

/frameworks/base/core/java/android/view/ViewRootImpl.java 

public final void deliver(QueuedInputEvent q) {
    if ((q.mFlags & QueuedInputEvent.FLAG_FINISHED) != 0) {
        // 调用next的deliver方法继续分发处理
        forward(q);
    } else if (shouldDropInputEvent(q)) {
        finish(q, false);
    } else {
        traceEvent(q, Trace.TRACE_TAG_VIEW);
        final int result;
        try {
            // 自身处理事件
            result = onProcess(q);
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
        }
        // 判断是否需要继续分发处理
        apply(q, result);
    }
}

 从native层的时候是以触摸事件展开分析,所以这里依然以触摸事件进行分析。

前面提到InputStage 是一个链表结构,内部采用拦截器模式来分发事件。

触摸事件会直接到ViewPostImeInputStage去进行拦截处理。

6.8 ViewPostImeInputStage.onProcess处理input事件

/frameworks/base/core/java/android/view/ViewRootImpl.java

@Override
protected int onProcess(QueuedInputEvent q) {
    if (q.mEvent instanceof KeyEvent) {
        // 处理key事件
        return processKeyEvent(q);
    } else {
        final int source = q.mEvent.getSource();
        if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
            // 处理pointer事件
            return processPointerEvent(q);
        } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
            // 处理轨迹球事件
            return processTrackballEvent(q);
        } else {
            // 处理一般的motion事件
            return processGenericMotionEvent(q);
        }
    }
}

6.9 ViewPostImeInputStage.processPointerEvent

 /frameworks/base/core/java/android/view/ViewRootImpl.java

          private int processPointerEvent(QueuedInputEvent q) {
              final MotionEvent event = (MotionEvent)q.mEvent;
              mAttachInfo.mUnbufferedDispatchRequested = false;
              mAttachInfo.mHandlingPointerEvent = true;
                // 调用view的dispatchPointerEvent来分发事件,此处的mView是decorview
              boolean handled = mView.dispatchPointerEvent(event);
             maybeUpdatePointerIcon(event);
              maybeUpdateTooltip(event);
              mAttachInfo.mHandlingPointerEvent = false;
              if (mAttachInfo.mUnbufferedDispatchRequested && !mUnbufferedInputDispatch) {
                  mUnbufferedInputDispatch = true;
                  if (mConsumeBatchedInputScheduled) {
                      scheduleConsumeBatchedInputImmediately();
                  }
              }
                // 如果已经消费事件,就拦截事件,返回finish
              return handled ? FINISH_HANDLED : FORWARD;
          }

         这里的mView.dispatchPointerEvent会走到View.java里面的dispatchPointerEvent方法里面去,View.java属于DecorView的父类,具体实现逻辑由它的子类实现,所以这里又会走到DecorView 中的dispatchTouchEvent 方法去。

6.10 DecorView.dispatchTouchEvent 

/frameworks/base/core/java/com/android/internal/policy/DecorView.java

@Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        // 通过phineWindow获取callBack
        final Window.Callback cb = mWindow.getCallback(); 
        return cb != null && !mWindow.isDestroyed() && mFeatureId < 0
                ? cb.dispatchTouchEvent(ev) : super.dispatchTouchEvent(ev);
    }

 这里的Window.Callback实际就是Activity的实例,Activity默认实现了Window.Callback接口的方法,这里就会将事件传递到Activity里。

6.11 Activity.dispatchTouchEvent

/frameworks/base/core/java/android/app/Activity.java

      public boolean dispatchTouchEvent(MotionEvent ev) {
          if (ev.getAction() == MotionEvent.ACTION_DOWN) {
              onUserInteraction();
          }
            // getWindow返回的是PhoneWindow的实例
          if (getWindow().superDispatchTouchEvent(ev)) {
              return true;
          }
          return onTouchEvent(ev);
      }

getWindow返回的是PhoneWindow的实例,所以这里会调用到PhoneWindow中的superDispatchTouchEvent方法里面去了。

6.12 PhoneWindow.superDispatchTouchEvent

/frameworks/base/core/java/com/android/internal/policy/PhoneWindow.java

      @Override
      public boolean superDispatchTouchEvent(MotionEvent event) {
           // 调用DecorView的同名方法
          return mDecor.superDispatchTouchEvent(event);
      }

 6.13 DecorView.superDispatchTouchEvent

 /frameworks/base/core/java/com/android/internal/policy/DecorView.java

 public boolean superDispatchTouchEvent(MotionEvent event) {
        return super.dispatchTouchEvent(event);
    }

 这里会直接调用DecorView的父类的dispatchTouchEvent方法,这里开始执行一个事件传递到View树的过程。

6.14 ViewGroup.dispatchTouchEvent

/frameworks/base/core/java/android/view/ViewGroup.java

@Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
             // 检查是否拦截
            final boolean intercepted;
            if (actionMasked == MotionEvent.ACTION_DOWN
                    || mFirstTouchTarget != null) { // 有触摸目标或者action为down
                final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
                if (!disallowIntercept) {
                    intercepted = onInterceptTouchEvent(ev); // 判断是否拦截,默认false
                    ev.setAction(action); 
                }
            } else {
                // 没有触摸目标,此操作不是初始关闭,因此此视图组继续拦截触摸。
                intercepted = true;
            }
            // 检查是否取消
            final boolean canceled = resetCancelNextUpFlag(this)
                    || actionMasked == MotionEvent.ACTION_CANCEL;
            // 没有取消,也没有被拦截       
            if (!canceled && !intercepted) {
                // 找一个可以接收事件的孩子。从前到后扫描mChildren。
                final View[] children = mChildren;
                for (int i = childrenCount - 1; i >= 0; i--) {
                    if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
                      // childView想在边界内接受触摸。
                    }
                }
            }
            // 分发给触摸目标。
            if (mFirstTouchTarget == null) {
                // 没有触摸目标,因此请将其视为普通视图
                handled = dispatchTransformedTouchEvent(ev, canceled, null,
                        TouchTarget.ALL_POINTER_IDS);
            }
            ....
    }

 6.15 ViewGroup.onInterceptTouchEvent

/frameworks/base/core/java/android/view/ViewGroup.java

这个方法默认不做拦截:

public boolean onInterceptTouchEvent(MotionEvent ev) {
        if (ev.isFromSource(InputDevice.SOURCE_MOUSE)
                && ev.getAction() == MotionEvent.ACTION_DOWN
                && ev.isButtonPressed(MotionEvent.BUTTON_PRIMARY)
                && isOnScrollbarThumb(ev.getX(), ev.getY())) {
            return true;
        }
        return false;
    }

6.16 ViewGroup.dispatchTransformedTouchEvent

/frameworks/base/core/java/android/view/ViewGroup.java

 这个方法负责将运动事件转换为特定子视图的坐标空间,如果子项为空, MotionEvent 将改为发送到此viewgroup,最后都会调用到view的dispatchTouchEvent去处理:

private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,
            View child, int desiredPointerIdBits) {
       ....
        
        if (child == null) {
             // 调用View的dispatchTouchEvent
            handled = super.dispatchTouchEvent(transformedEvent);
        } else {
            final float offsetX = mScrollX - child.mLeft;
            final float offsetY = mScrollY - child.mTop;
            transformedEvent.offsetLocation(offsetX, offsetY);
            if (! child.hasIdentityMatrix()) {
                transformedEvent.transform(child.getInverseMatrix());
            }
            // 调用子View的dispatchTouchEvent
            handled = child.dispatchTouchEvent(transformedEvent); 
        }
        return handled;  
    }

6.17 View.dispatchTouchEvent

/frameworks/base/core/java/android/view/View.java

public boolean dispatchTouchEvent(MotionEvent event) {
      		.....
          if (onFilterTouchEventForSecurity(event)) {
            // 如果有设置OnTouchListener,就先交给mOnTouchListener 处理
            ListenerInfo li = mListenerInfo;
            if (li != null && li.mOnTouchListener != null
                   && (mViewFlags & ENABLED_MASK) == ENABLED
                   && li.mOnTouchListener.onTouch(this, event)) {
               result = true;
            }
            // 如果没有处理,交给onTouchEvent方法
            if (!result && onTouchEvent(event)) {
                result = true;
            }
         }
	       ....
   }

6.18 View.onTouchEvent

/frameworks/base/core/java/android/view/View.java

public boolean onTouchEvent(MotionEvent event) {
        ...........
        // 如果设置了mTouchDelegate,就直接交给它处理
        if (mTouchDelegate != null) {
            if (mTouchDelegate.onTouchEvent(event)) {
                return true;
            }
        }
        // 如果可以点击或者支持在悬停或长按时显示工具提示。
        if (clickable || (viewFlags & TOOLTIP) == TOOLTIP) {
            switch (action) {
                case MotionEvent.ACTION_UP:
                   	 ....
                     // 仅当我们处于按下状态时才执行单击操作
                     if (!focusTaken) {
                         if (mPerformClick == null) {
                              mPerformClick = new PerformClick();
                         }
                        if (!post(mPerformClick)) {
                            performClickInternal();
                        }
                    }
                    break;
               case MotionEvent.ACTION_DOWN:
                    // 对于滚动容器内的视图,将按下的反馈延迟一小段时间,以防这是滚动。
                    if (isInScrollingContainer) {
                        mPrivateFlags |= PFLAG_PREPRESSED;
                        if (mPendingCheckForTap == null) {
                            mPendingCheckForTap = new CheckForTap();
                        }
                        mPendingCheckForTap.x = event.getX();
                        mPendingCheckForTap.y = event.getY();
                        postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());
                    } else {
                        // 不在滚动容器内,因此立即显示反馈
                        setPressed(true, x, y);
                        // 检查是否长按
                        checkForLongClick(0, x, y);
                    }
                    break;
        }
       return false;
  }

这个方法里面在action_down的时候,会延迟检查是否发生长按事件,执行相应的performLongClick方法。

在action_up的时候,会post一个PerformClick,执行相应的单击事件的方法。

6.19 小结

        通过以上分析,我们便了解了input事件从Native层传递到Java层,然后继续传递到View树上的整个过程。需要注意的是,在各个传递环节,如果调用方法返回了true,就代表它消费掉了本次事件,那么就不会继续朝后传递。另外,对于ViewGroup来说,存在onInterceptTouchEvent方法,此方法用来拦截事件向子view分发,如果返回了true,事件就会传递到当前ViewGroup的onTouchEvent中而不在向子View传递;否则的话,会分发到当前ViewGroup,然后再传递到子View。由于View不能包含子View,所以View不存在拦截方法。

7.  事件确认

在ViewPostImeInputStage 中,如果我们的view处理了对应的事件,就会调用到finish方法,接着调用下一个处理器:

7.1 ViewRootImpl.finish

/frameworks/base/core/java/android/view/ViewRootImpl.java

protected void apply(QueuedInputEvent q, int result) {
            if (result == FORWARD) {
                forward(q);
            } else if (result == FINISH_HANDLED) {
                finish(q, true);
            } else if (result == FINISH_NOT_HANDLED) {
                finish(q, false);
            } else {
                throw new IllegalArgumentException("Invalid result: " + result);
            }
    }

    protected void finish(QueuedInputEvent q, boolean handled) {
        q.mFlags |= QueuedInputEvent.FLAG_FINISHED;
        if (handled) {
           q.mFlags |= QueuedInputEvent.FLAG_FINISHED_HANDLED;
        }
        forward(q);
    }
    // 调用下一个处理器
    protected void forward(QueuedInputEvent q) {
        onDeliverToNext(q);
    }

 由6.6.3小结可知,下一个处理器是SyntheticInputStage,在onProcess方法里面的返回值是FORWARD,所以走到apply方法里面去会走到forward方法,紧接着调用onDeliverToNext,由于next为null就会调用finishInputEvent方法:

7.2 ViewRootImpl.onDeliverToNext

/frameworks/base/core/java/android/view/ViewRootImpl.java

final class SyntheticInputStage extends InputStage {
     public SyntheticInputStage() {
        super(null);
     }
  
     @Override
     protected int onProcess(QueuedInputEvent q) {
        q.mFlags |= QueuedInputEvent.FLAG_RESYNTHESIZED;
        if (q.mEvent instanceof MotionEvent) {
                final MotionEvent event = (MotionEvent)q.mEvent;
                final int source = event.getSource();
                    // 是轨迹球
                if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) { 
                    mTrackball.process(event);
                    return FINISH_HANDLED;
                // 是操纵杆
                } else if ((source & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) { 
                    mJoystick.process(event);
                    return FINISH_HANDLED;
                // 是摸导航
                } else if ((source & InputDevice.SOURCE_TOUCH_NAVIGATION)
                        == InputDevice.SOURCE_TOUCH_NAVIGATION) { 
                    mTouchNavigation.process(event);
                    return FINISH_HANDLED;
                }
       } else if ((q.mFlags & QueuedInputEvent.FLAG_UNHANDLED) != 0) {
         mKeyboard.process((KeyEvent)q.mEvent);
         return FINISH_HANDLED;
       }
      return FORWARD;
   }
}
..........................

protected void apply(QueuedInputEvent q, int result) {
            if (result == FORWARD) {
                forward(q);
            } else if (result == FINISH_HANDLED) {
                finish(q, true);
            } else if (result == FINISH_NOT_HANDLED) {
                finish(q, false);
            } else {
                throw new IllegalArgumentException("Invalid result: " + result);
            }
    }
.......................

 protected void forward(QueuedInputEvent q) {
            onDeliverToNext(q);
        }

......................

 protected void onDeliverToNext(QueuedInputEvent q) {
       if (mNext != null) {
          mNext.deliver(q);
       } else {
          finishInputEvent(q);
       }
    }
.........

7.3 ViewRootImpl.finishInputEvent

/frameworks/base/core/java/android/view/ViewRootImpl.java

public InputEventReceiver mReceiver;
...........
     
 private void finishInputEvent(QueuedInputEvent q) {
          Trace.asyncTraceEnd(Trace.TRACE_TAG_VIEW, "deliverInputEvent",
                  q.mEvent.getId());
  
          if (q.mReceiver != null) {
              boolean handled = (q.mFlags & QueuedInputEvent.FLAG_FINISHED_HANDLED) != 0;
              boolean modified = (q.mFlags & QueuedInputEvent.FLAG_MODIFIED_FOR_COMPATIBILITY) != 0;
              if (modified) {
                  Trace.traceBegin(Trace.TRACE_TAG_VIEW, "processInputEventBeforeFinish");
                  InputEvent processedEvent;
                  try {
                      processedEvent =
                              mInputCompatProcessor.processInputEventBeforeFinish(q.mEvent);
                  } finally {
                      Trace.traceEnd(Trace.TRACE_TAG_VIEW);
                  }
                  if (processedEvent != null) {
                      q.mReceiver.finishInputEvent(processedEvent, handled);
                  }
              } else {
                  q.mReceiver.finishInputEvent(q.mEvent, handled);
              }
          } else {
              q.mEvent.recycleIfNeededAfterDispatch();
          }
          / 回收队列中的输入事件
          recycleQueuedInputEvent(q);
      }

 7.4 InputEventReceiver.finishInputEvent

/frameworks/base/core/java/android/view/InputEventReceiver.java

      public final void finishInputEvent(InputEvent event, boolean handled) {
          if (event == null) {
              throw new IllegalArgumentException("event must not be null");
          }
          if (mReceiverPtr == 0) {
              Log.w(TAG, "Attempted to finish an input event but the input event "
                      + "receiver has already been disposed.");
          } else {
              int index = mSeqMap.indexOfKey(event.getSequenceNumber());
              if (index < 0) {
                  Log.w(TAG, "Attempted to finish an input event that is not in progress.");
              } else {
                  int seq = mSeqMap.valueAt(index);
                  mSeqMap.removeAt(index);
                // 调用naive接口通知事件是否已经消费
                  nativeFinishInputEvent(mReceiverPtr, seq, handled);
              }
          }
          event.recycleIfNeededAfterDispatch();
      }

7.5 android_view_InputEventReceiver.nativeFinishInputEvent

/frameworks/base/core/jni/android_view_InputEventReceiver.cpp 

static void nativeFinishInputEvent(JNIEnv* env, jclass clazz, jlong receiverPtr,
        jint seq, jboolean handled) {
    sp<NativeInputEventReceiver> receiver = reinterpret_cast<NativeInputEventReceiver*>(receiverPtr);
    status_t status = receiver->finishInputEvent(seq, handled);
    .....
}

 7.6 NativeInputEventReceiver.finishInputEvent

/frameworks/base/core/jni/android_view_InputEventReceiver.cpp 

  status_t NativeInputEventReceiver::finishInputEvent(uint32_t seq, bool handled) {
      if (kDebugDispatchCycle) {
          ALOGD("channel '%s' ~ Finished input event.", getInputChannelName().c_str());
      }
      // mInputConsumer是InputConsumer的实例
      status_t status = mInputConsumer.sendFinishedSignal(seq, handled);
      if (status) {
          if (status == WOULD_BLOCK) {
              if (kDebugDispatchCycle) {
                  ALOGD("channel '%s' ~ Could not send finished signal immediately.  "
                          "Enqueued for later.", getInputChannelName().c_str());
              }
              Finish finish;
              finish.seq = seq;
              finish.handled = handled;
              mFinishQueue.add(finish);
              if (mFinishQueue.size() == 1) {
                  setFdEvents(ALOOPER_EVENT_INPUT | ALOOPER_EVENT_OUTPUT);
              }
              return OK;
          }
          ALOGW("Failed to send finished signal on channel '%s'.  status=%d",
                  getInputChannelName().c_str(), status);
      }
      return status;
  }

7.7 InputConsumer.sendFinishedSignal

/frameworks/native/libs/input/InputTransport.cpp

status_t InputConsumer::sendFinishedSignal(uint32_t seq, bool handled) {
    if (seqChainCount) {
        ....
        while (!status && chainIndex > 0) {
            chainIndex--;
            status = sendUnchainedFinishedSignal(chainSeqs[chainIndex], handled);
        }
        ....
    }
    // 为批次中的最后一条消息发送完成信号。
    return sendUnchainedFinishedSignal(seq, handled);
}

 7.8 InputConsumer.sendUnchainedFinishedSignal

/frameworks/native/libs/input/InputTransport.cpp

  status_t InputConsumer::sendUnchainedFinishedSignal(uint32_t seq, bool handled) {
      InputMessage msg;
      msg.header.type = InputMessage::Type::FINISHED;
      msg.body.finished.seq = seq;
      msg.body.finished.handled = handled ? 1 : 0;
      return mChannel->sendMessage(&msg);
  }

这里通过InputChannel 发送完成信号。

前面第4节已经说过InputChannel的创建与初始化,包括client与server端的注册。

当窗口与输入系统建立连接时,Looper 通过 epoll 机制监听连接的输入端的文件描述符,当窗口通过连接反馈处理结果时,epoll 就会收到可读事件,因此 InputDispatcher 线程会被唤醒来读取窗口的事件处理结果。

发送消息过来之后触发handleReceiveCallback回调:

7.9 InputChannel发送消息到inputDispatcher线程handleReceiveCallback回调

/frameworks/native/libs/input/InputTransport.cpp
status_t InputChannel::sendMessage(const InputMessage* msg) {
    const size_t msgLength = msg->size();
    InputMessage cleanMsg;
    // copy一份msg
    msg->getSanitizedCopy(&cleanMsg);
    ssize_t nWrite;
    do {
        // 通过socket循环写入msg
        nWrite = ::send(mFd.get(), &cleanMsg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL);
    } while (nWrite == -1 && errno == EINTR);
    ..........
    return OK;
}

..........

frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp
status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel) {
#if DEBUG_REGISTRATION
    ALOGD("channel '%s' ~ registerInputChannel", inputChannel->getName().c_str());
#endif
  
    { // acquire lock
        std::scoped_lock _l(mLock);
        // ...
        // 创建connection并添加的注册列表中
        sp<Connection> connection = new Connection(inputChannel, false /*monitor*/, mIdGenerator);
        int fd = inputChannel->getFd();
        mConnectionsByFd[fd] = connection;
        mInputChannelsByToken[inputChannel->getConnectionToken()] = inputChannel;
        // 将inputChannel的fd添加到looper中,并且对应的event是ALOOPER_EVENT_INPUT
        // 传入的looper callback为handleReceiveCallback方法,
        // 因此当事件到来时,会触发此callback
        mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
    } // release lock
  
    // Wake the looper because some connections have changed.
    mLooper->wake();
    return OK;
}

7.10 InputDispatcher.handleReceiveCallback

/frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp

int InputDispatcher::handleReceiveCallback(int fd, int events, void* data) {
    InputDispatcher* d = static_cast<InputDispatcher*>(data);

    { // acquire lock
        AutoMutex _l(d->mLock);

        ssize_t connectionIndex = d->mConnectionsByFd.indexOfKey(fd);
        if (connectionIndex < 0) {
            ALOGE("Received spurious receive callback for unknown input channel.  "
                    "fd=%d, events=0x%x", fd, events);
            return 0; // remove the callback
        }

        bool notify;
        sp<Connection> connection = d->mConnectionsByFd.valueAt(connectionIndex);
        if (!(events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP))) {
            if (!(events & ALOOPER_EVENT_INPUT)) {
                ALOGW("channel '%s' ~ Received spurious callback for unhandled poll event.  "
                        "events=0x%x", connection->getInputChannelName(), events);
                return 1;
            }

            nsecs_t currentTime = now();
            bool gotOne = false;
            status_t status;
            // 通过一个无限循环读取,尽可能读取所有的反馈结果
            for (;;) {
                uint32_t seq;
                bool handled;
                // 接收消息
                status = connection->inputPublisher.receiveFinishedSignal(&seq, &handled);
                if (status) {
                    break;
                }
                // 调用 InputDispatcher 类 finishDispatchCycleLocked 方法
                d->finishDispatchCycleLocked(currentTime, connection, seq, handled);
                gotOne = true;
            }
            if (gotOne) {
                // 调用 runCommandsLockedInterruptible 执行命令(Commond)
                d->runCommandsLockedInterruptible();
                if (status == WOULD_BLOCK) {
                    return 1;
                }
            }
            ......
        } else {
            ......
        }
        ......
    } // release lock
}

 主要作用:

  • mConnectionsByFd 取出 Connection
  • 调用 Connection 类成员变量 inputPublisher 的 receiveFinishedSignal 方法接收消息
  • 调用 InputDispatcher 类 finishDispatchCycleLocked 方法
  • 调用 runCommandsLockedInterruptible 执行命令(Commond)

7.11 InputPublisher.receiveFinishedSignal

/frameworks/native/libs/input/InputTransport.cpp

status_t InputPublisher::receiveFinishedSignal(uint32_t* outSeq, bool* outHandled) {
    ......
    InputMessage msg;
    status_t result = mChannel->receiveMessage(&msg);
    if (result) {
        *outSeq = 0;
        *outHandled = false;
        return result;
    }
    if (msg.header.type != InputMessage::TYPE_FINISHED) {
        ALOGE("channel '%s' publisher ~ Received unexpected message of type %d from consumer",
                mChannel->getName().string(), msg.header.type);
        return UNKNOWN_ERROR;
    }
    *outSeq = msg.body.finished.seq;
    *outHandled = msg.body.finished.handled;
    return OK;
}

 从服务端 InputChannel 读取发来的消息。

7.12 InputDispatcher.finishDispatchCycleLocked

/frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp

  void InputDispatcher::finishDispatchCycleLocked(nsecs_t currentTime,
                                                  const sp<Connection>& connection, uint32_t seq,
                                                  bool handled) {
  #if DEBUG_DISPATCH_CYCLE
      ALOGD("channel '%s' ~ finishDispatchCycle - seq=%u, handled=%s",
            connection->getInputChannelName().c_str(), seq, toString(handled));
  #endif
  
      if (connection->status == Connection::STATUS_BROKEN ||
          connection->status == Connection::STATUS_ZOMBIE) {
          return;
      }
  
      // Notify other system components and prepare to start the next dispatch cycle.
        // // 通知其他系统组件并准备开始下一个调度周期
      onDispatchCycleFinishedLocked(currentTime, connection, seq, handled);
  }

7.13 InputDispatcher.onDispatchCycleFinishedLocked

/frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp

  void InputDispatcher::onDispatchCycleFinishedLocked(nsecs_t currentTime,
                                                      const sp<Connection>& connection, uint32_t seq,
                                                      bool handled) {
         // 创建命令并加入到命令队列 mCommandQueue 中
        // 当命令调用时,会执行 doDispatchCycleFinishedLockedInterruptible 函数
      std::unique_ptr<CommandEntry> commandEntry = std::make_unique<CommandEntry>(
              &InputDispatcher::doDispatchCycleFinishedLockedInterruptible);
      commandEntry->connection = connection;
      commandEntry->eventTime = currentTime;
      commandEntry->seq = seq;
      commandEntry->handled = handled;
      postCommandLocked(std::move(commandEntry));
  }

7.14 InputDispatcher.doDispatchCycleFinishedLockedInterruptible

/frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp

  void InputDispatcher::doDispatchCycleFinishedLockedInterruptible(CommandEntry* commandEntry) {
      sp<Connection> connection = commandEntry->connection;
      const nsecs_t finishTime = commandEntry->eventTime;
      uint32_t seq = commandEntry->seq;
      const bool handled = commandEntry->handled;
  
      // Handle post-event policy actions.
        // 根据序号seq,从连接的等待队列中获取事件
      std::deque<DispatchEntry*>::iterator dispatchEntryIt = connection->findWaitQueueEntry(seq);
      if (dispatchEntryIt == connection->waitQueue.end()) {
          return;
      }
        // 获取对应的事件
      DispatchEntry* dispatchEntry = *dispatchEntryIt;

        // 如果事件处理的有一点点慢,但是没超过超时事件,那么这里会给一个警告
        // 这也说明,窗口处理事件,不要执行耗时的代码
      const nsecs_t eventDuration = finishTime - dispatchEntry->deliveryTime;
      if (eventDuration > SLOW_EVENT_PROCESSING_WARNING_TIMEOUT) {
          ALOGI("%s spent %" PRId64 "ms processing %s", connection->getWindowName().c_str(),
                ns2ms(eventDuration), dispatchEntry->eventEntry->getDescription().c_str());
      }
      reportDispatchStatistics(std::chrono::nanoseconds(eventDuration), *connection, handled);
  
      bool restartEvent;
      if (dispatchEntry->eventEntry->type == EventEntry::Type::KEY) {
          KeyEntry* keyEntry = static_cast<KeyEntry*>(dispatchEntry->eventEntry);
          restartEvent =
                  afterKeyEventLockedInterruptible(connection, dispatchEntry, keyEntry, handled);
      } else if (dispatchEntry->eventEntry->type == EventEntry::Type::MOTION) {
          MotionEntry* motionEntry = static_cast<MotionEntry*>(dispatchEntry->eventEntry);
          restartEvent = afterMotionEventLockedInterruptible(connection, dispatchEntry, motionEntry,
                                                             handled);
      } else {
          restartEvent = false;
      }
  
      // Dequeue the event and start the next cycle.
      // Because the lock might have been released, it is possible that the
      // contents of the wait queue to have been drained, so we need to double-check
      // a few things.
      dispatchEntryIt = connection->findWaitQueueEntry(seq);
      if (dispatchEntryIt != connection->waitQueue.end()) {
          dispatchEntry = *dispatchEntryIt;
            // 从 Connection::waitQueue 中移除等待反馈的事件
          connection->waitQueue.erase(dispatchEntryIt);
            // 既然事件处理结果已经反馈了,那么就不用再记录它的处理超时时间了
          mAnrTracker.erase(dispatchEntry->timeoutTime,
                            connection->inputChannel->getConnectionToken());
            // 连接从无响应变为可响应,那么停止 ANR
          if (!connection->responsive) {
              connection->responsive = isConnectionResponsive(*connection);
          }
          traceWaitQueueLength(connection);
          if (restartEvent && connection->status == Connection::STATUS_NORMAL) {
              connection->outboundQueue.push_front(dispatchEntry);
                 traceOutboundQueueLength(connection);
          } else {
              releaseDispatchEntry(dispatchEntry);
          }
      }
  
      // Start the next dispatch cycle for this connection.
        // 既然通过连接收到反馈,那趁这个机会,如果发件箱还有事件,继续启动分发循环来发送事件
      startDispatchCycleLocked(now(), connection);
  }

 7.15 小结

  1. 检查连接中是否有对应的正在的等待的事件。
  2. 窗口已经反馈的事件的处理结果,那么从连接的等待队列 Connection::waitQueue 中移除。
  3. 窗口已经反馈的事件的处理结果,那么就不必处理这个事件的 ANR,因此移除事件的 ANR 超时时间。
  4. 此时窗口正在反馈事件的处理结果,那趁热打铁,那么开启下一次分发循环,发送连接发件箱中的事件。当然,如果发件箱没有事件,那么什么也不做。

完成分发循环,其实最主要的就是把按键事件从连接的等待队列中移除,以及解除 ANR 的触发。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值