InputManagerService

InputManagerService服务创建

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

  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());
  }

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

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;
    }
    //创建NativeInputManager对象,并将对象的指针返回给Java层
    NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
            messageQueue->getLooper());
    im->incStrong(0);
    return reinterpret_cast<jlong>(im);
}

NativeInputManager实现了接口InputReaderPolicyInterface ,InputDispatcherPolicyInterface。继续看其构造函数

NativeInputManager::NativeInputManager(jobject contextObj,
        jobject serviceObj, const sp<Looper>& looper) :
        mLooper(looper), mInteractive(true) {
    ... ...
    //创建了EventHub对象和InputManager对象
    sp<EventHub> eventHub = new EventHub();
    mInputManager = new InputManager(eventHub, this, this);
}

EventHub用于监听和读取设备节点信息,InputManager构造方法如下

InputManager::InputManager(
        const sp<EventHubInterface>& eventHub,
        const sp<InputReaderPolicyInterface>& readerPolicy,
        const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
    //创建了InputDispatcher,InputReader对象
    mDispatcher = new InputDispatcher(dispatcherPolicy);
    mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
    initialize();
}
void InputManager::initialize() {
    //InputReaderThread,InputDispatcherThread都继承自Thread,这两个线程分别用于运行InputReader,InputDispatcher
    mReaderThread = new InputReaderThread(mReader);
    mDispatcherThread = new InputDispatcherThread(mDispatcher);
}

至此输入系统重要参与者 InputManagerService、EventHub、InputReader、InputDispatcher以及native层策略InputReaderPolicy ,InputDispatcherPolicy实现类NativeInputManager全部创建完成。

接下来继续看InputManagerService.start方法,
/frameworks/base/services/core/java/com/android/server/input/InputManagerService.java

   public void start() {
       Slog.i(TAG, "Starting input manager");
       nativeStart(mPtr);
       ... ...
   }

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

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.");
    }
}

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

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;
}

InputManagerService.start主要是开启InputReaderThread和InputDispatcherThread线程。当两个线程启动后,

InputReader在其线程循环中不断的从EventHub中抽取原始输入事件,进行加工处理后将加工所得的事件放入InputDispatcher的派发队列中。

InputDispatcher则再其线程循环中将派发队列中的事件取出,查找合适的窗口,将事件写入窗口的事件接受管道中。

窗口事件接受线程的Looper从管道中将事件取出,交由事件处理函数进行事件响应。

整个过程共有三个线程收尾相接。

输入事件读取

InputReaderThread继承Thread,实现了threadLoop方法,线程一直循环,每循环一次会调用threadLoop,

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

loopOnce 主要工作分为三个部分:

void InputReader::loopOnce() {
    ... ...
    //1. 获得原始输入事件,存入mEventBuffer
    size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);

    { // acquire lock
        AutoMutex _l(mLock);
        mReaderIsAliveCondition.broadcast();
        //2. 处理输入事件
        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);
    }
    //3.传给InputDispathcher
    // 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();
}

第一步调用EventHub.getEvents中获取原始输入事件,从驱动节点得到原始输入事件和设备信息是采用Linux内核的INotify和Epoll机制,INotify可以监听节点的删除和添加,但是不会主动上报,而Epoll机制则是在有事件上报时读取事件,其余事件处于wait状态,线程休眠,从而不至于线程一直运行.

在EventHub构造方法中完成了Epoll注册,即要监听哪些事件.

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

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) {
    ... ...
    //监听设备节点和输入事件,监听设备节点是通过添加mINotifyFd完成的
    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.u32 = EPOLL_ID_WAKE;
    //注册时添加匿名管道mWakeReadPipeFd为参数,用于因没有输入事件时,线程处于休眠状态,但是需要唤醒InputReader所运行的线程时,就往这个管道里随便写数据,线程就会被唤醒
    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);

    ... ...
}

EventHub.getEvents方法主要工作在一个无限的for循环中完成

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 (;;) {
       ... ...       
       //mPendingEventItems数组用于存储未传给InputReader的原始事件,如果不为空,则赋值给event
       while (mPendingEventIndex < mPendingEventCount) {
           const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];

           //如果是唤醒事件awoken置为true
           if (eventItem.data.u32 == EPOLL_ID_WAKE) {
               if (eventItem.events & EPOLLIN) {
                   ALOGV("awoken after wake()");
                   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;
           }


           Device* device = mDevices.valueAt(deviceIndex);
           if (eventItem.events & EPOLLIN) {
               ... ...

                       event->deviceId = deviceId;
                       event->type = iev.type;
                       event->code = iev.code;
                       event->value = iev.value;
                       event += 1;
                       capacity -= 1;
      
               }
           } else if (eventItem.events & EPOLLHUP) {
               ALOGI("Removing device %s due to epoll hang-up event.",
                       device->identifier.name.string());
               deviceChanged = true;
               closeDeviceLocked(device);
           } else {
               ALOGW("Received unexpected epoll event 0x%08x for device %s.",
                       eventItem.events, device->identifier.name.string());
           }
       }

       ... ...
       //如果有未传输事件或者唤醒线程事件则直接跳出循环,将事件返回给InputReader
       // Return now if we have collected any events or if we were explicitly awoken.
       if (event != buffer || awoken) {
           break;
       }

       ... ...
        //如果没有待传输事件,则进入epoll_wait,线程休眠,等待事件,事件来到后,再次进入循环取出事件
        int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis);


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

}

所以InputReaderThread读取事件的操作实际上就是不停的循环调用EventHub.getEvents,而EventHub.getEvents里面的无限循环,则是在有待传输事件时跳出直接返回给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;
            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);
}

这里调用InputDevice.process做进一步处理

/frameworks/native/services/inputflinger/InputReader.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.
    size_t numMappers = mMappers.size();
    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().string());
            mDropUntilNextSync = true;
            reset(rawEvent->when);
        } else {
            //遍历所有InputMapper,交由InputMapper.process处理
            for (size_t i = 0; i < numMappers; i++) {
                InputMapper* mapper = mMappers[i];
                mapper->process(rawEvent);
            }
        }
        --count;
    }
}

InputDevice.process采用遍历InputMapper数组,看谁能处理当前rawEvent,比如键盘输入事件KeyboardInputMapper和SwitchInputMapper继承InputMapper并实现了process方法,采用的是工厂方法模式.

  • InputDevice: 表示一个输入设备节点,processEventsLocked 处理DEVICE_ADDED时创建.根据设备类型保存了 InputMapper数组.
  • InputMapper: 一个设备类型对应一个InputMapper对象,InputMapper根据输入事件 EV_KEY按键,EV_ABS坐标等事件去加工原始输入事件

一个设备节点可能包含多种物理输入设备,比如event0设备节点同时负责按键和触屏事件,所以这时InputDevice可能对应KeyboardInputMapper和SingleTouchInputMapper两个InputMapper.

1.键盘事件处理

KeyboardInputMapper 处理键盘输入事件, 主要是将Scancode转换为Keycode.Scancode为物理按键值,不同输入设备不一样,而Keycode为Android同意定义按键值

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

