framework学习笔记15. Input 输入事件(1)

原计划 input 输入事件的学习分为两节内容学习并记录,经学习发现并远不止这些内容,所以决定重新写 input 输入事件番外篇,如需参考,请阅读 input 输入事件番外篇;造成的不便,深表抱歉。

1. InputManagerService的启动:安卓系统服务的启动都是在 SystemServer 这个进程中,我们可以在main()方法调用的 new SystemServer().run() 中找打如下代码:

inputManager = new InputManagerService(context);  // 构建InputManagerService对象,见1.1
wm = WindowManagerService.main(context, inputManager,
                    mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
                    !mFirstBoot, mOnlyCore);

ServiceManager.addService(Context.WINDOW_SERVICE, wm);
ServiceManager.addService(Context.INPUT_SERVICE, inputManager);
mActivityManagerService.setWindowManager(wm);

inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
inputManager.start();  // 执行start()方法,见1.2

1.1 InputManagerService 的构造函数:

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

        mUseDevInputEventForAudioJack =
                context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
        // native方法,com_android_server_input_InputManagerService.cpp中
        mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());

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

我们在看看这个native方法:frameworks/base/services/core/jni目录中

// native方法,com_android_server_input_InputManagerService.cpp
static jlong nativeInit(JNIEnv* env, jclass clazz,
        jobject serviceObj, jobject contextObj, jobject messageQueueObj) {
    // MessageQueue的指针
    sp messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
    if (messageQueue == NULL) {
        jniThrowRuntimeException(env, "MessageQueue is not initialized.");
        return 0;
    }
    // 就是这个对象
    NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
            messageQueue->getLooper());
    im->incStrong(0);
    return reinterpret_cast(im);
}

// native方法,com_android_server_input_InputManagerService.cpp
NativeInputManager::NativeInputManager(jobject contextObj,
        jobject serviceObj, const sp& looper) :
        mLooper(looper), mInteractive(true) {
    // ...

    sp eventHub = new EventHub();
    mInputManager = new InputManager(eventHub, this, this);
}

上面的代码中创建了一个 NativeInputManager 对象,并且把这个对象返回了保存在 InputManagerService的 mPtr 中;然后再看看 new InputManager(eventHub, this, this):

// InputManager.cpp中:
InputManager::InputManager(
        const sp& eventHub,
        const sp& readerPolicy,
        const sp& dispatcherPolicy) {
    mDispatcher = new InputDispatcher(dispatcherPolicy);
    // 传入mDispatcher:读到的信号,肯定是要通过 mDispatcher 回调的
    mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
    initialize();
}

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

到这里,我们就获取到和输入事件相关的几个关键类:EventHub、InputReader、InputDispatcher;另外 InputReaderThread 和 InputDispatcherThread 就是两条处理线程;

1.2 执行start()方法:inputManager.start();

    public void start() {
        Slog.i(TAG, "Starting input manager");
        nativeStart(mPtr);  // native 方法:关键代码

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

        registerPointerSpeedSettingObserver();
        registerShowTouchesSettingObserver();

        // 接收ACTION_USER_SWITCHED,这是关于多用户切换的操作
        mContext.registerReceiver(new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                updatePointerSpeedFromSettings();
                updateShowTouchesFromSettings();
            }
        }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mHandler);

        updatePointerSpeedFromSettings();
        updateShowTouchesFromSettings();
    }

com_android_server_input_InputManagerService.cpp 中的 nativeStart(mPtr) 方法:

