Android输入管理1:输入信息分发

205 阅读16分钟

读书笔记备忘:通过分析查看Android Framework源码,搞清输入信息在系统中的流向。

主要通过2大部分来介绍Android输入信息的管理过程。第一部分:Android输入管理1:输入信息分发。第二部分:Android输入管理2:应用进程处理Input消息过程

本文为第一部分:Android输入管理1:输入信息分发。主要介绍输入相关的服务,相关类的初始化,输入信息的接收,输入信息的处理以及输入信息的分发过程。

相关类的简介

输入管理涉及到的类非常多。 下面介绍部分主要类的功能。

InputManagerService:输入管理服务,java类,主要输入管理的入口,初始化输入相关的类,以及启动服务。有很多native方法,会通过jni把很多输入处理转入到native层处理。对于的jni文件为com_android_server_input_InputManagerService.cpp

InputManager:native类,管理InputDispatcher,InputReader,InputDispatcherThread,InputReaderThread。

InputReaderThread:循环处理读取信息的线程,将处理过程转到InputReader类中。

InputReader:处理读取的输入信息Event。并把最终丢给InputDispatcher类分发数据。

InputDispatcherThread:用于处理事件分发的线程,最终将处理转到InputDispatcher类中。

InputDispatcher:信息分发类,InputDispatcherThread创建时,其作为参数传入。将信息处理后通过InputChannel发送出去。

EventHub: 将设备加入epoll监听中,并在epoll_wait上等待输入事件的到来,并获取输入信息。在 InputReader创建时,作为参数传入InputReader对象中。

InputManagerService的创建和启动

InputManagerService类,输入管理的入口。它的构造方法如下

//InputManagerService 的构造函数
public InputManagerService(Context context) {
        this.mContext = context;
        this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());

        mUseDevInputEventForAudioJack =
                context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
        Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack="
                + mUseDevInputEventForAudioJack);
        mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());

        String doubleTouchGestureEnablePath = context.getResources().getString(
                R.string.config_doubleTouchGestureEnableFile);
        mDoubleTouchGestureEnableFile = TextUtils.isEmpty(doubleTouchGestureEnablePath) ? null :
            new File(doubleTouchGestureEnablePath);

        LocalServices.addService(InputManagerInternal.class, new LocalService());
    }

在构造方法中,根据DisplayThread线程的looper创建InputManagerHandler对象用于消息处理,然后通过mHandler.getLooper().getQueue()获取DisplayThread线程的消息队列,作为参数传给nativeInit方法。调用nativeInit方法完成初始化。nativeInit 为navtive方法。

DisplayThread类是单例类。DisplayThread线程只用于WindowManager,DisplayManager,InputManager中,提供实时快速运行系统。 以下是本地方法nativeInit代码:

static jlong nativeInit(JNIEnv* env, jclass /* clazz */,
        jobject serviceObj, jobject contextObj, jobject messageQueueObj) {
    sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
    if (messageQueue == nullptr) {
        jniThrowRuntimeException(env, "MessageQueue is not initialized.");
        return 0;
    }

    NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
            messageQueue->getLooper());
    im->incStrong(0);
    return reinterpret_cast<jlong>(im);
}

nativeInit方法主要创建NativeInputManager对象。在NativeInputManager创建了1个InputManager对象。

//NativeInputManager 的构造函数

NativeInputManager::NativeInputManager(jobject contextObj,
        jobject serviceObj, const sp<Looper>& looper) :
        mLooper(looper), mInteractive(true) {
    JNIEnv* env = jniEnv();

    mServiceObj = env->NewGlobalRef(serviceObj);

    {
        AutoMutex _l(mLock);
        mLocked.systemUiVisibility = ASYSTEM_UI_VISIBILITY_STATUS_BAR_VISIBLE;
        mLocked.pointerSpeed = 0;
        mLocked.pointerGesturesEnabled = true;
        mLocked.showTouches = false;
        mLocked.pointerCapture = false;
        mLocked.pointerDisplayId = ADISPLAY_ID_DEFAULT;
    }
    mInteractive = true;

    mInputManager = new InputManager(this, this);
    defaultServiceManager()->addService(String16("inputflinger"),
            mInputManager, false);
}

NativeInputManager 的构造函数中创建了InputManager类,同时调用defaultServiceManager()的addService方法,将InputManager注册到系统服务中。 InputManager的构造函数如下:

