InputManagerService分发输入事件给应用程序(上)

InputManagerService分发输入事件给应用程序(上)

    • InputManagerService分发输入事件给应用程序上
      • 简介
      • 源码分析
      • 小结

1.简介

在InputManagerService服务初始化时,会在Native层创建两个线程:InputDispatcherThread和InputReaderThread。InputReader线程负责读取输入事件,并把输入事件传递给InputDispatcher线程,然后由InputDispatcher将输入事件分发给处于激活的窗口。

接下来将从源码的角度来分析输入事件的一个分发过程。

2.源码分析

在InputReaderThread线程中,将会循环执行其threadLoop()方法。

2.1 InputReaderThread.threadLoop()

bool InputReaderThread::threadLoop() {
    mReader->loopOnce();//调用InputReader的loopOnce()方法,见2.2
    return true;
}

当threadLoop()方法返回true时,代表将循环调用loopOnce()方法。当threadLoop()方法返回false时,代表退出循环。

2.2 InputReader.loopOnce()

void InputReader::loopOnce() {
    int32_t oldGeneration;
    int32_t timeoutMillis;
    bool inputDevicesChanged = false;
    Vector inputDevices;//输入设备列表
    { // acquire lock
        AutoMutex _l(mLock);

        oldGeneration = mGeneration;
        timeoutMillis = -1;

        uint32_t changes = mConfigurationChangesToRefresh;
        if (changes) {
            mConfigurationChangesToRefresh = 0;
            timeoutMillis = 0;
            refreshConfigurationLocked(changes);
        } else if (mNextTimeout != LLONG_MAX) {
            nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
            timeoutMillis = toMillisecondTimeoutDelay(now, mNextTimeout);
        }
    } // release lock

    size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);// 1.从EventHub中获取输入事件,见2.3

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

        if (count) {
            processEventsLocked(mEventBuffer, count);//2.如果获取到了输入事件,则处理该输入事件,见2.4
        }

        if (mNextTimeout != LLONG_MAX) {
            nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
            if (now >= mNextTimeout) {
                mNextTimeout = LLONG_MAX;
                timeoutExpiredLocked(now);
            }
        }

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

    if (inputDevicesChanged) {// 输入设备发生了变化
        mPolicy->notifyInputDevicesChanged(inputDevices);
    }

    mQueuedListener->flush();// 3.发送输入事件到InputDispatcher,见2.12
}

在loopOnce()方法中,主要做了三件事情:

  1. 通过EventHub的getEvents()方法获取输入事件,该方法将返回准备好的输入事件;
  2. 调用processEventsLocked()方法来处理输入事件;
  3. 通过mQueuedListener的flush()方法将输入事件发送到InputDispatcher;

接下来将分别围绕这三个过程来讲解。

2.3 EventHub.getEvents()