void KeyboardInputMapper::process(const RawEvent* rawEvent) {
    switch (rawEvent->type) {
    case EV_KEY: {
        //原始事件中读取scanCode
        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) {
    int32_t keyCode;
    int32_t keyMetaState;
    uint32_t policyFlags;
    //将scanCode转换为keyCode
    if (getEventHub()->mapKey(getDeviceId(), scanCode, usageCode, mMetaState,
                              &keyCode, &keyMetaState, &policyFlags)) {
        keyCode = AKEYCODE_UNKNOWN;
        keyMetaState = mMetaState;
        policyFlags = 0;
    }
    //分别对down和up事件做处理
    if (down) {
        // Rotate key codes according to orientation if needed.
        if (mParameters.orientationAware && mParameters.hasAssociatedDisplay) {
            keyCode = rotateKeyCode(keyCode, mOrientation);
        }

        // Add key down.
        ssize_t keyDownIndex = findKeyDown(scanCode);
        if (keyDownIndex >= 0) {
            // key repeat, be sure to use same keycode as before in case of rotation
            keyCode = mKeyDowns.itemAt(keyDownIndex).keyCode;
        } else {
            // key down
            if ((policyFlags & POLICY_FLAG_VIRTUAL)
                    && mContext->shouldDropVirtualKey(when,
                            getDevice(), keyCode, scanCode)) {
                return;
            }
            if (policyFlags & POLICY_FLAG_GESTURE) {
                mDevice->cancelTouch(when);
            }

            mKeyDowns.push();
            KeyDown& keyDown = mKeyDowns.editTop();
            keyDown.keyCode = keyCode;
            keyDown.scanCode = scanCode;
        }

        mDownTime = when;
    } else {
        // Remove key down.
        ssize_t keyDownIndex = findKeyDown(scanCode);
        if (keyDownIndex >= 0) {
            // key up, be sure to use same keycode as before in case of rotation
            keyCode = mKeyDowns.itemAt(keyDownIndex).keyCode;
            mKeyDowns.removeAt(size_t(keyDownIndex));
        } else {
            // key was not actually down
            ALOGI("Dropping key up from device %s because the key was not down.  "
                    "keyCode=%d, scanCode=%d",
                    getDeviceName().string(), keyCode, scanCode);
            return;
        }
    }

    ... ...
    //将结果封装为NotifyKeyArgs对象,调用getListener()->notifyKey(&args);传给InputDispatcher
    NotifyKeyArgs args(when, getDeviceId(), mSource, policyFlags,
            down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
            AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, keyMetaState, downTime);
    getListener()->notifyKey(&args);
}

2.触屏事件处理

TouchInputMapper子类分别为SingleTouchInputMapper,MultiTouchInputMapper,touch事件实现比较复杂, 跟键盘事件相比,touch事件的原始信息较多,包括点击坐标,点击区域,压力等等,所以需要多个rawEvent表示一次输入,比如一次滑动事件通过adb shell getevent 得到原始事件如下

/dev/input/event1: 0003 0039 0000c02c
/dev/input/event1: 0003 003a 00000032
/dev/input/event1: 0003 0030 00000008
/dev/input/event1: 0003 0035 00000301
/dev/input/event1: 0003 0036 00000409
/dev/input/event1: 0003 0031 00000032
/dev/input/event1: 0001 014a 00000001
/dev/input/event1: 0000 0000 00000000
/dev/input/event1: 0003 003a 00000043
/dev/input/event1: 0003 0030 0000000b
/dev/input/event1: 0003 0036 00000406
/dev/input/event1: 0003 0031 00000043
/dev/input/event1: 0000 0000 00000000
/dev/input/event1: 0003 0030 0000000a
/dev/input/event1: 0003 0035 00000303
/dev/input/event1: 0003 0036 000003ff
/dev/input/event1: 0000 0000 00000000
/dev/input/event1: 0003 0030 0000000b
/dev/input/event1: 0003 0035 00000307
/dev/input/event1: 0003 0036 000003f1
/dev/input/event1: 0000 0000 00000000
/dev/input/event1: 0003 003a 00000042
/dev/input/event1: 0003 0035 00000310
/dev/input/event1: 0003 0036 000003dc
/dev/input/event1: 0003 0031 00000042
/dev/input/event1: 0000 0000 00000000
/dev/input/event1: 0003 003a 00000043
/dev/input/event1: 0003 0035 0000031c
/dev/input/event1: 0003 0036 000003c1
/dev/input/event1: 0003 0031 00000043
/dev/input/event1: 0000 0000 00000000
/dev/input/event1: 0003 003a 00000033
/dev/input/event1: 0003 0035 0000032b
/dev/input/event1: 0003 0036 000003a6
/dev/input/event1: 0003 0031 00000033
/dev/input/event1: 0000 0000 00000000
/dev/input/event1: 0003 003a 00000043
/dev/input/event1: 0003 0035 00000337
/dev/input/event1: 0003 0036 0000038e
/dev/input/event1: 0003 0031 00000043
/dev/input/event1: 0000 0000 00000000
/dev/input/event1: 0003 0030 0000000d
/dev/input/event1: 0003 0035 00000340
/dev/input/event1: 0003 0036 0000037f
/dev/input/event1: 0000 0000 00000000
/dev/input/event1: 0003 0030 0000000b
/dev/input/event1: 0003 0036 0000037c
/dev/input/event1: 0000 0000 00000000
/dev/input/event1: 0003 0035 00000342
/dev/input/event1: 0003 0036 00000377
/dev/input/event1: 0000 0000 00000000
/dev/input/event1: 0003 0035 00000345
/dev/input/event1: 0003 0036 00000371
/dev/input/event1: 0000 0000 00000000
/dev/input/event1: 0003 0035 00000347
/dev/input/event1: 0003 0036 0000036c
/dev/input/event1: 0000 0000 00000000
/dev/input/event1: 0003 0039 ffffffff
/dev/input/event1: 0001 014a 00000000
/dev/input/event1: 0000 0000 00000000

上面type 0000是 EV_SYN,表示一个事件的结束,0003是坐标类型

# Event types
EV_SYN          = 0x00
EV_KEY          = 0x01
EV_REL          = 0x02
EV_ABS          = 0x03

touch事件处理非常复杂,这里就先记录下大概流程

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(rawEvent->when);
    }
}

TouchInputMapper只统一处理EV_SYN事件,因为一个事件由多个原始event组成,以EV_SYN标记一个事件结束,所以首先应收集一组原始事件,然后再对其进行处理

void TouchInputMapper::sync(nsecs_t when) {
    const RawState* last = mRawStatesPending.isEmpty() ?
            &mCurrentRawState : &mRawStatesPending.top();
    //1.由子类完成,收集原始事件存入mCurrentRawState
    // Sync touch
    syncTouch(when, next);

    // Assign pointer ids.
    if (!mHavePointerIds) {
        assignPointerIds(last, next);
    }
    processRawTouches(false /*timeout*/);
}

void TouchInputMapper::processRawTouches(bool timeout) {
    const size_t N = mRawStatesPending.size();
    size_t count;
    for(count = 0; count < N; count++) {
        ... ...
        //2. 加工原始事件,转换为上层需要的事件屏幕坐标系,Action Down等,存入mCurrentCookedState中
        cookAndDispatch(mCurrentRawState.when);
    }
    ... ... 
}

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, uint32_t deviceTimestamp,
        const PointerProperties* properties, const PointerCoords* coords,
        const uint32_t* idToIndex, BitSet32 idBits, int32_t changedId,
        float xPrecision, float yPrecision, nsecs_t downTime) {
    //3. 发送到InputDispatcher

    NotifyMotionArgs args(when, getDeviceId(), source, policyFlags,
            action, actionButton, flags, metaState, buttonState, edgeFlags,
            mViewport.displayId, deviceTimestamp, pointerCount, pointerProperties, pointerCoords,
            xPrecision, yPrecision, downTime);
    getListener()->notifyMotion(&args);
}