InputManager::InputManager(
        const sp<InputReaderPolicyInterface>& readerPolicy,
        const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
    mDispatcher = new InputDispatcher(dispatcherPolicy);
    mClassifier = new InputClassifier(mDispatcher);
    mReader = createInputReader(readerPolicy, mClassifier);
    initialize();
}

void InputManager::initialize() {
    mReaderThread = new InputReaderThread(mReader);
    mDispatcherThread = new InputDispatcherThread(mDispatcher);
}

// InputReaderFactory 的createInputReader
sp<InputReaderInterface> createInputReader(
        const sp<InputReaderPolicyInterface>& policy,
        const sp<InputListenerInterface>& listener) {
    return new InputReader(new EventHub(), policy, listener);
}

而在InputManager中有创建了InputDispatcher,InputClassifier和InputReader。同时调用initialize方法创建了2个线程对象InputReaderThread和InputDispatcherThread。 其中InputReader 的创建是调用InputReaderFactory的createInputReader 方法,并在这个方法中创建了EventHub对象。 当InputManagerService等相关对象创建和初始化结束后,SystemService中会调用InputManagerService的start方法启动服务。

//InputManagerService的start方法:
public void start() {
        Slog.i(TAG, "Starting input manager");
        nativeStart(mPtr);

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

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

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

        updatePointerSpeedFromSettings();
        updateShowTouchesFromSettings();
        updateAccessibilityLargePointerFromSettings();
    }

start方法调用本地函数nativeStart

//本地方法nativeStart
static void nativeStart(JNIEnv* env, jclass /* clazz */, jlong ptr) {
    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);

    status_t result = im->getInputManager()->start();
    if (result) {
        jniThrowRuntimeException(env, "Input manager could not be started.");
    }
}

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

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

        mDispatcherThread->requestExit();
        return result;
    }

    return OK;
}

本地方法nativeStart通过NativeInputManager获取InputManager对象引用,并调用InputManager的start方法。在InputManager的start方法中,启动了在初始化阶段创建的2个线程InputReaderThread和InputDispatcherThread,即调用他们的run方法。 以上即是InputManagerService服务的创建和启动过程。启动完成后,等待获取输入信息的到来,处理和分发消息。 消息是如何获取和分发的?看看下面一节

消息的获取

首先需要介绍一个重要的类EventHub。这个类的作用就是把所有这些设备产生的消息统一成一种格式,再发往上层进行处理。

EventHub::EventHub(void) :
        mBuiltInKeyboardId(NO_BUILT_IN_KEYBOARD), mNextDeviceId(1), mControllerNumbers(),
        mOpeningDevices(nullptr), mClosingDevices(nullptr),
        mNeedToSendFinishedDeviceScan(false),
        mNeedToReopenDevices(false), mNeedToScanDevices(true),
        mPendingEventCount(0), mPendingEventIndex(0), mPendingINotify(false) {
    acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);

    //创建——个epoll句柄
    mEpollFd = epoll_create1(EPOLL_CLOEXEC);
    LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance: %s", strerror(errno));

    //创建一个inotify对象
    mINotifyFd = inotify_init();

	//监视/dev/input目录的变化
    mInputWd = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE);
    LOG_ALWAYS_FATAL_IF(mInputWd < 0, "Could not register INotify for %s: %s",
            DEVICE_PATH, strerror(errno));
    if (isV4lScanningEnabled()) {
        mVideoWd = inotify_add_watch(mINotifyFd, VIDEO_DEVICE_PATH, IN_DELETE | IN_CREATE);
        LOG_ALWAYS_FATAL_IF(mVideoWd < 0, "Could not register INotify for %s: %s",
                VIDEO_DEVICE_PATH, strerror(errno));
    } else {
        mVideoWd = -1;
        ALOGI("Video device scanning disabled");
    }

    struct epoll_event eventItem;
    memset(&eventItem, 0, sizeof(eventItem));
    eventItem.events = EPOLLIN;
    eventItem.data.fd = mINotifyFd;

	//把inotify的句柄加入到epoll的监测中
    int result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem);
    LOG_ALWAYS_FATAL_IF(result != 0, "Could not add INotify to epoll instance.  errno=%d", errno);

    int wakeFds[2];

	//创建匿名管道
    result = pipe(wakeFds);
    LOG_ALWAYS_FATAL_IF(result != 0, "Could not create wake pipe.  errno=%d", errno);

    mWakeReadPipeFd = wakeFds[0];
    mWakeWritePipeFd = wakeFds[1];

	// 将管道读端设成非阻塞模式
    result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);
    LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake read pipe non-blocking.  errno=%d",
            errno);
	// 将管道写端设成非阻塞模式
    result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK);
    LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake write pipe non-blocking.  errno=%d",
            errno);

    eventItem.data.fd = mWakeReadPipeFd;

	// 将管道的读端加入到epoll的监测中
    result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, &eventItem);
    LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake read pipe to epoll instance.  errno=%d",
            errno);

    int major, minor;
    getLinuxRelease(&major, &minor);
    // EPOLLWAKEUP was introduced in kernel 3.5
    mUsingEpollWakeup = major > 3 || (major == 3 && minor >= 5);
}