// com_android_server_input_InputManagerService.cpp 中:
static void nativeStart(JNIEnv* env, jclass clazz, jlong ptr) {
    NativeInputManager* im = reinterpret_cast(ptr);

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


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

小结:nativeStart(mPtr) 方法就是把创建好的 c++ 对象 InputManager 传入,然后调用 InputManager 的start() 方法,而在 InputManager::start() 中也很简单,启动上面的两条处理线程(mReaderThread 和mDispatcherThread);

2. InputReader 与 InputReaderThread:InputReaderThread继承自C++的Thread类,Thread类封装了pthread线程工具,提供了与Java层Thread类相似的API。C++的Thread类提供了一个名为threadLoop()的纯虚函数,当线程开始运行后,将会在内建的线程循环中不断地调用threadLoop(),直到此函数返回false,则退出线程循环,从而结束线程。
InputReaderThread仅仅重写了threadLoop()函数:

// InputReader.cpp 中:
bool InputReaderThread::threadLoop() {
    mReader->loopOnce();
    return true;
}

// InputReader.cpp 中:
void InputReader::loopOnce() {
    // ... 省略
    // 见 注释
    size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
    // ...
    if (count) {
        processEventsLocked(mEventBuffer, count);  // 我们只关注 input 事件的输入,见 2.1
    }
    // ... 
}

注释:这里涉及到EventHub,我们就在这里开始研究一下EventHub了:
(1)EventHub的构造函数:

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

    /*(1)使用epoll_create()函数创建一个epoll对象**。EPOLL_SIZE_HINT指定最大监听个数为8
       这个epoll对象将用来监听设备节点是否有数据可读(有无事件)***/
    mEpollFd = epoll_create(EPOLL_SIZE_HINT);

    //(2)创建一个inotify对象**。这个inotify对象将被用来监听设备节点的增删事件
    mINotifyFd = inotify_init();
    // 将存储设备节点的路径/dev/input作为监听对象添加到inotify对象中。当此文件夹下的设备节点
    int result = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE);

    /*(3)接下来将mINotifyFd作为epoll的一个监控对象。当inotify事件到来时,epoll_wait()将
       立刻返回,EventHub便可从mINotifyFd中读取设备节点的增删信息,并作相应处理 */
    struct epoll_event eventItem;
    memset(&eventItem, 0, sizeof(eventItem));
    eventItem.events = EPOLLIN;  // 监听mINotifyFd可读
    // 注意这里并没有使用fd字段,而使用了自定义的值EPOLL_ID_INOTIFY
    eventItem.data.u32 = EPOLL_ID_INOTIFY;
    // 将对mINotifyFd的监听注册到epoll对象中
    result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem);

    /* 在构造函数剩余的代码中,EventHub创建了一个名为wakeFds的匿名管道,并将管道读取端
       的描述符的可读事件注册到epoll对象中。因为InputReader在执行getEvents()时会因无事件而
       导致其线程阻塞在epoll_wait()的调用里,然而有时希望能够立刻唤醒InputReader线程使其处
       理一些请求。此时只需向wakeFds管道的写入端写入任意数据,此时读取端有数据可读,使得
       epoll_wait()得以返回,从而达到唤醒InputReader线程的目的*/
    // ...
}

(2)getEvents():
InputReaderThread的线程循环为Reader子系统提供了运转的动力,EventHub的工作也是由它驱动的。
InputReader::loopOnce()函数调用EventHub::getEvents()函数获取事件列表,所以这个getEvents()是EventHub运行的动力所在,几乎包含了EventHub的所有工作事项。

// 那么先看看对事件的封装:RawEvent
struct RawEvent {
    nsecs_t when;             /* 发生事件时的时间戳 */
    int32_t deviceId;        /* 产生事件的设备Id,它是由EventHub自行分配的,InputReader
                                    以根据它从EventHub中获取此设备的详细信息 */
    int32_t type;             /* 事件的类型 */
    int32_t code;             /* 事件代码 */
    int32_t value;            /* 事件值 */
};