size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
    ALOG_ASSERT(bufferSize >= 1);
    AutoMutex _l(mLock);
    struct input_event readBuffer[bufferSize];
    RawEvent* event = buffer;//原始事件
    size_t capacity = bufferSize;//容量大小为256
    bool awoken = false;
    for (;;) {
        nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);// 当前时间
        // 是否需要重新打开设备
        if (mNeedToReopenDevices) {
            mNeedToReopenDevices = false;

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

            closeAllDevicesLocked();
            mNeedToScanDevices = true;
            break; 
        }

        // 记录最近被删除的设备
        while (mClosingDevices) {
        Device* device = mClosingDevices;
        mClosingDevices = device->next;
        event->when = now;
        event->deviceId = device->id == mBuiltInKeyboardId ? BUILT_IN_KEYBOARD_ID : device->id;
        event->type = DEVICE_REMOVED;//事件类型为设备删除
        event += 1;
        delete device;
        mNeedToSendFinishedDeviceScan = true;
        if (--capacity == 0) {
            break;
            }
        }

        // 需要扫描设备
        if (mNeedToScanDevices) {
            mNeedToScanDevices = false;
            scanDevicesLocked();//扫描设备,扫描的路径为/dev/input
            mNeedToSendFinishedDeviceScan = true;
        }

        // 记录打开的设备
        while (mOpeningDevices != NULL) {
        Device* device = mOpeningDevices;
        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;
        }

        //结束设备扫描
        if (mNeedToSendFinishedDeviceScan) {
            mNeedToSendFinishedDeviceScan = false;
            event->when = now;
            event->type = FINISHED_DEVICE_SCAN;//事件类型为设备扫描结束
            event += 1;
            if (--capacity == 0) {
                break;
            }
        }

        // 获取下一个输入事件
        bool deviceChanged = false;
        while (mPendingEventIndex < mPendingEventCount) {
        const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];//获取待处理的epoll事件
        if (eventItem.data.u32 == EPOLL_ID_INOTIFY) {//epoll数据类型为EPOLL_ID_INOTIFY
            if (eventItem.events & EPOLLIN) {//epoll事件类型为可读
                mPendingINotify = true;//发送通知
            } else {
                ALOGW("Received unexpected epoll event 0x%08x for INotify.", eventItem.events);
            }
            continue;
            }
        }

        // epoll数据类型为EPOLL_ID_WAKE
        if (eventItem.data.u32 == EPOLL_ID_WAKE) {
            if (eventItem.events & EPOLLIN) {//epoll事件类型为可读
                ALOGV("awoken after wake()");
                awoken = true;//唤醒
                char buffer[16];
                ssize_t nRead;
                do {
                    nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer));//从mWakeReadPipeFd中读取数据
                } while ((nRead == -1 && errno == EINTR) || nRead == sizeof(buffer));
            } else {
                ALOGW("Received unexpected epoll event 0x%08x for wake read pipe.",
                        eventItem.events);
            }
            continue;
        }

        ssize_t deviceIndex = mDevices.indexOfKey(eventItem.data.u32);// 获取设备索引

        Device* device = mDevices.valueAt(deviceIndex);// 根据设备索引获取设备

        if (eventItem.events & EPOLLIN) {//如果epoll事件类型为可读
            int32_t readSize = read(device->fd, readBuffer,
                    sizeof(struct input_event) * capacity);//从设备文件描述符中读取数据到readBuffer

            if (readSize == 0 || (readSize < 0 && errno == ENODEV)) {
                deviceChanged = true;
                closeDeviceLocked(device);
            } else if (readSize < 0) {
               .......
            } else if ((readSize % sizeof(struct input_event)) != 0) {
                ......
            } else {
                int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;//设备ID
                size_t count = size_t(readSize) / sizeof(struct input_event);//获取读到的输入事件数量
                for (size_t i = 0; i < count; i++) {
                    struct input_event& iev = readBuffer[i];//输入事件
                    .......
                    //将input_event事件,封装成RawEvent事件
                    event->when = nsecs_t(iev.time.tv_sec) * 1000000000LL
                            + nsecs_t(iev.time.tv_usec) * 1000LL;
                    event->deviceId = deviceId;
                    event->type = iev.type;
                    event->code = iev.code;
                    event->value = iev.value;
                    event += 1;
                    capacity -= 1;
                    if (capacity == 0) {
                    mPendingEventIndex -= 1;
                    break;
                }
            }
            .....
            // 如果获取到了输入事件或者需要唤醒,则立即返回
            if (event != buffer || awoken) {
                break;
            }
            mPendingEventIndex = 0;
            mLock.unlock();//释放锁
            release_wake_lock(WAKE_LOCK_ID);
            int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis);//等待输入事件到来

            acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
            mLock.lock();//获取锁

            if (pollResult == 0) {//发生了超时
                mPendingEventCount = 0;
                break;
            }

            if (pollResult < 0) {
                // 发生了错误
                mPendingEventCount = 0;
                ......
            } else {
            // 发生了一些输入事件
            mPendingEventCount = size_t(pollResult);
            }

        }
    }

    return event - buffer;//然后读取的输入事件
}

在EventHub的getEvent方法中,如果是第一次调用的话,则需要先扫描/dev/input目录下的输入设备。接着用mPendingEventItems保存待处理的输入事件,如果以及有输入事件需要处理,则立即返回;否则通过epoll_wait等待输入事件到来。

从EventHub中获取到输入事件之后,接着调用processEventsLocked()方法进行事件处理。

2.4 InputReader.processEventsLocked()