在EventHub 构造函数中做了哪些工作? 1.创建——个epoll句柄。epoll是Linux内核为处理大批量文件描述符而做了改进的poll,是Linux下多路复用IO接口select/poll的增强版本 2.创建一个inotify对象。inotify是一个Linux特性,它监控文件系统操作,比如读取、写入和创建。 3.调用inotify_add_watch监视/dev/input目录的变化。并将句柄加入到epoll的监测中。 4.创建匿名管道,将读端管道加入到epoll的监测中。

EventHub的创建在上面的代码中已经说明。即在创建InputReader对象时,作为第一个参数new EventHub 并传入到InputReader对象中。 EventHub构造函数中,并没有和具体的输入设备关联。在EventHub中有个getEvents方法,在这个方法中读取/dev/input中对应的设备,最终调用registerFdForEpoll方法,将设备加入到epoll的监测中。 那消息读取在什么地方?我来看一下InputReaderThread线程

// --- InputReaderThread ---

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

InputReaderThread::~InputReaderThread() {
}

bool InputReaderThread::threadLoop() {
    mReader->loopOnce();
    return true;
}

上面InputManagerService启动时,start方法里面调用了InputReaderThread和InputDispatcherThread的run方法。最终导致其threadLoop被调用。threadLoop返回true,表示其会被循环调用。当返回false表示会退出循环。 mReader即是创建InputReaderThread时传入的InputReader对象。所以这里调用的是InputReader的loopOnce方法。

void InputReader::loopOnce() {
    int32_t oldGeneration;
    int32_t timeoutMillis;
    bool inputDevicesChanged = false;
    std::vector<InputDeviceInfo> 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);

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

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

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

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

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

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

在loopOnce方法中调用了mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE)方法。上面介绍过,在getEvents方法中获取了/dev/input目录下对应的设备并且将其加入到epoll监听。完成这些动作后,会等待输入事件。看一下下面的主要处理代码:

size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
    ALOG_ASSERT(bufferSize >= 1);

    AutoMutex _l(mLock);

    struct input_event readBuffer[bufferSize];

    RawEvent* event = buffer;
    size_t capacity = bufferSize;
    bool awoken = false;
    for (;;) {
        ...
        // Grab the next input event.
        bool deviceChanged = false;
        while (mPendingEventIndex < mPendingEventCount) {
            const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];

		    ...            

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

        // Poll for events.  Mind the wake lock dance!
        // We hold a wake lock at all times except during epoll_wait().  This works due to some
        // subtle choreography.  When a device driver has pending (unread) events, it acquires
        // a kernel wake lock.  However, once the last pending event has been read, the device
        // driver will release the kernel wake lock.  To prevent the system from going to sleep
        // when this happens, the EventHub holds onto its own user wake lock while the client
        // is processing events.  Thus the system can only sleep if there are no events
        // pending or currently being processed.
        //
        // The timeout is advisory only.  If the device is asleep, it will not wake just to
        // service the timeout.
        mPendingEventIndex = 0;

        mLock.unlock(); // release lock before poll, must be before release_wake_lock
        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(); // reacquire lock after poll, must be after acquire_wake_lock

        if (pollResult == 0) {
            // Timed out.
            mPendingEventCount = 0;
            break;
        }

        if (pollResult < 0) {
            // An error occurred.
            mPendingEventCount = 0;

            // Sleep after errors to avoid locking up the system.
            // Hopefully the error is transient.
            if (errno != EINTR) {
                ALOGW("poll failed (errno=%d)\n", errno);
                usleep(100000);
            }
        } else {
            // Some events occurred.
            mPendingEventCount = size_t(pollResult);
        }
    }

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