第三步,传给InputDispatcher,

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

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

void QueuedInputListener::notifyMotion(const NotifyMotionArgs* args) {
    mArgsQueue.push(new NotifyMotionArgs(*args));
}

void QueuedInputListener::notifySwitch(const NotifySwitchArgs* args) {
    mArgsQueue.push(new NotifySwitchArgs(*args));
}
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可避免InputDispatcherThread频繁被唤醒,传给InputDispatcher事件分为三种类型 notifyKey,notifyMotion,notifySwitch

EventHub.getEvents 返回一组输入事件存入mEventBuffer中, 然后调用processEventsLocked(mEventBuffer, count)遍历所有事件,加工后的事件封装成NotifyArgs放入队列 mArgsQueue中,这组输入事件全部处理完后,在调用QueuedInputListener.flush从队列 mArgsQueue中取出发送给InputDispatcher,从而避免在事件处理过程中频繁唤醒InputDispatcherThread

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

void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) {
... ...

    uint32_t policyFlags = args->policyFlags;
    policyFlags |= POLICY_FLAG_TRUSTED;
    //policyFlags是引用传递???
    android::base::Timer t;
    //是否需要被系统拦截
    mPolicy->interceptMotionBeforeQueueing(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)) {
            mLock.unlock();

            MotionEvent event;
            event.initialize(args->deviceId, args->source, args->action, args->actionButton,
                    args->flags, args->edgeFlags, args->metaState, args->buttonState,
                    0, 0, args->xPrecision, args->yPrecision,
                    args->downTime, args->eventTime,
                    args->pointerCount, args->pointerProperties, args->pointerCoords);

            policyFlags |= POLICY_FLAG_FILTERED;
            //如果被过滤掉直接返回
            if (!mPolicy->filterInputEvent(&event, policyFlags)) {
                return; // event was consumed by the filter
            }

            mLock.lock();
        }
        //将NotifyMotionArgs封装为MotionEntry,放入分发队列
        // Just enqueue a new motion event.
        MotionEntry* newEntry = new MotionEntry(args->eventTime,
                args->deviceId, args->source, policyFlags,
                args->action, args->actionButton, args->flags,
                args->metaState, args->buttonState,
                args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime,
                args->displayId,
                args->pointerCount, args->pointerProperties, args->pointerCoords, 0, 0);
        
        needWake = enqueueInboundEventLocked(newEntry);
        mLock.unlock();
    } // release lock
    //有要分发事件,唤醒分发线程InputDispatcherThread
    if (needWake) {
        mLooper->wake();
    }
}
bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {
    bool needWake = mInboundQueue.isEmpty();
    //入队
    mInboundQueue.enqueueAtTail(entry);
    traceInboundQueueLengthLocked();
    //下面是两处优化,需要立即分发事件
    switch (entry->type) {
    //1. 如果是Home/End_Call/AppSwitch 这种按键500ms后必须响应,如果在500ms内没有响应,则丢弃之前待分发事件,直接响应按键
    case EventEntry::TYPE_KEY: {
        // Optimize app switch latency.
        // If the application takes too long to catch up then we drop all events preceding
        // the app switch key.
        KeyEntry* keyEntry = static_cast<KeyEntry*>(entry);
        if (isAppSwitchKeyEventLocked(keyEntry)) {
            if (keyEntry->action == AKEY_EVENT_ACTION_DOWN) {
                mAppSwitchSawKeyDown = true;
            } else if (keyEntry->action == AKEY_EVENT_ACTION_UP) {
                if (mAppSwitchSawKeyDown) {
#if DEBUG_APP_SWITCH
                    ALOGD("App switch is pending!");
#endif
                    mAppSwitchDueTime = keyEntry->eventTime + APP_SWITCH_TIMEOUT;
                    mAppSwitchSawKeyDown = false;
                    needWake = true;
                }
            }
        }
        break;
    }
    //2. 如果当前点击窗口和正在处理事件的窗口不是一个窗口,那么将这个事件记录下来,赋给mNextUnblockedEvent,分发事件时候再做进一步处理
    case EventEntry::TYPE_MOTION: {
        // Optimize case where the current application is unresponsive and the user
        // decides to touch a window in a different application.
        // If the application takes too long to catch up then we drop all events preceding
        // the touch into the other window.
        MotionEntry* motionEntry = static_cast<MotionEntry*>(entry);
        if (motionEntry->action == AMOTION_EVENT_ACTION_DOWN
                && (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER)
                && mInputTargetWaitCause == INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY
                && mInputTargetWaitApplicationHandle != NULL) {
            int32_t displayId = motionEntry->displayId;
            int32_t x = int32_t(motionEntry->pointerCoords[0].
                    getAxisValue(AMOTION_EVENT_AXIS_X));
            int32_t y = int32_t(motionEntry->pointerCoords[0].
                    getAxisValue(AMOTION_EVENT_AXIS_Y));
            sp<InputWindowHandle> touchedWindowHandle = findTouchedWindowAtLocked(displayId, x, y);
            if (touchedWindowHandle != NULL
                    && touchedWindowHandle->inputApplicationHandle
                            != mInputTargetWaitApplicationHandle) {
                // User touched a different application than the one we are waiting on.
                // Flag the event, and start pruning the input queue.
                mNextUnblockedEvent = motionEntry;
                needWake = true;
            }
        }
        break;
    }
    }

    return needWake;
}

InputDispatcherThread被唤醒后执行threadLoop()方法

重要数据列表

/frameworks/native/services/inputflinger/InputDispatcher.h

    EventEntry* mPendingEvent;
    Queue<EventEntry> mInboundQueue;
    Queue<EventEntry> mRecentQueue;
    Queue<CommandEntry> mCommandQueue;


  /* Manages the dispatch state associated with a single input channel. */
  class Connection : public RefBase {
  protected:
      virtual ~Connection();

  public:
      enum Status {
          // Everything is peachy.
          STATUS_NORMAL,
          // An unrecoverable communication error has occurred.
          STATUS_BROKEN,
          // The input channel has been unregistered.
          STATUS_ZOMBIE
      };

      Status status;
      sp<InputChannel> inputChannel; // never null
      sp<InputWindowHandle> inputWindowHandle; // may be null
      ... ..
  }
    