// getEvent():
size_t EventHub::getEvents(int timeoutMillis,RawEvent* buffer, size_t bufferSize) {
    /* event指针指向了在buffer下一个可用于存储事件的RawEvent结构体。每存储一个事件,
       event指针都回向后偏移一个元素 */
    RawEvent* event = buffer;
    /*capacity记录了buffer中剩余的元素数量。当capacity为0时,表示buffer已满,此时需要停
       继续处理新事件,并将已处理的事件返回给调用者 */
    size_t capacity = bufferSize;
    /* 接下来的循环是getEvents()函数的主体。在这个循环中,会先将可用事件放入到buffer中并返回。
       如果没有可用事件,则进入epoll_wait()等待事件的到来,epoll_wait()返回后会重新循环将可用
       将新事件放入buffer */
    for (;;){
       nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
        /* **(1)首先进行与设备相关的工作。**某些情况下,如EventHub创建后第一次执行getEvents()函数
           时,需要扫描/dev/input文件夹下的所有设备节点并将这些设备打开。另外,当设备节点的发生增
           动作生时,会将设备事件存入到buffer中 */
        // ...
        /* **(2)处理未被InputReader取走的输入事件与设备事件。**epoll_wait()所取出的epoll_event
           存储在mPendingEventItems中,mPendingEventCount指定了mPendingEventItems数组
           所存储的事件个数。而mPendingEventIndex指定尚未处理的epoll_event的索引 */
       while (mPendingEventIndex < mPendingEventCount) {
           const struct epoll_event & eventItem = mPendingEventItems[mPendingEventIndex++];
           /* 在这里分析每一个epoll_event,如果是表示设备节点可读,则读取原始事件并放置到buffer
              中。如果是表示mINotifyFd可读,则设置mPendingINotify为true,当InputReader
              将现有的输入事件都取出后读取mINotifyFd中的事件,并进行相应的设备加载与卸载操作。
               另外,如果此epoll_event表示wakeFds的读取端有数据可读,则设置awake标志为true,
              无论此次getEvents()调用有无取到事件,都不会再次进行epoll_wait()进行事件等待 */
           // ...
        }
        //(3)如果mINotifyFd有数据可读,说明设备节点发生了增删操作
        if(mPendingINotify && mPendingEventIndex >= mPendingEventCount) {
           /* 读取mINotifyFd中的事件,同时对输入设备进行相应的加载与卸载操作。这个操作必须当
              InputReader将现有输入事件读取并处理完毕后才能进行,因为现有的输入事件可能来自需要
              被卸载的输入设备,InputReader处理这些事件依赖于对应的设备信息 */
            // ...
            deviceChanged= true;
        }
        // 设备节点增删操作发生时,则重新执行循环体,以便将设备变化的事件放入buffer中
        if(deviceChanged) {
           continue;
        }
        // 如果此次getEvents()调用成功获取了一些事件,或者要求唤醒InputReader,则退出循环并
        // 结束getEvents()的调用,使InputReader可以立刻对事件进行处理
        if(event != buffer || awoken) {
           break;
        }
        /*(4)如果此次getEvents()调用没能获取事件,说明mPendingEventItems中没有事件可用,
           于是执行epoll_wait()函数等待新的事件到来,将结果存储到mPendingEventItems里,并重
           置mPendingEventIndex为0 */
       mPendingEventIndex = 0;
       // ...
        intpollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS,timeoutMillis);
       // ...
        mPendingEventCount= size_t(pollResult);
        // 从epoll_wait()中得到新的事件后,重新循环,对新事件进行处理
    }
    // 返回本次getEvents()调用所读取的事件数量
    return event - buffer;
}

2.1 上面getEvents()返回了mEventBuffer之后,初步的处理:

void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {
    for (const RawEvent* rawEvent = rawEvents; count;) {  // 遍历获取到的event数组  
        int32_t type = rawEvent->type;
        size_t batchSize = 1;
        // 如果是常规的event事件,FIRST_SYNTHETIC_EVENT = DEVICE_ADDED (0x10000000)
        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;
            }
            /* 把这次获取到的event数组中属于同一批次的,进一步处理,判定条件就是:常规event以
               及是属于同一设备 */
            processEventsForDeviceLocked(deviceId, rawEvent, batchSize);  // 见 2.3
        } else {
            // 这里就是3种特殊的 event 类型,例如有时候打开设备的时候会有这个 ADD 事件
            switch (rawEvent->type) {
            case EventHubInterface::DEVICE_ADDED:
                addDeviceLocked(rawEvent->when, rawEvent->deviceId);  // 见 2.2
                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;
            }
        }
        // 如果再上面没有处理完event数组中的成员,那么依次继续  
        count -= batchSize;
        rawEvent += batchSize;
    }
}

2.2 添加设备:addDeviceLocked(rawEvent->when, rawEvent->deviceId);
在EventHub中提到将事件封装成 RawEvent结构体,其中的 type 就是事件的类型,通过上面的代码可以知道一共有四种类型,接下来挑选 DEVICE_ADDED 事件看看。

