[Android] Input事件分发流程之InputReader(2)

继IMS构造方法分析完成后,看看IMS中的start方法

public void start() {
        Slog.i(TAG, "Starting input manager");
        // 之前初始化了InputManager->inputDispatcher&&inputReader
        // 这里开始start它们,并且会创建InputThread线程,也就是InputReaderThread和InputDispatcherThread
        // InputThread是一个自定义的类,它接受三个参数:一个字符串作为线程名,
        // 一个lambda表达式作为线程函数,另一个lambda表达式在线程结束时被调用
        nativeStart(mPtr);

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

        //注册触摸点速度和是否显示功能的观察者
        registerPointerSpeedSettingObserver();
        registerShowTouchesSettingObserver();
       ...
        // 更新触摸点的速度
        updatePointerSpeedFromSettings();
        // 是否在屏幕上显示触摸点
        updateShowTouchesFromSettings();
        updateAccessibilityLargePointerFromSettings();
        updateDeepPressStatusFromSettings("just booted");
        updateMaximumObscuringOpacityForTouchFromSettings();
        updateBlockUntrustedTouchesModeFromSettings();
    }

以上只关注nativeStart(mPtr);,mPtr指向的就是NativeInputManager,之前初始化了InputManager->inputDispatcher&&inputReader,这里开始start它们,并且会创建InputThread线程,也就是InputReaderThread和InputDispatcherThread

// **com_android_server_input_InputManagerService.cpp**
static void nativeStart(JNIEnv* env, jclass /* clazz */, jlong ptr) {
    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
    // 获取InputManager,调用它的start
    status_t result = im->getInputManager()->start();
    if (result) {
        jniThrowRuntimeException(env, "Input manager could not be started.");
    }
}

// **InputManager.cpp**
status_t InputManager::start() {
    // 调用inputDispatcher的start()
    status_t result = mDispatcher->start();
    if (result) {
        ALOGE("Could not start InputDispatcher thread due to error %d.", result);
        return result;
    }
    // 调用inputReader的start()
    result = mReader->start();
    if (result) {
        ALOGE("Could not start InputReader due to error %d.", result);

        mDispatcher->stop();
        return result;
    }

    return OK;
}

InputReader线程

也就是在InputManager中调用了mDispatcher->start();和mReader->start();去分别创建对应的线程,并让Inputeader和InputDispatcher执行具体逻辑。先来看看InputReader中的start方法

status_t InputReader::start() {
    if (mThread) {
        return ALREADY_EXISTS;
    }
    // InputThread是一个自定义的类,它接受三个参数:一个字符串作为线程名,一个lambda表达式作为线程函数,
    // 另一个lambda表达式在线程结束时被调用
    mThread = std::make_unique<InputThread>(
            "InputReader", [this]() { loopOnce(); }, [this]() { mEventHub->wake(); });
    return OK;
}

// 这里就是start后的主要内容
// 读取eventHub里面的设备节点内容
// 调用的是 mEventHub->getEvents
void InputReader::loopOnce() {
    int32_t oldGeneration;
    int32_t timeoutMillis;
    bool inputDevicesChanged = false;
    ...
    // 读取设备里的所有事件,存放到了mEventBuffer
		// RawEvent mEventBuffer[EVENT_BUFFER_SIZE] GUARDED_BY(mLock);
    size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);

    { // acquire lock
        ...
        if (count) {
            // 关键代码
            processEventsLocked(mEventBuffer, count);
        }
		...
    mQueuedListener->flush();
}

首先调用了mEventHub中的getEvents方法其获取输入的原始事件,并存放到RawEvent中,所以该实体类中存放的是原始输入事件,然后调用了之前初始化创建的mQueuedListener,调用flush()将事件发送给InputDispatcher中,继续看看EventHub中的getEvents方法