从上面的代码可以看到调用了epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis);方法,代码会在这里等待输入事件。而且线程大部分时间都是在epoll_wait上等待。当有输入数据之后,唤醒线程,pollResult大于0,代码进入下个for循环。当有数据时for循环中的while (mPendingEventIndex < mPendingEventCount) 循环开始执行。其中int32_t readSize = read(device->fd, readBuffer, sizeof(struct input_event) * capacity); 读取数据到readBuffer中。之后将数据转换成RawEvent对象,该对象在EventHub的getEvents方法的第2个参数中传入。信息读取结束后,退出while 循环,然后判断event != buffer 退出for循环,这时getEvents函数返回。从getEvents方法返回到loopOnce后,代码继续往下执行。当返回的count大于0,则执行processEventsLocked(mEventBuffer, count);方法来处理获取到的RawEvent对象。 消息获取结束后,就需要处理它们了。 下面我们看看消息的处理分发

消息的处理

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;
            while (batchSize < count) {
                if (rawEvent[batchSize].type >= EventHubInterface::FIRST_SYNTHETIC_EVENT
                        || rawEvent[batchSize].deviceId != deviceId) {
                    break;
                }
                batchSize += 1;
            }
#if DEBUG_RAW_EVENTS
            ALOGD("BatchSize: %zu Count: %zu", batchSize, count);
#endif
            processEventsForDeviceLocked(deviceId, rawEvent, batchSize);
        } else {
            switch (rawEvent->type) {
            case EventHubInterface::DEVICE_ADDED:
                addDeviceLocked(rawEvent->when, rawEvent->deviceId);
                break;
            case EventHubInterface::DEVICE_REMOVED:
                removeDeviceLocked(rawEvent->when, rawEvent->deviceId);
                break;
            case EventHubInterface::FINISHED_DEVICE_SCAN:
                handleConfigurationChangedLocked(rawEvent->when);
                break;
            default:
                ALOG_ASSERT(false); // can't happen
                break;
            }
        }
        count -= batchSize;
        rawEvent += batchSize;
    }
}

void InputReader::processEventsForDeviceLocked(int32_t deviceId,
        const RawEvent* rawEvents, size_t count) {
    ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
    if (deviceIndex < 0) {
        ALOGW("Discarding event for unknown deviceId %d.", deviceId);
        return;
    }

    InputDevice* device = mDevices.valueAt(deviceIndex);
    if (device->isIgnored()) {
        //ALOGD("Discarding event for ignored deviceId %d.", deviceId);
        return;
    }

    device->process(rawEvents, count);
}


processEventsLocked处理RawEvent分为2类。 1.设备发生变化的Event,包含添加,移除设备和扫描设备结束3种情况。对添加,移除设备Event处理,只需增加和删除mDevices列表中Device对象即可。扫描设备结束Event还需要调用handleConfigurationChangedLocked处理设备的配置文件。 2.设备自身产生的Event,如键盘的按键Event。从RawEvent数组中取出连续的同类Event,通过processEventsForDeviceLocked函数一起处理。processEventsForDeviceLocked根据deviceId得到InputDevice对象,然后调用它的process()函数

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 DEBUG_RAW_EVENTS
        ALOGD("Input event: device=%d type=0x%04x code=0x%04x value=0x%08x when=%" PRId64,
                rawEvent->deviceId, rawEvent->type, rawEvent->code, rawEvent->value,
                rawEvent->when);
#endif

        if (mDropUntilNextSync) {
            if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
                mDropUntilNextSync = false;
#if DEBUG_RAW_EVENTS
                ALOGD("Recovered from input event buffer overrun.");
#endif
            } else {
#if DEBUG_RAW_EVENTS
                ALOGD("Dropped input event while waiting for next input sync.");
#endif
            }
        } else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_DROPPED) {
            ALOGI("Detected input event buffer overrun for device %s.", getName().c_str());
            mDropUntilNextSync = true;
            reset(rawEvent->when);
        } else {
            for (InputMapper* mapper : mMappers) {
                mapper->process(rawEvent);
            }
        }
        --count;
    }
}

InputDevice::process 函数中又调用了InputDevice中保存的所有InputMapper对象的process函数来处理RawEvent。InputMapper对象是在创建InputDevice时,根据Device类的device->classes值创建的。 InputMapper具体类型如:KeyboardInputMapper,CursorInputMapper,SingleTouchInputMapper,JoystickInputMapper等。 以KeyboardInputMapper为例:

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);
        }
        break;
    }
    case EV_MSC: {
        if (rawEvent->code == MSC_SCAN) {
            mCurrentHidUsage = rawEvent->value;
        }
        break;
    }
    case EV_SYN: {
        if (rawEvent->code == SYN_REPORT) {
            mCurrentHidUsage = 0;
        }
    }
    }
}