void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {
    for (const RawEvent* rawEvent = rawEvents; count;) {
        int32_t type = rawEvent->type;//获取输入事件类型
        size_t batchSize = 1;
        if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) {
            int32_t deviceId = rawEvent->deviceId;//设备ID
            while (batchSize < count) {
                if (rawEvent[batchSize].type >= EventHubInterface::FIRST_SYNTHETIC_EVENT
                        || rawEvent[batchSize].deviceId != deviceId) {
                    break;
                }
                batchSize += 1;
            }
            processEventsForDeviceLocked(deviceId, rawEvent, batchSize);// 处理设备事件,见2.7
        } else {
            switch (rawEvent->type) {
            case EventHubInterface::DEVICE_ADDED:
                addDeviceLocked(rawEvent->when, rawEvent->deviceId);//添加设备,见2.5
                break;
            case EventHubInterface::DEVICE_REMOVED:
                removeDeviceLocked(rawEvent->when, rawEvent->deviceId);//移除设备
                break;
            case    EventHubInterface::FINISHED_DEVICE_SCAN:
                handleConfigurationChangedLocked(rawEvent->when);//设备扫描结束
                break;
            default:
                ALOG_ASSERT(false); // can't happen
                break;
            }
        }
        count -= batchSize;//更新待处理的输入事件数量
        rawEvent += batchSize;
    }
}

事件处理总共有以下几种类型:

  • DEVICE_ADDED:设备添加;
  • DEVICE_REMOVED:设备移除;
  • FINISHED_DEVICE_SCAN:设备扫描完成;
  • 输入事件处理

下面看下设备添加事件处理过程。

2.5 InputReader.addDeviceLocked()

void InputReader::addDeviceLocked(nsecs_t when, int32_t deviceId) {
    ssize_t deviceIndex = mDevices.indexOfKey(deviceId);//设备索引
    if (deviceIndex >= 0) {
        //设备已经添加了,则直接返回
        return;
    }

    InputDeviceIdentifier identifier = mEventHub->getDeviceIdentifier(deviceId);
    uint32_t classes = mEventHub->getDeviceClasses(deviceId);
    int32_t controllerNumber = mEventHub->getDeviceControllerNumber(deviceId);

    InputDevice* device = createDeviceLocked(deviceId, controllerNumber, identifier, classes);//创建设备,见2.6
    device->configure(when, &mConfig, 0);
    device->reset(when);

    mDevices.add(deviceId, device);//添加设备到mDevices中
    ......
}

2.6 InputReader.createDeviceLocked()

InputDevice* InputReader::createDeviceLocked(int32_t deviceId, int32_t controllerNumber,
    const InputDeviceIdentifier& identifier, uint32_t classes) {

    InputDevice* device = new InputDevice(&mContext, deviceId, bumpGenerationLocked(),
        controllerNumber, identifier, classes);//创建InputDevice对象

    // 外部设备
    if (classes & INPUT_DEVICE_CLASS_EXTERNAL) {
        device->setExternal(true);
    }

    // 鼠标
    if (classes & INPUT_DEVICE_CLASS_MIC) {
        device->setMic(true);
    }

    ......

    // 键盘类型
    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;
    }

    // 添加键盘类设备KeyboardInputMapper
    if (keyboardSource != 0) {
        device->addMapper(new KeyboardInputMapper(device, keyboardSource, keyboardType));
    }

    // 添加鼠标类设备CursorInputMapper
    if (classes & INPUT_DEVICE_CLASS_CURSOR) {
        device->addMapper(new CursorInputMapper(device));
    }

    // 添加触屏类设备MultiTouchInputMapper或者SingleTouchInputMapper
    if (classes & INPUT_DEVICE_CLASS_TOUCH_MT) {
        device->addMapper(new MultiTouchInputMapper(device));
    } else if (classes & INPUT_DEVICE_CLASS_TOUCH) {
        device->addMapper(new SingleTouchInputMapper(device));
    }

    .....
    return device;
}

该方法的主要功能是创建一个InputDevice对象,将InputReader的mContext对象赋值给InputDevice对象所对应的变量;根据设备的类型来创建并添加对应的InputMapper。

输入设备的类型有很多种,其中常见的包含以下几种:

  • 键盘类设备:KeyboardInputMapper
  • 触屏类设备:MultiTouchInputMapper或者SingleTouchInputMapper
  • 鼠标类设备:CursorInputMapper

介绍完了设备的添加过程,接下来回到2.4处,继续分析设备输入事件的处理过程,该过程主要是调用processEventsForDeviceLocked()方法。