void InputReader::addDeviceLocked(nsecs_t when, int32_t deviceId) {
    ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
    if (deviceIndex >= 0) {
        return;
    }
    // 这里取之前在EventHub中解析出来的设备相关参数 
    InputDeviceIdentifier identifier = mEventHub->getDeviceIdentifier(deviceId);
    // 在open设备时 初始化,代表类型
    // open设备调用的方法:EventHub::openDeviceLocked(const charchar *devicePath)
    uint32_t classes = mEventHub->getDeviceClasses(deviceId);
    int32_t controllerNumber = mEventHub->getDeviceControllerNumber(deviceId);
    // 这里又创建一个 InputDervice,会根据classes选择对应的事件处理mapper与当前的设备绑定
    InputDevice* device = createDeviceLocked(deviceId, controllerNumber, identifier, classes);
    device->configure(when, &mConfig, 0);
    device->reset(when);

    mDevices.add(deviceId, device);  // 添加这个 InputDevice  
    bumpGenerationLocked();
}

2.3 常规 event 的处理:

    // InputReader.cpp 中 processEventsForDeviceLocked() 方法:
    void InputReader::processEventsForDeviceLocked(int32_t deviceId,  
            const RawEvent* rawEvents, size_t count) {  
        ssize_t deviceIndex = mDevices.indexOfKey(deviceId);  
        if (deviceIndex < 0) {  
            return;  
        }  

         // 这里根据id 取出上面添加进去的inputdevice  
        InputDevice* device = mDevices.valueAt(deviceIndex);
        if (device->isIgnored()) {  
            return;  
        }  
      
        device->process(rawEvents, count); // 这里调用了一个process的函数  
    }  


    // InputReader.cpp 中 process() 方法:
    void InputDevice::process(const RawEvent* rawEvents, size_t count) {  
        // 这里有个map个数,在create时 会根据classes类型去匹配处理map,一般都是匹配一个
        size_t numMappers = mMappers.size(); 
        // 遍历事件数组,依次去处理  
        for (const RawEvent* rawEvent = rawEvents; count--; rawEvent++) {   
      
            if (mDropUntilNextSync) {  
                if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {  
                    mDropUntilNextSync = false;  
                } else {  
                    ALOGD("Dropped input event while waiting for next input sync.");  
                }  
            } 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 {  
                for (size_t i = 0; i < numMappers; i++) {  
                    InputMapper* mapper = mMappers[i];  
                    // 调用处理 mapper的process 函数,开始分发流程,见 3.1
                    mapper->process(rawEvent); 
                }  
            }  
        }  
    }  

3. input事件分发:mapper->process(rawEvent)
在 2.2 中提到 createDeviceLocked() 这个方法给device添加绑定Mapper的,如下代码所示。

InputDevice* InputReader::createDeviceLocked(int32_t deviceId, int32_t controllerNumber,
        const InputDeviceIdentifier& identifier, uint32_t classes) {
    InputDevice* device = new InputDevice(&mContext, deviceId, bumpGenerationLocked(),
            controllerNumber, identifier, classes);

    // External devices.
    if (classes & INPUT_DEVICE_CLASS_EXTERNAL) {
        device->setExternal(true);
    }

    // ...
    // Touchscreens and touchpad devices.
    if (classes & INPUT_DEVICE_CLASS_TOUCH_MT) {
        device->addMapper(new MultiTouchInputMapper(device));
    } else if (classes & INPUT_DEVICE_CLASS_TOUCH) {
        device->addMapper(new SingleTouchInputMapper(device));
    }

    return device;
}

3.1 分发前的处理:
我们就以SingleTouchInputMapper为例

void SingleTouchInputMapper::process(const RawEvent* rawEvent) {
    TouchInputMapper::process(rawEvent);  // 调用父类的process
    mSingleTouchMotionAccumulator.process(rawEvent); 
}


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

/**
以下语句均是将输入事件信息转存至类成员变量中:
    mCursorButtonAccumulator.process(rawEvent);
    mCursorScrollAccumulator.process(rawEvent);
    mTouchButtonAccumulator.process(rawEvent);
    mSingleTouchMotionAccumulator.process(rawEvent); 
**/

输入事件分发的关键在 TouchInputMapper::sync() 方法中:这个同步函数比较长,下面是简化后的代码,我们之关注一下事件的分发就行了;