bool InputDispatcherThread::threadLoop() {
    mDispatcher->dispatchOnce();
    return true;
}
void InputDispatcher::dispatchOnce() {
    nsecs_t nextWakeupTime = LONG_LONG_MAX;
    { // acquire lock
        AutoMutex _l(mLock);
        mDispatcherIsAliveCondition.broadcast();

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

dispatchOnce方法主要是调用dispatchOnceInnerLocked,dispatchOnceInnerLocked的主要工作是从mInboundQueue队列中取出事件,然后分发给目标窗口,计算出下次唤醒的时间,最后调用mLooper->pollOnce使线程再次进入等待状态.

  • nextWakeupTime = LONG_LONG_MAX 线程进入休眠,等待唤醒;
  • nextWakeupTime = LONG_LONG_MIN 立即开始执行线程循环;
  • nextWakeupTime 进过dispatchOnceInnerLocked分发事件后,比如已经有事件发给一个窗口,但此窗口尚未对其进行反馈,则可以放弃此事件的派发并设置nextWakeupTime为一个合理的时间点.
void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
    nsecs_t currentTime = now();

    // Reset the key repeat timer whenever normal dispatch is suspended while the
    // device is in a non-interactive state.  This is to ensure that we abort a key
    // repeat if the device is just coming out of sleep.
    if (!mDispatchEnabled) {
        resetKeyRepeatLocked();
    }

    // If dispatching is frozen, do not process timeouts or try to deliver any new events.
    if (mDispatchFrozen) {
#if DEBUG_FOCUS
        ALOGD("Dispatch frozen.  Waiting some more.");
#endif
        return;
    }

    // Optimize latency of app switches.
    // Essentially we start a short timeout when an app switch key (HOME / ENDCALL) has
    // been pressed.  When it expires, we preempt dispatch and drop all other pending events.
    bool isAppSwitchDue = mAppSwitchDueTime <= currentTime;
    if (mAppSwitchDueTime < *nextWakeupTime) {
        *nextWakeupTime = mAppSwitchDueTime;
    }

    // Ready to start a new event.
    // If we don't already have a pending event, go grab one.
    //! mPendingEvent 等同于 mPendingEvent == NULL吗
    if (! mPendingEvent) {
        //派发队列为空
        if (mInboundQueue.isEmpty()) {
            if (isAppSwitchDue) {
                // The inbound queue is empty so the app switch key we were waiting
                // for will never arrive.  Stop waiting for it.
                resetPendingAppSwitchLocked(false);
                isAppSwitchDue = false;
            }

            ... ...

            // Nothing to do if there is no pending event.
            if (!mPendingEvent) {
                return;
            }
        } else {
            //派发队列不为空,直接取出赋给mPendingEvent
            // Inbound queue has at least one entry.
            mPendingEvent = mInboundQueue.dequeueAtHead();
            traceInboundQueueLengthLocked();
        }

        // Poke user activity for this event.
        if (mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER) {
            pokeUserActivityLocked(mPendingEvent);
        }

        // 充置ANR信息
        resetANRTimeoutsLocked();
    }

    // Now we have an event to dispatch.
    // All events are eventually dequeued and processed this way, even if we intend to drop them.
    ALOG_ASSERT(mPendingEvent != NULL);
    bool done = false;
    DropReason dropReason = DROP_REASON_NOT_DROPPED;
    if (!(mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER)) {
        dropReason = DROP_REASON_POLICY;
    } else if (!mDispatchEnabled) {
        dropReason = DROP_REASON_DISABLED;
    }

    if (mNextUnblockedEvent == mPendingEvent) {
        mNextUnblockedEvent = NULL;
    }

    switch (mPendingEvent->type) {
    ... ...
    
    case EventEntry::TYPE_MOTION: {
        MotionEntry* typedEntry = static_cast<MotionEntry*>(mPendingEvent);
        if (dropReason == DROP_REASON_NOT_DROPPED && isAppSwitchDue) {
            dropReason = DROP_REASON_APP_SWITCH;
        }
        if (dropReason == DROP_REASON_NOT_DROPPED
                && isStaleEventLocked(currentTime, typedEntry)) {
            dropReason = DROP_REASON_STALE;
        }
        if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) {
            dropReason = DROP_REASON_BLOCKED;
        }
        //触屏事件继续分发,派发成功或者丢弃改方法都返回true
        done = dispatchMotionLocked(currentTime, typedEntry,
                &dropReason, nextWakeupTime);
        break;
    }

    default:
        ALOG_ASSERT(false);
        break;
    }
    
    if (done) {
        if (dropReason != DROP_REASON_NOT_DROPPED) {
            dropInboundEventLocked(mPendingEvent, dropReason);
        }
        mLastDropReason = dropReason;
        //将mPendingEvent = NULL,下次循环不再处理该事件
        releasePendingEventLocked();
        *nextWakeupTime = LONG_LONG_MIN;  // force next poll to wake up immediately
    }
}

bool InputDispatcher::dispatchMotionLocked(
        nsecs_t currentTime, MotionEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) {
    // Preprocessing.
    if (! entry->dispatchInProgress) {
        entry->dispatchInProgress = true;

        logOutboundMotionDetailsLocked("dispatchMotion - ", entry);
    }

    // Clean up if dropping the event.
    if (*dropReason != DROP_REASON_NOT_DROPPED) {
        setInjectionResultLocked(entry, *dropReason == DROP_REASON_POLICY
                ? INPUT_EVENT_INJECTION_SUCCEEDED : INPUT_EVENT_INJECTION_FAILED);
        return true;
    }

    bool isPointerEvent = entry->source & AINPUT_SOURCE_CLASS_POINTER;

    // Identify targets.
    Vector<InputTarget> inputTargets;

    bool conflictingPointerActions = false;
    int32_t injectionResult;
    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);
    }
    //窗口处于无响应状态,返回false 下次继续派发
    if (injectionResult == INPUT_EVENT_INJECTION_PENDING) {
        return false;
    }

    setInjectionResultLocked(entry, injectionResult);
    //没有找到合适窗口,事件被丢弃
    if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) {
        if (injectionResult != INPUT_EVENT_INJECTION_PERMISSION_DENIED) {
            CancelationOptions::Mode mode(isPointerEvent ?
                    CancelationOptions::CANCEL_POINTER_EVENTS :
                    CancelationOptions::CANCEL_NON_POINTER_EVENTS);
            CancelationOptions options(mode, "input event injection failed");
            synthesizeCancelationEventsForMonitorsLocked(options);
        }
        return true;
    }
    添加mMonitoringChannels 到inputTargets,可监听所有输入事件
    addMonitoringTargetsLocked(inputTargets);

    // Dispatch the motion.
    if (conflictingPointerActions) {
        CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS,
                "conflicting pointer actions");
        synthesizeCancelationEventsForAllConnectionsLocked(options);
    }
    //将事件派发给inputTargets
    dispatchEventLocked(currentTime, entry, inputTargets);
    return true;
}

dispatchMotionLocked方法主要工作就是根据输入事件查找分发窗口,分为按坐标和按焦点查找两种,如果有注册监听事件的窗口,则也会直接派发.找到派发窗口后调用dispatchEventLocked继续分发给窗口

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

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

    pokeUserActivityLocked(eventEntry);

    for (size_t i = 0; i < inputTargets.size(); i++) {
        const InputTarget& inputTarget = inputTargets.itemAt(i);
        //根据inputTarget.inputChannel找到对应Connection在数组中的索引
        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
        }
    }
}

后面prepareDispatchCycleLocked调用enqueueDispatchEntryLocked将事件放入 Connection的outboundQueue中,然后调用startDispatchCycleLocked从outboundQueue中取出事件分发 connection->inputPublisher.publishMotionEvent

第一种,触屏事件按坐标查找目标窗口