2.7 InputReader.processEventsForDeviceLocked()

void InputReader::processEventsForDeviceLocked(int32_t deviceId,
    const RawEvent* rawEvents, size_t count) {
    ssize_t deviceIndex = mDevices.indexOfKey(deviceId);//设备索引
    if (deviceIndex < 0) {
        //如果设备不存在,则直接返回
        return;
    }

    InputDevice* device = mDevices.valueAt(deviceIndex);//获取设备
    if (device->isIgnored()) {
        //如果设备需要忽略,则直接返回
        return;
    }

    device->process(rawEvents, count);//调用InputDevice的process方法来处理,见2.8
}

2.8 InputDevice.process()

void InputDevice::process(const RawEvent* rawEvents, size_t count) {
    size_t numMappers = mMappers.size();//mapper的数量
    // 处理所有的输入事件
    for (const RawEvent* rawEvent = rawEvents; count--; rawEvent++) {
        if (mDropUntilNextSync) {
            if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
                mDropUntilNextSync = false;
            }
        } else if(rawEvent->type == EV_SYN && rawEvent->code == SYN_DROPPED){
            mDropUntilNextSync = true;
            reset(rawEvent->when);
        }else {
            // 调用每个mapper依次处理该事件
            for (size_t i = 0; i < numMappers; i++) {
                InputMapper* mapper = mMappers[i];//获取InputMapper
                mapper->process(rawEvent);// 调用InputMapper的处理方法,见2.9
            }
        }
    }
}

针对每个mapper,顺序处理所有的输入事件。在前面的2.6过程中,创建了许多类型的InputMapper,这里我们将以KeyboardInputMapper(按键事件)为例来说明事件的传递过程。

2.9 KeyboardInputMapper.process()

void KeyboardInputMapper::process(const RawEvent* rawEvent) {
    switch (rawEvent->type) {
        case EV_KEY: {
            int32_t scanCode = rawEvent->code;
            int32_t usageCode = mCurrentHidUsage;
            mCurrentHidUsage = 0;

            if (isKeyboardOrGamepadKey(scanCode)) {//按键事件
                processKey(rawEvent->when, rawEvent->value != 0, scanCode, usageCode);//处理方法,见2.10
            }
            break;
        }
        ......
    }
}

在KeyboardInputMapper方法中,首先会判断扫描码是否为键盘码,如果是的话,则调用processKey()方法处理。

2.10 KeyboardInputMapper.processKey()

void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t scanCode,int32_t usageCode) {
    int32_t keyCode;
    int32_t keyMetaState;
    uint32_t policyFlags;
    if (getEventHub()->mapKey(getDeviceId(), scanCode, usageCode, mMetaState,
                          &keyCode, &keyMetaState, &policyFlags)) {// 根据扫描码获取对应的keyCode
        keyCode = AKEYCODE_UNKNOWN;
        keyMetaState = mMetaState;
        policyFlags = 0;
    }

    if (down) {//处理按下的键
        // 根据方向需要旋转keyCode
        if (mParameters.orientationAware && mParameters.hasAssociatedDisplay) {
            keyCode = rotateKeyCode(keyCode, mOrientation);
        }
        // 添加key down事件
        ssize_t keyDownIndex = findKeyDown(scanCode);// key down索引
        if (keyDownIndex >= 0) {
            // key事件重复了,必须确保和之前的keyCode一致
            keyCode = mKeyDowns.itemAt(keyDownIndex).keyCode;
        } else {
            if ((policyFlags & POLICY_FLAG_VIRTUAL)
                && mContext->shouldDropVirtualKey(when,
                        getDevice(), keyCode, scanCode)) {
                return;
            }

            if (policyFlags & POLICY_FLAG_GESTURE) {
                mDevice->cancelTouch(when);
            }
            // mKeyDowns记录着所有按下的键
            mKeyDowns.push();//压入栈顶
            KeyDown& keyDown = mKeyDowns.editTop();
            keyDown.keyCode = keyCode;
            keyDown.scanCode = scanCode;
        }
        mDownTime = when;//记录按下时间
    }else{//处理抬起操作
        移除key down事件
        ssize_t keyDownIndex = findKeyDown(scanCode);// 查找key down事件
        if (keyDownIndex >= 0) {
            // key up操作,必须确保和之前的keyCode保持一致
            keyCode = mKeyDowns.itemAt(keyDownIndex).keyCode;
            mKeyDowns.removeAt(size_t(keyDownIndex));
        } else {
            return;
        }
    }
    ......

    nsecs_t downTime = mDownTime;

    ......
    NotifyKeyArgs args(when, getDeviceId(), mSource, policyFlags,
        down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
        AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, keyMetaState, downTime);//创建NotifyKeyArgs对象,when记录eventTime,downTime记录按下时间。
    getListener()->notifyKey(&args);//通知key事件,见2.11
}