size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer/*缓存事件*/, size_t bufferSize/*256*/) {
    struct input_event readBuffer[bufferSize];

    // 原始事件
    RawEvent* event = buffer;
    // 256
    size_t capacity = bufferSize;
    bool awoken = false;
    // 循环读取设备节点
    for (;;) {
        ...
				// std::vector> mOpeningDevices;
				// 初始化动作,主要是打开设备和扫描设备
        // 扫描设备,并打开每个设备目录/dev/input/...
        scanDevicesLocked();
				while (!mOpeningDevices.empty()) {
						// 获取mOpeningDevices中的设备/dev/input/目录下的文件:event1/2/3/4等
            std::unique_ptr<Device> device = std::move(*mOpeningDevices.rbegin());
            mOpeningDevices.pop_back();
            ALOGV("Reporting device opened: id=%d, name=%s\n", device->id, device->path.c_str());
						// 将每个设备打包生成RawEvent(event)形式进行存储对应的信息
            event->when = now;
            event->deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
            // 添加设备的事件
            event->type = DEVICE_ADDED;
            event += 1;
						...
        }
				// 这里是开始处理每个设备中的事件
				while (mPendingEventIndex < mPendingEventCount) {
            // 从mPendingEventCount读取事件
            const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];
            ...
            // 打开/dev/input/... event1/2/3等设备文件
            Device* device = getDeviceByFdLocked(eventItem.data.fd);
            if (device == nullptr) {
                ALOGE("Received unexpected epoll event 0x%08x for unknown fd %d.", eventItem.events,
                      eventItem.data.fd);
                ALOG_ASSERT(!DEBUG);
                continue;
            }
						...
            // This must be an input event
            // 读取设备中的输入事件
            if (eventItem.events & EPOLLIN) {
                // 读取设备里面的事件内容
                int32_t readSize =
                        read(device->fd, readBuffer, sizeof(struct input_event) * capacity);
                if (readSize == 0 || (readSize < 0 && errno == ENODEV)) {
                    // Device was removed before INotify noticed.
                    ALOGW("could not get event, removed? (fd: %d size: %" PRId32
                          " bufferSize: %zu capacity: %zu errno: %d)\n",
                          device->fd, readSize, bufferSize, capacity, errno);
                    deviceChanged = true;
										// 没有事件则关闭设备
                    closeDeviceLocked(*device);
                } ... else {
                    int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;

                    // 获取设备输入事件的数量
                    size_t count = size_t(readSize) / sizeof(struct input_event);
                    for (size_t i = 0; i < count; i++) {
                        // 将每个事件打包生成RawEvent
                        struct input_event& iev = readBuffer[i];
                        event->when = processEventTimestamp(iev);
                        event->readTime = systemTime(SYSTEM_TIME_MONOTONIC);
                        event->deviceId = deviceId;
                        event->type = iev.type;
                        event->code = iev.code;
                        event->value = iev.value;
                        event += 1;
                        capacity -= 1;
                    }
                    ...
                }
            } 
						...
        }
				...
				// poll之前先释放锁
        mLock.unlock(); // release lock before poll
        // 等待input事件的到来
        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;
}

以上内容就是scanDevicesLocked做初始化动作,扫描设备,打开设备,将设备保存到mOpeningDevices中,然后循环读取每个设备中的事件,将每个事件封装成RawEvent并加上了DEVICE_ADDED这个标志(后面会用到,来决定是移除还是新增),再保存到buffer(mEventBuffer)里面,如果设备中没有事件了则会关闭设备,然后通过epoll_wait来一直等等下一次的input事件到来,所以我们回到InputReader.cpp#loopOnce中继续分析processEventsLocked(mEventBuffer, count);

void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {
    // rawEvents保存了通过EventHub中获取的设备里的事件
    // count是事件数量
    for (const RawEvent* rawEvent = rawEvents; count;) {
        int32_t type = rawEvent->type;
        size_t batchSize = 1;
        if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) {
            ...
					// 事件的处理
					processEventsForDeviceLocked(deviceId, rawEvent, batchSize);
        } else {
            // 在EventHub.getEvents中有处理,每个事件都会封装为RawEvent,并且而加上了DEVICE_ADDED标志
            switch (rawEvent->type) {
                case EventHubInterface::DEVICE_ADDED:
                    // 创建设备,eventHubId设备唯一id,通过id可获取设备
										// 这里主要是创建InputDevice,根据device判断是鼠标类型触摸事件,还是键盘类,或触摸屏类
                    addDeviceLocked(rawEvent->when, rawEvent->deviceId);
                    break;
                case EventHubInterface::DEVICE_REMOVED:
                    removeDeviceLocked(rawEvent->when, rawEvent->deviceId);
                    break;
                case EventHubInterface::FINISHED_DEVICE_SCAN:
                    handleConfigurationChangedLocked(rawEvent->when);
                    break;
                default:
                    ALOG_ASSERT(false); // can't happen
                    break;
            }
        }
        // 处理完事件,count减少
        count -= batchSize;
        // 处理完事件,指针向后移动一个
        rawEvent += batchSize;
    }
}