void TouchInputMapper::sync(nsecs_t when) {
    // Sync button state.
    mCurrentButtonState = mTouchButtonAccumulator.getButtonState()
            | mCursorButtonAccumulator.getButtonState();

    // Sync scroll state.
    mCurrentRawVScroll = mCursorScrollAccumulator.getRelativeVWheel();
    mCurrentRawHScroll = mCursorScrollAccumulator.getRelativeHWheel();
    mCursorScrollAccumulator.finishSync();

    // Sync touch state.
    bool havePointerIds = true;
    mCurrentRawPointerData.clear();
    /*调用子类的syncTouch,这里是 SingleTouchMotionAccumulator的syncTouch(),
      更新ABS 坐标值,我这里是把数据存入到mCurrentRawPointerData中供下面cook */
    syncTouch(when, &havePointerIds);

    // Reset state that we will compute below.
    mCurrentFingerIdBits.clear();
    mCurrentStylusIdBits.clear();
    mCurrentMouseIdBits.clear();
    mCurrentCookedPointerData.clear();  // 先清除一下

    if (mDeviceMode == DEVICE_MODE_DISABLED) {
        // Drop all input if the device is disabled.
        mCurrentRawPointerData.clear();
        mCurrentButtonState = 0;
    } else {
        if (mDeviceMode == DEVICE_MODE_POINTER) {
            PointerUsage pointerUsage = mPointerUsage;
            dispatchPointerUsage(when, policyFlags, pointerUsage);  
        } else {
            if (mDeviceMode == DEVICE_MODE_DIRECT
                    && mConfig.showTouches && mPointerController != NULL) {
                mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_SPOT);                
                mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
                mPointerController->setButtonState(mCurrentButtonState);
                mPointerController->setSpots(mCurrentCookedPointerData.pointerCoords,
                        mCurrentCookedPointerData.idToIndex,
                        mCurrentCookedPointerData.touchingIdBits);
            }
            // 分发事件,这里的三个方法最终都回调用 dispatchMotion()
            //            
            dispatchHoverExit(when, policyFlags);
            dispatchTouches(when, policyFlags);
            dispatchHoverEnterAndMove(when, policyFlags);
        }

           // 之后的代码是一些数据保存之类的操作
           // ...
    }
    // ...
    mCurrentRawVScroll = 0;
    mCurrentRawHScroll = 0;
}

dispatchMotion():

void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source,
        int32_t action, 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) {
    // ...
    NotifyMotionArgs args(when, getDeviceId(), source, policyFlags,
            action, flags, metaState, buttonState, edgeFlags,
            mViewport.displayId, pointerCount, pointerProperties, pointerCoords,
            xPrecision, yPrecision, downTime);
    // 这里的 getListener() 就是我们之前提到的 传入mDispatcher作为回调,只是做了进一步封装;
    getListener()->notifyMotion(&args);  
}

3.2 InputDispatcher 和 InputDispatcherThread:分发输入事件
InputDispatcherThread 和之前的 InputReaderThread 一样,先看看 threadLoop()方法;

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


// dispatchOnce() 方法:
void InputDispatcher::dispatchOnce() {
    nsecs_t nextWakeupTime = LONG_LONG_MAX;
    { 
        AutoMutex _l(mLock);
        mDispatcherIsAliveCondition.broadcast();

        // 第一次进来时mCommandQueue是空,能进入此分支;
·       // 然后在 dispatchOnceInnerLocked() 方法中 return;
        // 最终在 mLooper->pollOnce(timeoutMillis) 休眠等待; 
        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);
    // looper进入休眠等待,wake() 方法唤醒(向fd中写入数据就会唤醒);
    mLooper->pollOnce(timeoutMillis);  
}