int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
        const MotionEntry* entry, Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime,
        bool* outConflictingPointerActions) {
    ... ...
    //down事件处理,按Zorder遍历窗口列表,如果发现坐标落在该窗口上直接返回
    if (newGesture || (isSplit && maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN)) {
        /* Case 1: New splittable pointer going down, or need target for hover or scroll. */

        ... ...
        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) {
                if (! (flags & InputWindowInfo::FLAG_NOT_TOUCHABLE)) {
                    isTouchModal = (flags & (InputWindowInfo::FLAG_NOT_FOCUSABLE
                            | InputWindowInfo::FLAG_NOT_TOUCH_MODAL)) == 0;
                    if (isTouchModal || windowInfo->touchableRegionContainsPoint(x, y)) {
                        newTouchedWindowHandle = windowHandle;
                        break; // found touched window, exit window loop
                    }
                }

                if (maskedAction == AMOTION_EVENT_ACTION_DOWN
                        && (flags & InputWindowInfo::FLAG_WATCH_OUTSIDE_TOUCH)) {
                    mTempTouchState.addOrUpdateWindow(
                            windowHandle, InputTarget::FLAG_DISPATCH_AS_OUTSIDE, BitSet32(0));
                }
            }
        }
    //move, up, cancel事件处理,判断坐标落在的窗口与之前down事件是否是同一个窗口,如果不是则添加新的窗口到mTempTouchState中
    } else {
        /* Case 2: Pointer move, up, cancel or non-splittable pointer down. */
        ... ...

        // Check whether touches should slip outside of the current foreground window.
        if (maskedAction == AMOTION_EVENT_ACTION_MOVE
                && entry->pointerCount == 1
                && mTempTouchState.isSlippery()) {
            int32_t x = int32_t(entry->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X));
            int32_t y = int32_t(entry->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y));

            sp<InputWindowHandle> oldTouchedWindowHandle =
                    mTempTouchState.getFirstForegroundWindowHandle();
            sp<InputWindowHandle> newTouchedWindowHandle =
                    findTouchedWindowAtLocked(displayId, x, y);
            if (oldTouchedWindowHandle != newTouchedWindowHandle
                    && newTouchedWindowHandle != NULL) {
#if DEBUG_FOCUS
                ALOGD("Touch is slipping out of window %s into window %s.",
                        oldTouchedWindowHandle->getName().c_str(),
                        newTouchedWindowHandle->getName().c_str());
#endif
                // Make a slippery exit from the old window.
                mTempTouchState.addOrUpdateWindow(oldTouchedWindowHandle,
                        InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT, BitSet32(0));
                ... ...
                mTempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds);
            }
        }
    }

    //找到目标窗口后,判断目标窗口是否已经准备好,比如,如果当前窗口的待处理的事件不为空,并且当前时间距离队头事件分发的事件距离大于0.5s,则认为发生ANR,即checkWindowReadyForMoreInputLocked返回reason不为空,那么injectionResult赋值为INPUT_EVENT_INJECTION_PENDING,在下个循环中继续分发这个事件
    // Ensure all touched foreground windows are ready for new input.
    for (size_t i = 0; i < mTempTouchState.windows.size(); i++) {
        const TouchedWindow& touchedWindow = mTempTouchState.windows[i];
        if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) {
            // Check whether the window is ready for more input.
            std::string reason = checkWindowReadyForMoreInputLocked(currentTime,
                    touchedWindow.windowHandle, entry, "touched");
            if (!reason.empty()) {
                injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
                        NULL, touchedWindow.windowHandle, nextWakeupTime, reason.c_str());
                goto Unresponsive;
            }
        }
    }
    //如果分发成功,把目标窗口保存到inputTargets中
    // Success!  Output targets.
    injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED;

    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);
    }

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

findTouchedWindowTargetsLocked的主要工作包括以下三个部分:

  1. 在窗口列表mWindowHandles中根据窗口信息和事件坐标找到目标窗口
  2. 判断目标窗口是否准备好了,如果没有injectionResult赋值为INPUT_EVENT_INJECTION_PENDING,下次循环中继续分发
  3. 目标窗口没问题则将其赋值给inputTargets

第二种,按焦点查找目标窗口findFocusedWindowTargetsLocked,这个方法主要靠WMS传过来的焦点窗口决定mFocusedWindowHandle

按键事件分发

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

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

void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {
... ...
    /*注意这时候拦截是在InputReaderThread中,在找到目标窗口之前拦截,而interceptKeyBeforeDispatching是在InputDispatchThread中拦截,返回结果按位与或非ACTION_PASS_TO_USER,如灭屏时除了power键外的大部分按键 ,在ANR发生前处理紧急事件,result &= ~ACTION_PASS_TO_USER*/
    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();
        }

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

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

    if (needWake) {
        mLooper->wake();
    }
}
bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry,
        DropReason* dropReason, nsecs_t* nextWakeupTime) {
    ... ...

    // Give the policy a chance to intercept the key.
    if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN) {
        if (entry->policyFlags & POLICY_FLAG_PASS_TO_USER) {
            CommandEntry* commandEntry = postCommandLocked(
                    & InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible);
            if (mFocusedWindowHandle != NULL) {
                commandEntry->inputWindowHandle = mFocusedWindowHandle;
            }
            commandEntry->keyEntry = entry;
            entry->refCount += 1;
            return false; // wait for the command to run
        } else {
            entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE;
        }
    } else if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_SKIP) {
        if (*dropReason == DROP_REASON_NOT_DROPPED) {
            *dropReason = DROP_REASON_POLICY;
        }
    }

    ... ...

    // Identify targets.
    Vector<InputTarget> inputTargets;
    int32_t injectionResult = findFocusedWindowTargetsLocked(currentTime,
            entry, inputTargets, nextWakeupTime);
    if (injectionResult == INPUT_EVENT_INJECTION_PENDING) {
        return false;
    }

    ... ...

    // Dispatch the key.
    dispatchEventLocked(currentTime, entry, inputTargets);
    return true;
}

dispatchKeyLocked中首先调用interceptKeyBeforeDispatching再次询问是否需要拦截,然后找到焦点窗口作为目标窗口,然后继续派发事件,interceptKeyBeforeDispatching返回0交给用户处理,小于0拦截,大于0稍后再一次询问再发,用于组合键情况

与touch事件一样将事件放入队列mInboundQueue中,然后开始InputDispatcherThread 线程循环取出事件

native Looper tips:

Looper::pollOnce()中调用epoll_wait使线程进入等待状态,timeout参数为负数则一直等待

Looper::wake()像管道中写入,从而可以唤醒线程,唤醒时调用awoken将数据read出来,线程从阻塞状态返回

Looper::addFd调用epoll_ctl 创建监听节点,当有事件触发时,回调LooperCallback的handleEvent方法

输入事件分发

dispatchMotionLocked方法主要工作就是根据输入事件查找分发窗口,分为按坐标和按焦点查找两种,如果有注册监听事件的窗口,则也会直接派发.找到派发窗口后调用dispatchEventLocked继续分发给窗口

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

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

    pokeUserActivityLocked(eventEntry);

    for (size_t i = 0; i < inputTargets.size(); i++) {
        const InputTarget& inputTarget = inputTargets.itemAt(i);
        //根据inputTarget.inputChannel找到对应Connection在数组中的索引
        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
        }
    }
}
void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime,
        const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) {
    bool wasEmpty = connection->outboundQueue.isEmpty();
    //加入到派发队列 connection->outboundQueue.enqueueAtTail中
    // 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) {
        ... ...
  
              // Publish the motion event.
              status = connection->inputPublisher.publishMotionEvent(dispatchEntry->seq,
                      motionEntry->deviceId, motionEntry->source, motionEntry->displayId,
                      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;
          }
  
          default:
              ALOG_ASSERT(false);
              return;
          }
        ... ...
  
          // Re-enqueue the event on the wait queue.
          connection->outboundQueue.dequeue(dispatchEntry);
          traceOutboundQueueLengthLocked(connection);
          connection->waitQueue.enqueueAtTail(dispatchEntry);
          traceWaitQueueLengthLocked(connection);
      }
  }