void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t scanCode,
        int32_t usageCode) {
	
	...

    NotifyKeyArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource,
            getDisplayId(), policyFlags, down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
            AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, keyMetaState, downTime);
    getListener()->notifyKey(&args);
}

如果是按键消息KeyboardInputMapper::process调用processKey函数处理。processKey()函数的主要工作是把扫描码转换成键盘码,然后调用getListener()函数得到InputListenerInterface的指针,最后调用它的notifyKey()函数。这个InputListenerInterface指针实际指向的是QueuedlnputListener对象,它是在InputReader的构造函数中创建出来的,如下所示:

InputReader::InputReader(const sp<EventHubInterface>& eventHub,
        const sp<InputReaderPolicyInterface>& policy,
        const sp<InputListenerInterface>& listener) :
        mContext(this), mEventHub(eventHub), mPolicy(policy),
        mNextSequenceNum(1), mGlobalMetaState(0), mGeneration(1),
        mDisableVirtualKeysTimeout(LLONG_MIN), mNextTimeout(LLONG_MAX),
        mConfigurationChangesToRefresh(0) {
    mQueuedListener = new QueuedInputListener(listener);

    { // acquire lock
        AutoMutex _l(mLock);

        refreshConfigurationLocked(0);
        updateGlobalMetaStateLocked();
    } // release lock
}

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

QueuedInputListener的参数listener是在创建InputReader时传入的,即为InputClassifier。QueuedInputListener.notifyKey()只是把args参数放到了mArgsQueue集合中。 我们再回到InputRead的LoopOnce()函数,看看最后这个函数调用了mQueuedListener->flush()函数:

void QueuedInputListener::flush() {
    size_t count = mArgsQueue.size();
    for (size_t i = 0; i < count; i++) {
        NotifyArgs* args = mArgsQueue[i];
        args->notify(mInnerListener);
        delete args;
    }
    mArgsQueue.clear();
}

QueuedInputListener::flush将mArgsQueue中的数据一一取出,并调用每个元素的notify方法,元素的类型是NotifyArgs。NotifyArgs是基类,KeyboardInputMapper中,实际的对象类型是NotifyKeyArgs。notify函数的参数mInnerListener mInnerListener,即为创建QueuedInputListener传入的值的InputClassifier对象。

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


void InputClassifier::notifyKey(const NotifyKeyArgs* args) {
    // pass through
    mListener->notifyKey(args);
}

在NotifyKeyArgs::notify中直接调用了listener的notifyKey函数,listener即InputClassifier对象。而InputClassifier的notifyKey又调用了mListener->notifyKey函数。mListener即为创建InputClassifier时传入的。在最开始的初始化代码中我们已经看到这个mListener即是InputDispatcher。所以mListener->notifyKey即是InputDispatcher的notifyKey方法:

void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {
#if DEBUG_INBOUND_EVENT_DETAILS
    ALOGD("notifyKey - eventTime=%" PRId64
            ", deviceId=%d, source=0x%x, displayId=%" PRId32 "policyFlags=0x%x, action=0x%x, "
            "flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, downTime=%" PRId64,
            args->eventTime, args->deviceId, args->source, args->displayId, args->policyFlags,
            args->action, args->flags, args->keyCode, args->scanCode,
            args->metaState, args->downTime);
#endif
    if (!validateKeyEvent(args->action)) {
        return;
    }

    uint32_t policyFlags = args->policyFlags;
    int32_t flags = args->flags;
    int32_t metaState = args->metaState;
    // InputDispatcher tracks and generates key repeats on behalf of
    // whatever notifies it, so repeatCount should always be set to 0
    constexpr int32_t repeatCount = 0;
    if ((policyFlags & POLICY_FLAG_VIRTUAL) || (flags & AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY)) {
        policyFlags |= POLICY_FLAG_VIRTUAL;
        flags |= AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY;
    }
    if (policyFlags & POLICY_FLAG_FUNCTION) {
        metaState |= AMETA_FUNCTION_ON;
    }

    policyFlags |= POLICY_FLAG_TRUSTED;

    int32_t keyCode = args->keyCode;
    accelerateMetaShortcuts(args->deviceId, args->action, keyCode, metaState);

    KeyEvent event;
    event.initialize(args->deviceId, args->source, args->displayId, args->action,
            flags, keyCode, args->scanCode, metaState, repeatCount,
            args->downTime, args->eventTime);

    android::base::Timer t;
    mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags);
    if (t.duration() > SLOW_INTERCEPTION_THRESHOLD) {
        ALOGW("Excessive delay in interceptKeyBeforeQueueing; took %s ms",
                std::to_string(t.duration().count()).c_str());
    }

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

        if (shouldSendKeyToInputFilterLocked(args)) {
            mLock.unlock();

            policyFlags |= POLICY_FLAG_FILTERED;
            if (!mPolicy->filterInputEvent(&event, policyFlags)) {
                return; // event was consumed by the filter
            }

            mLock.lock();
        }

        KeyEntry* newEntry = new KeyEntry(args->sequenceNum, args->eventTime,
                args->deviceId, args->source, args->displayId, policyFlags,
                args->action, flags, keyCode, args->scanCode,
                metaState, repeatCount, args->downTime);

        needWake = enqueueInboundEventLocked(newEntry);
        mLock.unlock();
    } // release lock

    if (needWake) {
        mLooper->wake();
    }
}



bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {
    bool needWake = mInboundQueue.isEmpty();
    mInboundQueue.enqueueAtTail(entry);
    ...
}

在这个方法中,使用参数创建KeyEntry实例,然后传入enqueueInboundEventLocked函数中,在这个函数中将传入的对象加入到mInboundQueue队列里面。消息在这个队列里面等待分发, 最后调用mLooper->wake()唤醒分发线程。消息是如何被分发出去的?看看下面的过程

消息分发

在上面服务初始化部分,我们看到当InputManager::start()不仅启动了InputReaderThread,同时也调用了InputDispatcherThread的run函数,启动了InputDispatcherThread线程,最终InputDispatcherThread的threadLoop被调用,如下:

// --- InputDispatcherThread ---

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

InputDispatcherThread::~InputDispatcherThread() {
}

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

InputDispatcherThread::threadLoop调用mDispatcher->dispatchOnce(),回到上面服务的初始化过程可以看到mDispatcher即是InputDispatcherThread创建时传入的InputDispatcher对象。InputDispatcher的dispatchOnce代码如下:

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

        // Run a dispatch loop if there are no pending commands.
        // The dispatch loop might enqueue commands to run afterwards.
        if (!haveCommandsLocked()) {
            dispatchOnceInnerLocked(&nextWakeupTime);
        }

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

    // Wait for callback or timeout or wake.  (make sure we round up, not down)
    nsecs_t currentTime = now();
    int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime);
    mLooper->pollOnce(timeoutMillis);
}



void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {

	...

    mPendingEvent = mInboundQueue.dequeueAtHead();

    switch (mPendingEvent->type) {
	
	...

    case EventEntry::TYPE_KEY: {
        KeyEntry* typedEntry = static_cast<KeyEntry*>(mPendingEvent);
        if (isAppSwitchDue) {
            if (isAppSwitchKeyEvent(typedEntry)) {
                resetPendingAppSwitchLocked(true);
                isAppSwitchDue = false;
            } else if (dropReason == DROP_REASON_NOT_DROPPED) {
                dropReason = DROP_REASON_APP_SWITCH;
            }
        }
        if (dropReason == DROP_REASON_NOT_DROPPED
                && isStaleEvent(currentTime, typedEntry)) {
            dropReason = DROP_REASON_STALE;
        }
        if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) {
            dropReason = DROP_REASON_BLOCKED;
        }
        done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);
        break;
    }

	...
}

dispatchOnce函数中,如果haveCommandsLocked()返回false 即mCommandQueue队列不为NULL,则调用dispatchOnceInnerLocked()函数分发消息。dispatchOnceInnerLocked()函数先从mInboundQueue.dequeueAtHead()中取出消息,如果类型是EventEntry::TYPE_KEY,则调用dispatchKeyLocked()函数继续处理。 dispatchKeyLocked经过层层调用最终调用到startDispatchCycleLocked函数。

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

	...
	
	 switch (eventEntry->type) {
        case EventEntry::TYPE_KEY: {
            KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry);

            // Publish the key event.
            status = connection->inputPublisher.publishKeyEvent(dispatchEntry->seq,
                    keyEntry->deviceId, keyEntry->source, keyEntry->displayId,
                    dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags,
                    keyEntry->keyCode, keyEntry->scanCode,
                    keyEntry->metaState, keyEntry->repeatCount, keyEntry->downTime,
                    keyEntry->eventTime);
            break;
        }
	
	...

}