void InputReader::processEventsForDeviceLocked(int32_t eventHubId, const RawEvent* rawEvents,
                                               size_t count) {
    auto deviceIt = mDevices.find(eventHubId);
    ...
    // 调用InputDevice的process
    // 传递原始事件+事件数量
    device->process(rawEvents, count);
}

首先会走addDeviceLocked来创建InputDevice,因为/dev/input里每个device的功能都不同,有的处理指纹事件,有的处理鼠标键盘类数据,有的处理屏幕触摸事件,然后再执行到processEventsForDeviceLocked,因为processEventsForDeviceLocked执行之前已经创建了各个类型的InputDevice,这里就是调用对应类型的InputDevice.process方法,那随便找一个TouchInputMapper.cpp来分析吧,触摸事件

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

void TouchInputMapper::process(const RawEvent* rawEvent/*原始事件*/) {
		// 鼠标按下,滚动,触摸
    mCursorButtonAccumulator.process(rawEvent);
    mCursorScrollAccumulator.process(rawEvent);
    mTouchButtonAccumulator.process(rawEvent);

    if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
        // 主要关注sync
        sync(rawEvent->when, rawEvent->readTime);
    }
}

sync会继续调用processRawTouches,接着看

// 它处理原始触摸输入数据并将其转换为可读的触摸事件。
// 首先,它检查设备模式是否为DISABLED。如果是,它将取消当前的触摸,并清空当前的状态(mCurrentCookedState),然后更新触摸点。
// 接下来,它会处理任何待处理的原始触摸状态。这些状态被存储在mRawStatesPending中。
// 如果当前状态是一个stylus(触笔)状态,则会检查是否需要等待stylus数据。
// 如果需要等待,它将退出循环。否则,它会将当前状态设为下一个待处理状态,并通过cookAndDispatch函数将其转换为可读的触摸事件
void TouchInputMapper::processRawTouches(bool timeout) {
		// 检查设备是否处于disabled状态
    if (mDeviceMode == DeviceMode::DISABLED) {
        // Drop all input if the device is disabled.
        cancelTouch(mCurrentRawState.when, mCurrentRawState.readTime);
        ...
        return;
    }

    // 它会处理任何待处理的原始触摸状态,这些状态被存储在mRawStatesPending中。
    const size_t N = mRawStatesPending.size();
    size_t count;
    // 待处理的原始事件 RawEvent
    for (count = 0; count < N; count++) {
        ...
        // 继续调用,主要就是将原始事件转换为可读的触摸事件
        cookAndDispatch(mCurrentRawState.when, mCurrentRawState.readTime);
    }
    ...
}

简要说明一下cookAndDispatch方法的作用,判断事件的类型属于手势触摸还是鼠标等类型,假设是手势触摸则调用dispatchPointerGestures进行事件分发,然后判断事件是否移动,tap按下等状态,进行单独处理和事件分发,并把当前手指通过markBit(id);存入一个整型变量中,所以不管有多少个手指触摸,都以进制形式存放在一个变量中,内存开销小,最后调用dispatchMotion方法将事件的状态,例如是否按下,按下的时间,事件动作,以及事件id封装到NotifyMotionArgs中,然后进行分发(也就是通知消息并携带该args给InputDispatcher),实际是调用getListener()->notifyMotion(&args);

所以继续看看InputDispatcher.cpp中的notifyMotion方法,进入下一个阶段

总结:

  1. 从InputReader线程创建开始,第一时间就是从EventHub中的getEvents方法中打开/dev/input中的设备,然后循环读取设备中的事件,获取事件,并转换为原始事件(RawEvent),然后再将原始事件,此次事件处理完成后继续循环等待input事件的到来

2.然后再继续调用了processEventsLocked判断原始事件属于什么类型,例如触摸,鼠标,键盘等,创建对应的InputDevice

  1. 接着继续调用processEventsForDeviceLocked来处理InputDevice→process,然后继续分析了TouchInputMapper.cpp,因为这个mapper就是InputDevice的其中一种类型,根据事件类型,判断是否点击,滑动,多个手势,将事件信息封装成NotifyMotionArgs,将手指封装到整型变量中,代表有多少个手指,然后分发给InputDispatcher

你可能感兴趣的:(Android开发旅途,android,开发语言,aosp)