WMS输入管道

InputChannel 就是SocketPair 描述符及其操作的封装,而且是成对使用的.
InputChannel 继承自Parcelable,用于在窗口所在应用进程和InputDispathcer所在的SystemServer进程之间传送输入事件.采用socketpair双工套接字方式实现传输输入事件. 窗口创建时,成对创建InputChannel对象,一个传给InputDispathcer,一个给应用进程,两端都可以读写事件.

首先看下窗口创建时InputChannel的创建流程,窗口创建时ViewRootImpl中创建了一个InputChannel空对象

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

 public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
     ... ... 
     if ((mWindowAttributes.inputFeatures
                        & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
                    mInputChannel = new InputChannel();
                }
                mForceDecorViewVisibility = (mWindowAttributes.privateFlags
                        & PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY) != 0;
                try {
                    mOrigWindowType = mWindowAttributes.type;
                    mAttachInfo.mRecomputeGlobalAttributes = true;
                    collectViewAttributes();
                    res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                            getHostVisibility(), mDisplay.getDisplayId(), mWinFrame,
                            mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                            mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel);
                } catch (RemoteException e) {
... ...
 }

然后会调到WindowManagerService.java的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, Rect outOutsets,
            DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel) {
            ... ...
            final boolean openInputChannels = (outInputChannel != null
                    && (attrs.inputFeatures & INPUT_FEATURE_NO_INPUT_CHANNEL) == 0);
            if  (openInputChannels) {
                win.openInputChannel(outInputChannel);
            }
           ... ...
    }

如果没有创建过调用openInputChannel创建一对InputChannel对象
/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();
       //创建一对InputChannel存放在数组中
       InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
       mInputChannel = inputChannels[0];
       mClientChannel = inputChannels[1];
       mInputWindowHandle.inputChannel = inputChannels[0];
       //应用端的mClientChannel对象通过binder传给应用进程,因为此时是在系统服务进程
       if (outInputChannel != null) {
           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);
       }
       //服务端mInputChannel兑现传给InputDispatcher
       mService.mInputManager.registerInputChannel(mInputChannel, mInputWindowHandle);
   }

下面分别从以下三个部分分析:

  1. 创建输入通道InputChannel
  2. 将mClientChannel通过binder传到应用进程
  3. 将mInputChannel传给InputDispatcher

/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 + "'");
        }
        return nativeOpenInputChannelPair(name);
    }
static jobjectArray android_view_InputChannel_nativeOpenInputChannelPair(JNIEnv* env,
        jclass clazz, jstring nameObj) {
    const char* nameChars = env->GetStringUTFChars(nameObj, NULL);
    std::string name = nameChars;
    env->ReleaseStringUTFChars(nameObj, nameChars);

    sp<InputChannel> serverChannel;
    sp<InputChannel> clientChannel;
    //调用openInputChannelPair创建socket通信,并将文件描述符封装在native 的InputChannel对象serverChannel, clientChannel中
    status_t result = InputChannel::openInputChannelPair(name, serverChannel, clientChannel);

    if (result) {
        String8 message;
        message.appendFormat("Could not open input channel pair.  status=%d", result);
        jniThrowRuntimeException(env, message.string());
        return NULL;
    }

    jobjectArray channelPair = env->NewObjectArray(2, gInputChannelClassInfo.clazz, NULL);
    if (env->ExceptionCheck()) {
        return NULL;
    }
    //根据native InputChannel对象创建Java对象
    jobject serverChannelObj = android_view_InputChannel_createInputChannel(env,
            std::make_unique<NativeInputChannel>(serverChannel));
    if (env->ExceptionCheck()) {
        return NULL;
    }

    jobject clientChannelObj = android_view_InputChannel_createInputChannel(env,
            std::make_unique<NativeInputChannel>(clientChannel));
    if (env->ExceptionCheck()) {
        return NULL;
    }

    env->SetObjectArrayElement(channelPair, 0, serverChannelObj);
    env->SetObjectArrayElement(channelPair, 1, clientChannelObj);
    return channelPair;
}

android_view_InputChannel_nativeOpenInputChannelPair方法创建了两个InputChannel的java对象返回给java层

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

status_t InputChannel::openInputChannelPair(const std::string& name,
        sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) {
    int sockets[2];
    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;
    }

    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));

    std::string serverChannelName = name;
    serverChannelName += " (server)";
    outServerChannel = new InputChannel(serverChannelName, sockets[0]);

    std::string clientChannelName = name;
    clientChannelName += " (client)";
    outClientChannel = new InputChannel(clientChannelName, sockets[1]);
    return OK;
}

具体怎么创建socket句柄

NativeInputChannel 中封装 native层的InputChannel,native层的InputChannel的构造方法中读取java层InputChannel对应的文件描述符,

static NativeInputChannel* android_view_InputChannel_getNativeInputChannel(JNIEnv* env,
        jobject inputChannelObj) {
    jlong longPtr = env->GetLongField(inputChannelObj, gInputChannelClassInfo.mPtr);
    return reinterpret_cast<NativeInputChannel*>(longPtr);
}

179static void android_view_InputChannel_nativeTransferTo(JNIEnv* env, jobject obj,
180        jobject otherObj) {
181    if (android_view_InputChannel_getNativeInputChannel(env, otherObj) != NULL) {
182        jniThrowException(env, "java/lang/IllegalStateException",
183                "Other object already has a native input channel.");
184        return;
185    }
186
187    NativeInputChannel* nativeInputChannel =
188            android_view_InputChannel_getNativeInputChannel(env, obj);
189    android_view_InputChannel_setNativeInputChannel(env, otherObj, nativeInputChannel);
190    android_view_InputChannel_setNativeInputChannel(env, obj, NULL);
191}

90static void android_view_InputChannel_setNativeInputChannel(JNIEnv* env, jobject inputChannelObj,
91        NativeInputChannel* nativeInputChannel) {
92    env->SetLongField(inputChannelObj, gInputChannelClassInfo.mPtr,
93             reinterpret_cast<jlong>(nativeInputChannel));
94}

第三部分传给InputDispatcher

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

523    /**
524     * Registers an input channel so that it can be used as an input event target.
525     * @param inputChannel The input channel to register.
526     * @param inputWindowHandle The handle of the input window associated with the
527     * input channel, or null if none.
528     */
529    public void registerInputChannel(InputChannel inputChannel,
530            InputWindowHandle inputWindowHandle) {
531        if (inputChannel == null) {
532            throw new IllegalArgumentException("inputChannel must not be null.");
533        }
534
535        nativeRegisterInputChannel(mPtr, inputChannel, inputWindowHandle, false);
536    }

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