最终通过connection->inputPublisher.publishKeyEvent将消息分发出去。 connection是什么?先看看在InputManagerService中有个registerInputChannel()方法:

    /**
     * Registers an input channel so that it can be used as an input event target.
     * @param inputChannel The input channel to register.
     * @param inputWindowHandle The handle of the input window associated with the
     * input channel, or null if none.
     */
    public void registerInputChannel(InputChannel inputChannel, IBinder token) {
        if (inputChannel == null) {
            throw new IllegalArgumentException("inputChannel must not be null.");
        }

        if (token == null) {
            token = new Binder();
        }
        inputChannel.setToken(token);

        nativeRegisterInputChannel(mPtr, inputChannel, Display.INVALID_DISPLAY);
    }

//nativeRegisterInputChannel在native层的代码

static void nativeRegisterInputChannel(JNIEnv* env, jclass /* clazz */,
        jlong ptr, jobject inputChannelObj, jint displayId) {
    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);

    sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,
            inputChannelObj);
    if (inputChannel == nullptr) {
        throwInputChannelNotInitialized(env);
        return;
    }

    status_t status = im->registerInputChannel(env, inputChannel, displayId);

    if (status) {
        std::string message;
        message += StringPrintf("Failed to register input channel.  status=%d", status);
        jniThrowRuntimeException(env, message.c_str());
        return;
    }

    android_view_InputChannel_setDisposeCallback(env, inputChannelObj,
            handleInputChannelDisposed, im);
}

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

//InputDispatcher类的registerInputChannel函数
status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel,
        int32_t displayId) {
#if DEBUG_REGISTRATION
    ALOGD("channel '%s' ~ registerInputChannel - displayId=%" PRId32,
            inputChannel->getName().c_str(), displayId);
#endif

    { // acquire lock
        std::scoped_lock _l(mLock);

        if (getConnectionIndexLocked(inputChannel) >= 0) {
            ALOGW("Attempted to register already registered input channel '%s'",
                    inputChannel->getName().c_str());
            return BAD_VALUE;
        }

        sp<Connection> connection = new Connection(inputChannel, false /*monitor*/);

        int fd = inputChannel->getFd();
        mConnectionsByFd.add(fd, connection);
        mInputChannelsByToken[inputChannel->getToken()] = inputChannel;

        mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
    } // release lock

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

上面的代码可以看到InputManagerService的registerInputChannel方法调用了native层方法nativeRegisterInputChannel函数。 在nativeRegisterInputChannel函数中调用了NativeInputManager的registerInputChannel函数,并将native层的InputChannel对象作为参数出入其中。native层的InputChannel对象,是根据java层的InputChannel生成的。 NativeInputManager的registerInputChannel函数调用mInputManager->getDispatcher()->registerInputChannel(inputChannel, displayId);函数。这个getDispatcher()获取的就是InputDispatcher对象。所以最后调用的是InputDispatcher类的registerInputChannel函数。 在InputDispatcher类的registerInputChannel函数中,创建了Connection对象,并将Connection对象加入到mConnectionsByFd队列中。然后inputChannel的句柄fd加入到Looper对象的epoll检测中。 mConnectionsByFd存在多个Connection,那么前面分发输入的消息使用的connection->inputPublisher.publishKeyEvent是哪个Connection对象? InputDispatcher::dispatchKeyLocked()函数会调用findFocusedWindowTargetsLocked函数得到当前拥有焦点的窗口的inputChannel信息,然后调用getConnectionIndexLocked函数得到mConnectionsByFd中inputChannel关联的Connection对象的index。

ssize_t InputDispatcher::getConnectionIndexLocked(const sp<InputChannel>& inputChannel) {
    if (inputChannel == nullptr) {
        return -1;
    }

    for (size_t i = 0; i < mConnectionsByFd.size(); i++) {
        sp<Connection> connection = mConnectionsByFd.valueAt(i);
        if (connection->inputChannel->getToken() == inputChannel->getToken()) {
            return i;
        }
    }

    return -1;
}

//
void InputDispatcher::dispatchEventLocked(nsecs_t currentTime,
        EventEntry* eventEntry, const std::vector<InputTarget>& inputTargets) {
    ATRACE_CALL();
#if DEBUG_DISPATCH_CYCLE
    ALOGD("dispatchEventToCurrentInputTargets");
#endif

    ALOG_ASSERT(eventEntry->dispatchInProgress); // should already have been set to true

    pokeUserActivityLocked(eventEntry);

    for (const InputTarget& inputTarget : inputTargets) {
        ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel);
        if (connectionIndex >= 0) {
            sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
            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());
#endif
        }
    }
}