在processKey方法中,首先根据扫描码获取到对应的keyCode方法,构建NotifyKeyArgs对象,然后调用notifyKey()方法通知key事件。

NotifykeyArgs对象记录了key按下的时间,keyCode以及scanCode,定义如下:

NotifyKeyArgs::NotifyKeyArgs(nsecs_t eventTime, int32_t deviceId, uint32_t source,
    uint32_t policyFlags,
    int32_t action, int32_t flags, int32_t keyCode, int32_t scanCode,
    int32_t metaState, nsecs_t downTime) :
    eventTime(eventTime), deviceId(deviceId), source(source), policyFlags(policyFlags),
    action(action), flags(flags), keyCode(keyCode), scanCode(scanCode),
    metaState(metaState), downTime(downTime) {
}

getListener()方法获取的是mQueuedListener,而mQueuedListener的类型是QueuedInputListener。

InputListenerInterface*     InputReader::ContextImpl::getListener() {
    return mReader->mQueuedListener.get();
}

sp mQueuedListener;

2.11 QueuedInputListener.notifyKey()

void QueuedInputListener::notifyKey(const NotifyKeyArgs* args) {
    mArgsQueue.push(new NotifyKeyArgs(*args));
}

mArgsQueue的数据类型为Vector

3.小结

InputReader的核心工作就是从EventHub获取数据后生成EventEntry事件,然后加入到InputDispatcher的mInboundQueue队列,最后唤醒InputDispatcherThread线程进行处理。InputReader整个工作流程包含以下三个部分:

  1. 调用EventHub.getEvents()方法,获取原始的输入事件;通过EventHub监听输入设备(/dev/input),并从中读取输入事件到mEventBuffer数组,mEventBuffer数组大小为256,然后将输入事件input_event转换为RawEvent。具体过程见2.3。
  2. 调用processEventsLocked()方法,对输入事件进行加工处理,不同类型的输入事件,转换为不同的NotifyArgs子类。例如,键盘类的输入事件转换为NotifykeyArgs类。具体过程见2.4~2.10。
  3. 调用QueuedListener的flush()方法,将输入事件传递到InputDispatcher处理。通过InputDispatcher的notifyKey()方法,对输入事件先拦截和过滤处理,然后将输入事件放入mInboundQueue队列中。如果需要唤醒的话,则通过InputDispatcher的mLooper->wake()方法,唤醒InputDispatcherThread线程来处理输入事件。具体过程见2.11~2.21。

InputReader的调用过程如下:

InputReaderThread.threadLoop()
    InputReader.loopOnce()
        EventHub.getEvents() 
        InputReader.processEventsLocked()  
            InputReader.addDeviceLocked()
                InputReader.createDeviceLocked()
            InputReader.processEventsForDeviceLocked()
                InputDevice.process()
                    KeyboardInputMapper.process()
                        KeyboardInputMapper.processKey()
                            QueuedInputListener.notifyKey()
        QueuedInputListener.flush()
            NotifyKeyArgs.notify()
                InputDispatcher.notifyKey()
                    NativeInputManager.interceptKeyBeforeQueueing()
                        InputManagerService.interceptKeyBeforeQueueing()
                            InputMonitor.interceptKeyBeforeQueueing()
                                PhoneWindowManager.interceptKeyBeforeQueueing()
                    NativeInputManager.filterInputEvent()
                    InputDispatcher.enqueueInboundEventLocked()
                        Looper.wake()

InputManagerService分发输入事件消息给应用程序(下)将从InputDispatcherThread线程开始分析,InputDispatcher如何将输入事件分发到应用程序激活的Activity窗口。

你可能感兴趣的:(Android)