static void nativeRegisterInputChannel(JNIEnv* env, jclass /* clazz */,
        jlong ptr, jobject inputChannelObj, jobject inputWindowHandleObj, jboolean monitor) {
    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
    //将Java的inputChannel对象转换为native的inputChannel对象
    sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,
            inputChannelObj);
    if (inputChannel == NULL) {
        throwInputChannelNotInitialized(env);
        return;
    }
    //将Java的InputWindowHandle对象转换为native的InputWindowHandle对象
    sp<InputWindowHandle> inputWindowHandle =
            android_server_InputWindowHandle_getHandle(env, inputWindowHandleObj);
    //像InputDispatcher注册
    status_t status = im->registerInputChannel(
            env, inputChannel, inputWindowHandle, monitor);
    if (status) {
        std::string message;
        message += StringPrintf("Failed to register input channel.  status=%d", status);
        jniThrowRuntimeException(env, message.c_str());
        return;
    }

    if (! monitor) {
        android_view_InputChannel_setDisposeCallback(env, inputChannelObj,
                handleInputChannelDisposed, im);
    }
}

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

sp<InputChannel> android_view_InputChannel_getInputChannel(JNIEnv* env, jobject inputChannelObj) {
    NativeInputChannel* nativeInputChannel =
            android_view_InputChannel_getNativeInputChannel(env, inputChannelObj);
    return nativeInputChannel != NULL ? nativeInputChannel->getInputChannel() : NULL;
}

static NativeInputChannel* android_view_InputChannel_getNativeInputChannel(JNIEnv* env,
        jobject inputChannelObj) {
    jlong longPtr = env->GetLongField(inputChannelObj, gInputChannelClassInfo.mPtr);
    return reinterpret_cast<NativeInputChannel*>(longPtr);
}

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

  status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel,
          const sp<InputWindowHandle>& inputWindowHandle, bool monitor) {
  #if DEBUG_REGISTRATION
      ALOGD("channel '%s' ~ registerInputChannel - monitor=%s", inputChannel->getName().string(),
              toString(monitor));
  #endif
  
      { // acquire lock
          AutoMutex _l(mLock);
  
          if (getConnectionIndexLocked(inputChannel) >= 0) {
              ALOGW("Attempted to register already registered input channel '%s'",
                      inputChannel->getName().string());
              return BAD_VALUE;
          }
          //以inputChannel,inputWindowHandle为参数创建Connection
          sp<Connection> connection = new Connection(inputChannel, inputWindowHandle, monitor);
  
          int fd = inputChannel->getFd();
          以inputChannel对应的fd为key,Connection对象为值存入一个map中,以便于查找
          mConnectionsByFd.add(fd, connection);
  
          if (monitor) {
              mMonitoringChannels.push(inputChannel);
          }
          //监听inputChannel文件描述符,当有消息到来时回调handleReceiveCallback,当接收到来自窗口的反馈时,派发线程的mLooper->pollOnce会被唤醒,并回调handleReceiveCallback进行处理,因此窗口反馈的到来也会使派发线程进入下一次循环.
          mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
      } // release lock
  
      // Wake the looper because some connections have changed.
      mLooper->wake();
      return OK;
  }

关于InputWindowHandle

WindowState定义final 的InputWindowHandle对象,一个Java层的InputWindowHandle对象也都唯一对应着一个Native层的InputWindowHandle对象.InputWindowHandle中定义了关于窗口的所有信息,包括层级,焦点,大小等.并包含了windowstate对象和服务端的InputChannel对象.

关于Connection

inputChannel被封装近Connection 对象,Connection类描述了从InputDispatcher到目标窗口中的一个连接,其中保存了向窗口发送时间的状态信息.重要成员:

  • mInputPublisher
    封装了InputChannel并直接对其进行写入和读取.
  • outboundQueue
    用于保存等待通多此Connection进行发送的事件队列
  • waitQueue
    用于保存已经通过此Connection将事件发送给窗口,正在等待窗口反馈的事件队列

所以是一个Connection对应一个窗口吗???

派发流程总结:

将输入事件放入Connection的outboundQueue队列中,然后InputPublisher将事件从outboundQueue队列取出并依次封装为InputMessage,写入InputChannel中,如果outboundQueue队列之前为空,证明之前的事件已经发送完成,然后将写入outboundQueue的事件放入waitQueue队列里.随后派发线程进入休眠状态.当窗口端读取事件并发来反馈后,派发线程被唤醒,触发handleReceiveCallback回调,handleReceiveCallback中将从waitQueue中移除已经成功读取的事件.

客户端得到InputChannel对象后,以他为参数创建一个InputEventReceiver对象,实现onInputEvent,等待事件到来时回调.

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

static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,
        jobject inputChannelObj, jobject messageQueueObj) {
    sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,
            inputChannelObj);
    ... ...

    sp<NativeInputEventReceiver> receiver = new NativeInputEventReceiver(env,
            receiverWeak, inputChannel, messageQueue);
    status_t status = receiver->initialize();
    ... ...
}

以inputChannel为参数创建一个NativeInputEventReceiver对象,初始化调用setFdEvents

void NativeInputEventReceiver::setFdEvents(int events) {
    if (mFdEvents != events) {
        mFdEvents = events;
        int fd = mInputConsumer.getChannel()->getFd();
        if (events) {
            mMessageQueue->getLooper()->addFd(fd, 0, events, this, NULL);
        } else {
            mMessageQueue->getLooper()->removeFd(fd);
        }
    }
}

通过Looper->addFd监听InputChannel对应的fd,当派发线程写入事件时,便可以唤起该线程,并回调InputEventReceiver.onInputEvent方法,InputEventReceiver.onInputEvent处理完后InputConsumer写入反馈状态,派发线程唤醒,开始下一次派发循环

窗口输入事件ANR原理

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

int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime,
        const EventEntry* entry, Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime) {
    int32_t injectionResult;
    std::string reason;

... ...

    // Check whether the window is ready for more input.
    reason = checkWindowReadyForMoreInputLocked(currentTime,
            mFocusedWindowHandle, entry, "focused");
    if (!reason.empty()) {
        injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
                mFocusedApplicationHandle, mFocusedWindowHandle, nextWakeupTime, reason.c_str());
        goto Unresponsive;
    }

    // Success!  Output targets.
    injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED;
    addWindowTargetLocked(mFocusedWindowHandle,
            InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS, BitSet32(0),
            inputTargets);

    // Done.
Failed:
Unresponsive:
    nsecs_t timeSpentWaitingForApplication = getTimeSpentWaitingForApplicationLocked(currentTime);
    updateDispatchStatisticsLocked(currentTime, entry,
            injectionResult, timeSpentWaitingForApplication);
#if DEBUG_FOCUS
    ALOGD("findFocusedWindow finished: injectionResult=%d, "
            "timeSpentWaitingForApplication=%0.1fms",
            injectionResult, timeSpentWaitingForApplication / 1000000.0);
#endif
    return injectionResult;
}

checkWindowReadyForMoreInputLocked方法判断窗口是否准备号接受事件