getConnectionIndexLocked函数通过与inputChannel相同的token信息获取对应的Connection对象的inex。InputDispatcher::dispatchEventLocked函数中,获取到connectionIndex后,通过mConnectionsByFd.valueAt(connectionIndex)获取对应的Connection对象,传入prepareDispatchCycleLocked函数。 最终传给startDispatchCycleLocked函数,在这个函数中使用connection->inputPublisher.publishKeyEvent来分发消息。 再来看看inputPublisher.publishKeyEvent函数:

status_t InputPublisher::publishKeyEvent(
        uint32_t seq,
        int32_t deviceId,
        int32_t source,
        int32_t displayId,
        int32_t action,
        int32_t flags,
        int32_t keyCode,
        int32_t scanCode,
        int32_t metaState,
        int32_t repeatCount,
        nsecs_t downTime,
        nsecs_t eventTime) {
    if (ATRACE_ENABLED()) {
        std::string message = StringPrintf("publishKeyEvent(inputChannel=%s, keyCode=%" PRId32 ")",
                mChannel->getName().c_str(), keyCode);
        ATRACE_NAME(message.c_str());
    }
#if DEBUG_TRANSPORT_ACTIONS
    ALOGD("channel '%s' publisher ~ publishKeyEvent: seq=%u, deviceId=%d, source=0x%x, "
            "action=0x%x, flags=0x%x, keyCode=%d, scanCode=%d, metaState=0x%x, repeatCount=%d,"
            "downTime=%" PRId64 ", eventTime=%" PRId64,
            mChannel->getName().c_str(), seq,
            deviceId, source, action, flags, keyCode, scanCode, metaState, repeatCount,
            downTime, eventTime);
#endif

    if (!seq) {
        ALOGE("Attempted to publish a key event with sequence number 0.");
        return BAD_VALUE;
    }

    InputMessage msg;
    msg.header.type = InputMessage::TYPE_KEY;
    msg.body.key.seq = seq;
    msg.body.key.deviceId = deviceId;
    msg.body.key.source = source;
    msg.body.key.displayId = displayId;
    msg.body.key.action = action;
    msg.body.key.flags = flags;
    msg.body.key.keyCode = keyCode;
    msg.body.key.scanCode = scanCode;
    msg.body.key.metaState = metaState;
    msg.body.key.repeatCount = repeatCount;
    msg.body.key.downTime = downTime;
    msg.body.key.eventTime = eventTime;
    return mChannel->sendMessage(&msg);
}

该函数中通过mChannel->sendMessage(&msg);将信息分发出去。mChannel即使创建Connection时传入的InputChannel对象。

总结

这个流程涉及的类较多,过程比较复杂,下面做一些简单的总结

主要过程流程图

输入消息分发过程.jpg 初始化调用过程

Android 输入管理---初始化.jpg 信息读取和处理过程

Android 输入管理---信息读取和处理.jpg 信息分发过程

Android 输入管理---消息分发.jpg

源码路径:

源码基于android 10.0

SystemServer: /frameworks/base/services/java/com/android/server/SystemServer.java

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

NativeInputManager:此类在com_android_server_input_InputManagerService文件中定义

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

InputManager.cpp: /frameworks/native/services/inputflinger/InputManager.cpp

InputReaderFactory.cpp:/frameworks/native/services/inputflinger/InputReaderFactory.cpp

InputReaderThread:此类是在InputReaderBase类中定义。

InputReaderBase:/frameworks/native/services/inputflinger/InputReaderBase.cpp

InputDevice: 此类在InputReader文件中定义

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

KeyboardInputMapper:此类在InputReader中定义

QueuedInputListener:此类在InputListener文件中定义

NotifyKeyArgs: 此类在InputListener中定义

InputListener:/frameworks/native/services/inputflinger/InputListener.cpp

Connection: 此类在InputDispatcher中定义

InputDispatcherThread: 此类在InputDispatcher中定义

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

InputPublisher: 此类在InputTransport中定义

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

本文如有错误,欢迎留言指正。

下一篇: <<Android输入管理2:应用进程处理Input消息过程>>