Links to related articles:

1. Android Framework – Learning Launcher

2. Android FrameWork – Start the SystemServer process

Related source files:

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

/frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
/frameworks/native/services/inputflinger/InputDispatcher.cpp
/frameworks/native/services/inputflinger/InputReader.cpp
/frameworks/native/services/inputflinger/InputManager.cpp
/frameworks/native/services/inputflinger/EventHub.cpp
Copy the code

1. Summarize

For Android upper event distribution process, we should be more familiar with, because this is a knowledge point of custom View, but also a few years ago interview often asked a question. But knowing the upper-level event distribution process may not be enough, because much advanced functionality development relies on low-level knowledge. We all know that events are passed to the dispatchTouchEvent method of the Activity root layout View, so have we thought about where the event originated? Where exactly did this incident originate from?

In the Linux kernel system, everything is a file, so we only need to listen to the change of the /dev/input driver file to read the event; So Android has an InputReader for reading Input events and an InputDispatcher for distributing Input events.

2. Start the IMS

/** * Starts a miscellaneous grab bag of stuff that has yet to be refactored * and organized. */ private void startOtherServices() { final Context context = mSystemContext; . // Create InputManagerService InputManagerService inputManager = new InputManagerService(context); / / create WindowManagerService wm = WindowManagerService. Main (context, inputManager mFactoryTestMode! = FactoryTest.FACTORY_TEST_LOW_LEVEL, ! mFirstBoot, mOnlyCore); / / registration system services ServiceManager. The addService (Context. WINDOW_SERVICE, wm); ServiceManager.addService(Context.INPUT_SERVICE, inputManager); / / set up the management of the callback inputManager. SetWindowManagerCallbacks (wm) getInputMonitor ()); inputManager.start(); } public InputManagerService(Context context) { this.mContext = context; // Create InputManagerHandler this.mHandler = new InputManagerHandler(displayThread.get ().getLooper()); . // Native layer initialization, which uses handler's looper communication mechanism, Handler can also communicate across processes mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue()); } static jlong nativeInit(JNIEnv* env, jclass /* clazz */, jobject serviceObj, jobject contextObj, Jobject messageQueueObj) {sp<MessageQueue> MessageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj); if (messageQueue == NULL) { jniThrowRuntimeException(env, "MessageQueue is not initialized."); return 0; } // Create native layer NativeInputManager NativeInputManager* im = new NativeInputManager(contextObj, serviceObj, messageQueue->getLooper()); return reinterpret_cast<jlong>(im); } NativeInputManager::NativeInputManager(jobject contextObj, jobject serviceObj, const sp<Looper>& looper) : mLooper(looper), mInteractive(true) { ... // create EventHub with InputManager sp<EventHub> EventHub = new EventHub(); mInputManager = new InputManager(eventHub, this, this); } InputManager::InputManager( const sp<EventHubInterface>& eventHub, const sp<InputReaderPolicyInterface>& readerPolicy, Const sp < InputDispatcherPolicyInterface > & dispatcherPolicy) {/ / create InputDispatcher with InputReader mDispatcher = new InputDispatcher(dispatcherPolicy); mReader = new InputReader(eventHub, readerPolicy, mDispatcher); initialize(); } void InputManager::initialize() {// Create InputDispatcher and InputReader threads mReaderThread = new InputReaderThread(mReader); mDispatcherThread = new InputDispatcherThread(mDispatcher); } status_t InputManager::start() {// Start InputDispatcher and InputReader threads respectively status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY); . result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY); . return OK; }Copy the code

In the SystemServer process, InputManagerService creates the NativeInputManager object of the native layer during object construction. In NativeInputManager, EventHub and InputManager objects are constructed. Finally, InputManager creates and starts InputDispatcher and InputReader threads, respectively.

2. Read the Input event

EventHub::EventHub(void) : mBuiltInKeyboardId(NO_BUILT_IN_KEYBOARD), mNextDeviceId(1), mControllerNumbers(), mOpeningDevices(0), mClosingDevices(0), mNeedToSendFinishedDeviceScan(false), mNeedToReopenDevices(false), mNeedToScanDevices(true), mPendingEventCount(0), mPendingEventIndex(0), mPendingINotify(false) { acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID); Epollfd = epoll_create(EPOLL_SIZE_HINT); mINotifyFd = inotify_init(); // where DEVICE_PATH is "/dev/input", this code is in the driver layer, Interested in people with the int result = inotify_add_watch (mINotifyFd DEVICE_PATH, IN_DELETE | IN_CREATE); struct epoll_event eventItem; memset(&eventItem, 0, sizeof(eventItem)); eventItem.events = EPOLLIN; eventItem.data.u32 = EPOLL_ID_INOTIFY; // Add INotify to epoll instance result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem); int wakeFds[2]; result = pipe(wakeFds); MWakeReadPipeFd = wakeFds[0]; mWakeWritePipeFd = wakeFds[1]; Result = FCNTL (mWakeReadPipeFd, F_SETFL, O_NONBLOCK); result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK); eventItem.data.u32 = EPOLL_ID_WAKE; // Add the read end of the pipe to the epoll instance result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, &eventItem); . } InputReader::InputReader(const sp<EventHubInterface>& eventHub, const sp<InputReaderPolicyInterface>& policy, const sp<InputListenerInterface>& listener) : mContext(this), mEventHub(eventHub), mPolicy(policy), mGlobalMetaState(0), mGeneration(1), mDisableVirtualKeysTimeout(LLONG_MIN), mNextTimeout(LLONG_MAX), MConfigurationChangesToRefresh (0) {/ / create input is monitored object QueuedInputListener InputDispatcher mQueuedListener = new QueuedInputListener(listener); . } void InputReader::loopOnce() { int32_t oldGeneration; int32_t timeoutMillis; . // Get Events from mEventHub, EVENT_BUFFER_SIZE = 256 size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE); { // acquire lock AutoMutex _l(mLock); mReaderIsAliveCondition.broadcast(); // Process the event if (count) {processEventsLocked(mEventBuffer, count); }... } // release lock // send events to InputDispatcher mQueuedListener-> Flush (); } size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) { struct input_event readBuffer[bufferSize]; // RawEvent* event = buffer; Size_t capacity = bufferSize; for (;;) { nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); . if (mNeedToScanDevices) { mNeedToScanDevices = false; // Scan devices scanDevicesLocked(); mNeedToSendFinishedDeviceScan = true; } // Grab the next input event. bool deviceChanged = false; while (mPendingEventIndex < mPendingEventCount) { const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++]; // Continuously read events from the device, Put the input_event information into readBuffer // get the readBuffer data, Int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis); } // Return event-buffer; } 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; } / / real distributed event processEventsForDeviceLocked (deviceId rawEvent, batchSize); } else {/ / add device types are: access to the keyboard source type, the keyboard class device type, the mouse class device type, touch screen device type switch (rawEvent - > type) {case EventHubInterface: : DEVICE_ADDED: addDeviceLocked(rawEvent->when, rawEvent->deviceId); break; . } } count -= batchSize; rawEvent += batchSize; } } void InputReader::processEventsForDeviceLocked(int32_t deviceId, const RawEvent* rawEvents, Ssize_t deviceIndex = mdevices.indexofKey (deviceId); InputDevice* device = mDevices.valueAt(deviceIndex); device->process(rawEvents, count); } void TouchInputMapper::dispatchMotion(nsecs_t when, 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) { ... InputDispatcher NotifyMotionArgs (when, getDeviceId(), source, policyFlags, action, actionButton, flags, metaState, buttonState, edgeFlags, mViewport.displayId, pointerCount, pointerProperties, pointerCoords, xPrecision, yPrecision, downTime); getListener()->notifyMotion(&args); }Copy the code

After the InputReader thread is started, it will continuously read the event information through EventHub, then parse and encapsulate the event information into different objects, and finally notify InputDispatcher by way of back. The following device types are added: keyboard device type, mouse device type, and touchscreen device type.

3. Input Event distribution

  InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy) :
    mPolicy(policy),
    mPendingEvent(NULL), mLastDropReason(DROP_REASON_NOT_DROPPED),
    mAppSwitchSawKeyDown(false), mAppSwitchDueTime(LONG_LONG_MAX),
    mNextUnblockedEvent(NULL),
    mDispatchEnabled(false), mDispatchFrozen(false), mInputFilterEnabled(false),
    mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE) {
    // 创建 Looper 对象
    mLooper = new Looper(false);
    // 获取分发超时参数
    policy->getDispatcherConfiguration(&mConfig);
  }

  void InputDispatcher::dispatchOnce() {
    nsecs_t nextWakeupTime = LONG_LONG_MAX;
    {
        AutoMutex _l(mLock);
        // 唤醒等待线程,monitor() 用于监控 dispatcher 是否发生死锁
        mDispatcherIsAliveCondition.broadcast();

        if (!haveCommandsLocked()) {
            // 当 mCommandQueue 不为空时处理
            dispatchOnceInnerLocked(&nextWakeupTime);
        }

        if (runCommandsLockedInterruptible()) {
            nextWakeupTime = LONG_LONG_MIN;
        }
    }

    nsecs_t currentTime = now();
    int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime);
    // 进入等待,需要调用 mLooper.wake 方法来唤醒
    mLooper->pollOnce(timeoutMillis);  
  }

  void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
    ...
    if (! mPendingEvent) {
        if (mInboundQueue.isEmpty()) {
            // Nothing to do if there is no pending event.
            if (!mPendingEvent) {
                // 没有事件需要处理直接返回
                return;
            }
        } else {
            // Inbound queue has at least one entry.
            mPendingEvent = mInboundQueue.dequeueAtHead();
            traceInboundQueueLengthLocked();
        }
    }
    switch (mPendingEvent->type) {
      ...
      case EventEntry::TYPE_KEY: {
          ...
          // 分发 key 事件
          done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);
          break;
      }

      case EventEntry::TYPE_MOTION: {
        // 分发触摸事件
        done = dispatchMotionLocked(currentTime, typedEntry,
                &dropReason, nextWakeupTime);
        break;
      }
    }
    ...
  }

  bool InputDispatcher::dispatchMotionLocked(
        nsecs_t currentTime, MotionEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) {
    ...
    if (isPointerEvent) {
        // Pointer event.  (eg. touchscreen)
        injectionResult = findTouchedWindowTargetsLocked(currentTime,
                entry, inputTargets, nextWakeupTime, &conflictingPointerActions);
    } else {
        // Non touch event.  (eg. trackball)
        injectionResult = findFocusedWindowTargetsLocked(currentTime,
                entry, inputTargets, nextWakeupTime);
    }
    if (injectionResult == INPUT_EVENT_INJECTION_PENDING) {
        return false;
    }

    // 最后开始分发
    dispatchEventLocked(currentTime, entry, inputTargets);
    return true;
  }

  int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
        const MotionEntry* entry, Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime,
        bool* outConflictingPointerActions) {

    if (newGesture || (isSplit && maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN)) {
        // 遍历所有的 mWindowHandles
        size_t numWindows = mWindowHandles.size();
        for (size_t i = 0; i < numWindows; i++) {
            sp<InputWindowHandle> windowHandle = mWindowHandles.itemAt(i);
            const InputWindowInfo* windowInfo = windowHandle->getInfo();
            if (windowInfo->displayId != displayId) {
                continue; // wrong display
            }
            int32_t flags = windowInfo->layoutParamsFlags;
            if (windowInfo->visible) {
                // 可见,并且 flags 属性不是 InputWindowInfo::FLAG_NOT_TOUCHABLE
                if (! (flags & InputWindowInfo::FLAG_NOT_TOUCHABLE)) {
                    isTouchModal = (flags & (InputWindowInfo::FLAG_NOT_FOCUSABLE
                            | InputWindowInfo::FLAG_NOT_TOUCH_MODAL)) == 0;
                    // 点击的是不是当前 window 的覆盖
                    if (isTouchModal || windowInfo->touchableRegionContainsPoint(x, y)) {
                        // found touched window, exit window loop
                        // 找到了当前触摸的 window 
                        newTouchedWindowHandle = windowHandle;
                        break;
                    }
                }
            }
        } 
        
        mTempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds);
    } else {
       ...
    }
    // 再把 mTempTouchState 收集到的 windows 添加到 inputTargets 中
    for (size_t i = 0; i < mTempTouchState.windows.size(); i++) {
        const TouchedWindow& touchedWindow = mTempTouchState.windows.itemAt(i);
        addWindowTargetLocked(touchedWindow.windowHandle, touchedWindow.targetFlags,
                touchedWindow.pointerIds, inputTargets);
    }
    ...
    return injectionResult;
  }

  void InputDispatcher::dispatchEventLocked(nsecs_t currentTime,
        EventEntry* eventEntry, const Vector<InputTarget>& inputTargets) {
    for (size_t i = 0; i < inputTargets.size(); i++) {
        const InputTarget& inputTarget = inputTargets.itemAt(i);
        // 根据 inputChannel 的 fd 从 mConnectionsByFd 队列中查询目标 connection.
        ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel);
        if (connectionIndex >= 0) {
            // 找到目标连接
            sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
            // 准备分发事件出去了
            prepareDispatchCycleLocked(currentTime, connection, eventEntry, &inputTarget);
        } else {
          ...
        }
    }
  }

  void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime,
        const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) {
    bool wasEmpty = connection->outboundQueue.isEmpty();

    // Enqueue dispatch entries for the requested modes.
    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.isEmpty()) {
        startDispatchCycleLocked(currentTime, connection);
    }
  }

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

    while (connection->status == Connection::STATUS_NORMAL
            && !connection->outboundQueue.isEmpty()) {
        ...
        switch (eventEntry->type) {
        case EventEntry::TYPE_KEY: {
            ...
            break;
        }

        case EventEntry::TYPE_MOTION: {
            MotionEntry* motionEntry = static_cast<MotionEntry*>(eventEntry);
            ...
            // 通过 connection 的 inputPublisher 发布出去了
            // Publish the motion event.
            status = connection->inputPublisher.publishMotionEvent(dispatchEntry->seq,
                    motionEntry->deviceId, motionEntry->source,
                    dispatchEntry->resolvedAction, motionEntry->actionButton,
                    dispatchEntry->resolvedFlags, motionEntry->edgeFlags,
                    motionEntry->metaState, motionEntry->buttonState,
                    xOffset, yOffset, motionEntry->xPrecision, motionEntry->yPrecision,
                    motionEntry->downTime, motionEntry->eventTime,
                    motionEntry->pointerCount, motionEntry->pointerProperties,
                    usingCoords);
            break;
        }
        ...
    }
  }
Copy the code

InputDispatcher uses Looper to wake up and wait, which is the same underlying principle as Handler analysis. After receiving the event, it will first find the target window information for distribution, then find the communication connection through the inputChannel of inputTarget, and finally publish the event through connection. Where is it sent? We need to familiarize ourselves with the subsequent Windows ManagerService source code.

Video address: pan.baidu.com/s/1vY_Vb3Aa…

Video password: 566Q