std::string InputDispatcher::checkWindowReadyForMoreInputLocked(nsecs_t currentTime,
        const sp<InputWindowHandle>& windowHandle, const EventEntry* eventEntry,
        const char* targetType) {
    // If the window is paused then keep waiting.
    if (windowHandle->getInfo()->paused) {
        return StringPrintf("Waiting because the %s window is paused.", targetType);
    }
    //获取InputChannel在mConnectionsByFd中的索引,从而得到对应的Connection对象
    // If the window's connection is not registered then keep waiting.
    ssize_t connectionIndex = getConnectionIndexLocked(windowHandle->getInputChannel());
    if (connectionIndex < 0) {
        return StringPrintf("Waiting because the %s window's input channel is not "
                "registered with the input dispatcher.  The window may be in the process "
                "of being removed.", targetType);
    }

    // If the connection is dead then keep waiting.
    sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
    if (connection->status != Connection::STATUS_NORMAL) {
        return StringPrintf("Waiting because the %s window's input connection is %s."
                "The window may be in the process of being removed.", targetType,
                connection->getStatusLabel());
    }
     //inputPublisher被block,比如窗口反馈慢,导致InputChannel被写满,inputPublisher就会被block
    // If the connection is backed up then keep waiting.
    if (connection->inputPublisherBlocked) {
        return StringPrintf("Waiting because the %s window's input channel is full.  "
                "Outbound queue length: %d.  Wait queue length: %d.",
                targetType, connection->outboundQueue.count(), connection->waitQueue.count());
    }
    //Key事件要求outboundQueue和waitQueue全部为空才继续分发
    // Ensure that the dispatch queues aren't too far backed up for this event.
    if (eventEntry->type == EventEntry::TYPE_KEY) {
        // If the event is a key event, then we must wait for all previous events to
        // complete before delivering it because previous events may have the
        // side-effect of transferring focus to a different window and we want to
        // ensure that the following keys are sent to the new window.
        //
        // Suppose the user touches a button in a window then immediately presses "A".
        // If the button causes a pop-up window to appear then we want to ensure that
        // the "A" key is delivered to the new pop-up window.  This is because users
        // often anticipate pending UI changes when typing on a keyboard.
        // To obtain this behavior, we must serialize key events with respect to all
        // prior input events.
        if (!connection->outboundQueue.isEmpty() || !connection->waitQueue.isEmpty()) {
            return StringPrintf("Waiting to send key event because the %s window has not "
                    "finished processing all of the input events that were previously "
                    "delivered to it.  Outbound queue length: %d.  Wait queue length: %d.",
                    targetType, connection->outboundQueue.count(), connection->waitQueue.count());
        }
    } else {
       //Touch事件只要求在0.5s内窗口接到反馈即可,这个用waitQueue头事件的处理事件作为判断
        // Touch events can always be sent to a window immediately because the user intended
        // to touch whatever was visible at the time.  Even if focus changes or a new
        // window appears moments later, the touch event was meant to be delivered to
        // whatever window happened to be on screen at the time.
        //
        // Generic motion events, such as trackball or joystick events are a little trickier.
        // Like key events, generic motion events are delivered to the focused window.
        // Unlike key events, generic motion events don't tend to transfer focus to other
        // windows and it is not important for them to be serialized.  So we prefer to deliver
        // generic motion events as soon as possible to improve efficiency and reduce lag
        // through batching.
        //
        // The one case where we pause input event delivery is when the wait queue is piling
        // up with lots of events because the application is not responding.
        // This condition ensures that ANRs are detected reliably.
        if (!connection->waitQueue.isEmpty()
                && currentTime >= connection->waitQueue.head->deliveryTime
                        + STREAM_AHEAD_EVENT_TIMEOUT) {
            return StringPrintf("Waiting to send non-key event because the %s window has not "
                    "finished processing certain input events that were delivered to it over "
                    "%0.1fms ago.  Wait queue length: %d.  Wait queue head age: %0.1fms.",
                    targetType, STREAM_AHEAD_EVENT_TIMEOUT * 0.000001f,
                    connection->waitQueue.count(),
                    (currentTime - connection->waitQueue.head->deliveryTime) * 0.000001f);
        }
    }
    return "";
}

checkWindowReadyForMoreInputLocked返回reason不为空,则继续调用handleTargetsNotReadyLocked处理

int32_t InputDispatcher::handleTargetsNotReadyLocked(nsecs_t currentTime,
        const EventEntry* entry,
        const sp<InputApplicationHandle>& applicationHandle,
        const sp<InputWindowHandle>& windowHandle,
        nsecs_t* nextWakeupTime, const char* reason) {
        //系统没起来
    if (applicationHandle == NULL && windowHandle == NULL) {
        ... ...
        }
    } else {
    //ANR开始时间点记录, 因为mInputTargetWaitCause初始值为INPUT_TARGET_WAIT_CAUSE_NONE
        if (mInputTargetWaitCause != INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY) {
#if DEBUG_FOCUS
            ALOGD("Waiting for application to become ready for input: %s.  Reason: %s",
                    getApplicationWindowLabelLocked(applicationHandle, windowHandle).c_str(),
                    reason);
#endif
            nsecs_t timeout;
            if (windowHandle != NULL) {
                timeout = windowHandle->getDispatchingTimeout(DEFAULT_INPUT_DISPATCHING_TIMEOUT);
            } else if (applicationHandle != NULL) {
                timeout = applicationHandle->getDispatchingTimeout(
                        DEFAULT_INPUT_DISPATCHING_TIMEOUT);
            } else {
                timeout = DEFAULT_INPUT_DISPATCHING_TIMEOUT;
            }

            mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY;
            mInputTargetWaitStartTime = currentTime;
            mInputTargetWaitTimeoutTime = currentTime + timeout;
            mInputTargetWaitTimeoutExpired = false;
            mInputTargetWaitApplicationHandle.clear();

            if (windowHandle != NULL) {
                mInputTargetWaitApplicationHandle = windowHandle->inputApplicationHandle;
            }
            if (mInputTargetWaitApplicationHandle == NULL && applicationHandle != NULL) {
                mInputTargetWaitApplicationHandle = applicationHandle;
            }
        }
    }
    
    if (mInputTargetWaitTimeoutExpired) {
        return INPUT_EVENT_INJECTION_TIMED_OUT;
    }
    //再次窗口没准备好则会判断是否超过ANR时间,如果超过引发ANR
    if (currentTime >= mInputTargetWaitTimeoutTime) {
        onANRLocked(currentTime, applicationHandle, windowHandle,
                entry->eventTime, mInputTargetWaitStartTime, reason);

        // Force poll loop to wake up immediately on next iteration once we get the
        // ANR response back from the policy.
        *nextWakeupTime = LONG_LONG_MIN;
        return INPUT_EVENT_INJECTION_PENDING;
    } else {
        // Force poll loop to wake up when timeout is due.
        if (mInputTargetWaitTimeoutTime < *nextWakeupTime) {
            *nextWakeupTime = mInputTargetWaitTimeoutTime;
        }
        return INPUT_EVENT_INJECTION_PENDING;
    }
}

所以引发ANR的整体流程可以概况为:
inputdispacher派发线程在找到分发窗口后,首先判断窗口是否准备好了,如果准备好了(Key事件两个队列都为空,touch事件0.5秒内有反馈),那么直接写入InputChannel 分发给窗口, 分发线程进入休眠等待反馈,准备进行下次循环,如果窗口没有准备好,那么记录ANR开始时间,在下一次分发时如果窗口还没有准备好,那么判断时间,超时则抛出ANR,ANR事件设为Pending状态待分发

nextWakeupTime 派发线程休眠时间当有第一个ANR时设为ANR时间点mInputTargetWaitTimeoutTime,正在派发情况如果有输入事件待分发则nextWakeupTime 为LONG_LONG_MIN即立即唤醒,否则为LONG_LONG_MAX等待有时间时唤醒

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,219评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,363评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,933评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,020评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,400评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,640评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,896评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,597评论 0 199
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,327评论 1 244
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,581评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,072评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,399评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,054评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,083评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,849评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,672评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,585评论 2 270