上面的 dispatcherOnce() 方法在第一次进入时,会进入休眠状态,那么输入事件的时候是如何调用的呢?这就是我们 3.1 中的 getListener()->notifyMotion(&args),也就是Dispatcher的 notifyMotion() 方法:

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

    if (!validateMotionEvent(args->action, args->pointerCount, args->pointerProperties)) {
        return;   // 校验MotionEvent的参数
    }
    // ...
    bool needWake;
    { // acquire lock
        mLock.lock();

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

            MotionEvent event;
            event.initialize(args->deviceId, args->source, args->action, 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();
        }

        // Just enqueue a new motion event.
        // 解析成一个新的MotionEntry:newEntry        
        MotionEntry* newEntry = new MotionEntry(args->eventTime,
                args->deviceId, args->source, policyFlags,
                args->action, 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

    if (needWake) {
        mLooper->wake();  // 如果需要唤醒InputDispatcher线程, 则调用Looper的唤醒方法
    }
}

加入输入事件队列:enqueueInboundEventLocked(EventEntry* entry) 方法

bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {
    bool needWake = mInboundQueue.isEmpty();  // 如果队列为空 , 则需要唤醒
    mInboundQueue.enqueueAtTail(entry);  // 插入到mInboundQueue队列尾部
    // ...
    return needWake;
}

InputDispatcherThread::threadLoop() 会一直执行mDispatcher->dispatchOnce() 方法,唤醒 looper后,在dispatchOnce() 方法中继续调用 dispatchOnceInnerLocked(&nextWakeupTime)来处理输入事件,下面是这个方法的代码:

void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
    nsecs_t currentTime = now();
    // 判断事件分发是否允许,也就是在未开机、IMS未成功启动、关机等状态下是不可用的,默认值是false
    if (!mDispatchEnabled) {  
        resetKeyRepeatLocked();  //重置重复按键次数
    }
    //判断分发线程是否被冻结,是否可以配发,默认值是false
    if (mDispatchFrozen) {
        return;
    }
    //判断此处是不是正在切换应用,以便在home和endcall按键到来时,及时丢弃之前的事件,而直接响应特殊键
    bool isAppSwitchDue = mAppSwitchDueTime <= currentTime;
    if (mAppSwitchDueTime < *nextWakeupTime) {
        *nextWakeupTime = mAppSwitchDueTime;
    }

    // Ready to start a new event.
    //mPendingEvent是即将要被配发的事件,派发完成置为null,此处是判断是否正在配发事件
    if (! mPendingEvent) {
        if (mInboundQueue.isEmpty()) {  // 如果Event队列为空的话
            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;
            }

            // Synthesize a key repeat if appropriate.
            if (mKeyRepeatState.lastKeyEntry) {
                if (currentTime >= mKeyRepeatState.nextRepeatTime) {
                    mPendingEvent = synthesizeKeyRepeatLocked(currentTime);
                } else {
                    if (mKeyRepeatState.nextRepeatTime < *nextWakeupTime) {
                        *nextWakeupTime = mKeyRepeatState.nextRepeatTime;
                    }
                }
            }

            // Nothing to do if there is no pending event.
            if (!mPendingEvent) {   // 如果没有要处理的事件 , 则返回
                return;
            }
        } else {
            // Inbound queue has at least one entry.
            mPendingEvent = mInboundQueue.dequeueAtHead();  // 有Event时,取出第一个Event;
            traceInboundQueueLengthLocked();
        }

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

       // 重置此次事件分发的ANR超时时间,如果超过5秒,就会产生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) {
     // 处理Configuration Change消息 , 即屏幕旋转等等
    case EventEntry::TYPE_CONFIGURATION_CHANGED: {  
        ConfigurationChangedEntry* typedEntry =
                static_cast(mPendingEvent);
        done = dispatchConfigurationChangedLocked(currentTime, typedEntry);
        dropReason = DROP_REASON_NOT_DROPPED; // configuration changes are never dropped
        break;
    }
    // 处理设备重置消息 
    case EventEntry::TYPE_DEVICE_RESET: { 
        DeviceResetEntry* typedEntry =
                static_cast(mPendingEvent);
        done = dispatchDeviceResetLocked(currentTime, typedEntry);
        dropReason = DROP_REASON_NOT_DROPPED; // device resets are never dropped
        break;
    }
    // 处理Key按键消息
    case EventEntry::TYPE_KEY: {
        KeyEntry* typedEntry = static_cast(mPendingEvent);
        if (isAppSwitchDue) {
            if (isAppSwitchKeyEventLocked(typedEntry)) {
                resetPendingAppSwitchLocked(true);
                isAppSwitchDue = false;
            } else if (dropReason == DROP_REASON_NOT_DROPPED) {
                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;
        }
        done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);
        break;
    }
    // 判断时触屏事件时:
    case EventEntry::TYPE_MOTION: {  
        MotionEntry* typedEntry = static_cast(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;
        }
        done = dispatchMotionLocked(currentTime, typedEntry,
                &dropReason, nextWakeupTime);  // 分发事件
        break;
    }

    default:
        ALOG_ASSERT(false);
        break;
    }

    if (done) {
        if (dropReason != DROP_REASON_NOT_DROPPED) {
            dropInboundEventLocked(mPendingEvent, dropReason); // 从配发队列里面丢弃事件
        }

        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) {
    bool isPointerEvent = entry->source & AINPUT_SOURCE_CLASS_POINTER;
    // 找到目标窗口
    Vector inputTargets;

    bool conflictingPointerActions = false;
    int32_t injectionResult;
    if (isPointerEvent) {
        // 如果是手指事件的话 ,则找到Touch窗口:关键代码1
        injectionResult = findTouchedWindowTargetsLocked(currentTime,
                entry, inputTargets, nextWakeupTime, &conflictingPointerActions);
    } else {
        // 如果不是手指触摸事件 , 比如轨迹球事件的话 , 则找到Focus窗口
        injectionResult = findFocusedWindowTargetsLocked(currentTime,
                entry, inputTargets, nextWakeupTime);
    }
    // 如果找到窗口失败, 返回
    if (injectionResult == INPUT_EVENT_INJECTION_PENDING) {
        return false;
    }
    // 开始向窗口分发事件:关键代码2
    dispatchEventLocked(currentTime, entry, inputTargets);
    return true;
}

(关键代码1)找到Touch窗口findFocusedWindowTargetsLocked():也是这个方法限制了不同app在不同窗口层级时,上面的app不能把触屏事件分发给下面的app;

int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
        const MotionEntry* entry, Vector& inputTargets, nsecs_t* nextWakeupTime,
        bool* outConflictingPointerActions) {
    // ...
    if (newGesture || (isSplit && maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN)) {
       //从MotionEntry中获取坐标点
        int32_t pointerIndex = getMotionEventActionPointerIndex(action);
        int32_t x = int32_t(entry->pointerCoords[pointerIndex].
                getAxisValue(AMOTION_EVENT_AXIS_X));
        int32_t y = int32_t(entry->pointerCoords[pointerIndex].
                getAxisValue(AMOTION_EVENT_AXIS_Y));        
        sp newTouchedWindowHandle;
        bool isTouchModal = false;
        size_t numWindows = mWindowHandles.size();//1
        // 遍历窗口,找到触摸过的窗口和窗口之外的外部目标
        for (size_t i = 0; i < numWindows; i++) {//2
            //获取InputDispatcher中代表窗口的windowHandle 
            sp windowHandle = mWindowHandles.itemAt(i);
            //得到窗口信息windowInfo 
            const InputWindowInfo* windowInfo = windowHandle->getInfo();
            if (windowInfo->displayId != displayId) {
            //如果displayId不匹配,开始下一次循环
                continue; 
            }
            //获取窗口的flag
            int32_t flags = windowInfo->layoutParamsFlags;
            //如果窗口时可见的
            if (windowInfo->visible) {
               //如果窗口的flag不为FLAG_NOT_TOUCHABLE(窗口是touchable)
                if (! (flags & InputWindowInfo::FLAG_NOT_TOUCHABLE)) {
                   // 如果窗口是focusable或者flag不为FLAG_NOT_FOCUSABLE,则说明该窗口是"可触摸模式"
                    isTouchModal = (flags & (InputWindowInfo::FLAG_NOT_FOCUSABLE
                            | InputWindowInfo::FLAG_NOT_TOUCH_MODAL)) == 0;//3
                   //如果窗口是 可触摸模式或者坐标点落在窗口之上(找到目标窗口)
                    if (isTouchModal || windowInfo->touchableRegionContainsPoint(x, y)) {
                        newTouchedWindowHandle = windowHandle;//4
                        break; // found touched window, exit window loop
                    }
                }
                if (maskedAction == AMOTION_EVENT_ACTION_DOWN
                        && (flags & InputWindowInfo::FLAG_WATCH_OUTSIDE_TOUCH)) {
                    //将符合条件的窗口放入TempTouchState中,以便后续处理。
                    mTempTouchState.addOrUpdateWindow(
                            windowHandle, InputTarget::FLAG_DISPATCH_AS_OUTSIDE, BitSet32(0));//5
                }
            }
        // ...
        }
    } else{
        // ...
    }
    // ...
    // 把临时存放窗口的 TempTouchState 加入到全局的 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);
    }
   // ...
}

(关键代码2)开始向窗口分发事件 dispatchEventLocked(currentTime, entry, inputTargets):

void InputDispatcher::dispatchEventLocked(nsecs_t currentTime,
        EventEntry* eventEntry, const Vector& inputTargets) {

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

    pokeUserActivityLocked(eventEntry);

    for (size_t i = 0; i < inputTargets.size(); i++) {  // 遍历 inputTargets
        const InputTarget& inputTarget = inputTargets.itemAt(i);
        
        ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel);
        if (connectionIndex >= 0) {
            // 获取跨进程通讯的连接;
            sp connection = mConnectionsByFd.valueAt(connectionIndex);
            // 通过拿到的连接进行分发;
            prepareDispatchCycleLocked(currentTime, connection, eventEntry, &inputTarget);
        } else {
            // ...
        }
    }
}

prepareDispatchCycleLocked(currentTime, connection, eventEntry, &inputTarget) ->
enqueueDispatchEntriesLocked(currentTime, connection, splitMotionEntry, inputTarget) ->
startDispatchCycleLocked(currentTime, connection)

void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
        const sp& connection) {
#if DEBUG_DISPATCH_CYCLE
    ALOGD("channel '%s' ~ startDispatchCycle",
            connection->getInputChannelName());
#endif

    while (connection->status == Connection::STATUS_NORMAL&& !connection->outboundQueue.isEmpty()) {
        DispatchEntry* dispatchEntry = connection->outboundQueue.head;
        dispatchEntry->deliveryTime = currentTime;

        // Publish the event.
        status_t status;
        EventEntry* eventEntry = dispatchEntry->eventEntry;
        switch (eventEntry->type) {
        case EventEntry::TYPE_KEY: {
            // ... key 事件
            break;
        }

        case EventEntry::TYPE_MOTION: {
            MotionEntry* motionEntry = static_cast(eventEntry);

            PointerCoords scaledCoords[MAX_POINTERS];
            const PointerCoords* usingCoords = motionEntry->pointerCoords;

            // Set the X and Y offset depending on the input source.
            float xOffset, yOffset, scaleFactor;
            if ((motionEntry->source & AINPUT_SOURCE_CLASS_POINTER)
                    && !(dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS)) {
                scaleFactor = dispatchEntry->scaleFactor;
                xOffset = dispatchEntry->xOffset * scaleFactor;
                yOffset = dispatchEntry->yOffset * scaleFactor;
                if (scaleFactor != 1.0f) {
                    for (uint32_t i = 0; i < motionEntry->pointerCount; i++) {
                        scaledCoords[i] = motionEntry->pointerCoords[i];
                        scaledCoords[i].scale(scaleFactor);
                    }
                    usingCoords = scaledCoords;
                }
            } else {
                xOffset = 0.0f;
                yOffset = 0.0f;
                scaleFactor = 1.0f;

                // We don't want the dispatch target to know.
                if (dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS) {
                    for (uint32_t i = 0; i < motionEntry->pointerCount; i++) {
                        scaledCoords[i].clear();
                    }
                    usingCoords = scaledCoords;
                }
            }

            // Publish the motion event. 
            // 通过连接分发给远程端;
            status = connection->inputPublisher.publishMotionEvent(dispatchEntry->seq,
                    motionEntry->deviceId, motionEntry->source,
                    dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags,
                    motionEntry->edgeFlags, motionEntry->metaState, motionEntry->buttonState,
                    xOffset, yOffset,
                    motionEntry->xPrecision, motionEntry->yPrecision,
                    motionEntry->downTime, motionEntry->eventTime,
                    motionEntry->pointerCount, motionEntry->pointerProperties,
                    usingCoords);
            break;
        }

        // Check the result.
        if (status) {
            // ...
            return;
        }

        // Re-enqueue the event on the wait queue.
        connection->outboundQueue.dequeue(dispatchEntry);
        traceOutboundQueueLengthLocked(connection);
        connection->waitQueue.enqueueAtTail(dispatchEntry);
        traceWaitQueueLengthLocked(connection);
    }
}

你可能感兴趣的:(framework学习笔记15. Input 输入事件(1))