View机制深入学习 事件处理机制一

Posted 流云易采

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了View机制深入学习 事件处理机制一相关的知识,希望对你有一定的参考价值。

以TouchEvent为主,看一下View和ViewGroup内部是如何处理Input Events的;
首先来看事件的产生来源:

一、获取事件:

事件的来源可以分为“软件”,“硬件”两种;
主要的事件包含有:
按键事件(KeyEvent) :即物理按键按下产生的事件,相关的常用物理按键一般有HOME,BACK等
触摸事件(TouchEvent):
鼠标事件(MouseEvent)、轨迹球事件(TrackBallEvent)(这两个已经不常见);

针对所有事件的共性抽象出了InputEvent接口;其有两个子类:KeyEvent,MotionEvent;

1、事件的投递流程:

1>源信息采集
对“硬件源”产生的原始信息进行收集;它需要Linux内核驱动的支持,android系统通过/dev/input下的节点来访问当前发生的事件。
2>前期处理
对收集到信息进行筛选以及格式转化
3>WMS分配
WMS是窗口的Manager,同时也是InputEvent的派发者。
4>应用程序处理
WMS会先把事件传递到对应ViewRootImpl,ViewRootImpl分发事件,传递给相应的DecorView,DecorView在调用Activity中的Window.Callback将事件传递给Activity;然后Activity在通过dispatchTouchEvent分发事件,下面就来到熟悉的View事件分发机制;具体见《View机制深入学习(四)View的事件分发机制》

2、InputManagerService启动:

InputManagerService同样也是有SystemServer进程启动,这个在Android启动过程——init.rc,Zygote,SystemServer中已经提到过,
系统启动后创建init进程(pid=1),init进程创建出Zygote进程,然后Zygote进程孵化出SystemServer进程,在SystemServer进程中创建IMS:

/** @path: \\frameworks\\base\\services\\java\\com\\android\\server\\SystemServer.java */
class ServerThread extends Thread 
    @Override
    public void run() 
        // 可以看到IMS和WMS是紧密相关的
        ......
        // @value InputManagerService inputManager
        inputManager = new InputManagerService(context, wmHandler);

        Slog.i(TAG, "Window Manager");
        // @value WindowManagerService wm
        wm = WindowManagerService.main(context, power, display, inputManager,
                uiHandler, wmHandler,
                factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL,
                !firstBoot, onlyCore);
        ServiceManager.addService(Context.WINDOW_SERVICE, wm);
        ServiceManager.addService(Context.INPUT_SERVICE, inputManager);

        ActivityManagerService.self().setWindowManager(wm);

        inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
        inputManager.start();
        .....
    

3、InputMangerService:

/** \\frameworks\\base\\services\\core\\java\\com\\android\\server\\input\\InputManagerService.java **/
public class InputManagerService extends IInputManager.Stub implements Watchdog.Monitor 
    // 指向native端IMS类对象的地址
    private final long mPtr;

    public InputManagerService(Context context) 
        this.mContext = context;
        this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());

        mUseDevInputEventForAudioJack = context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);

        // 创建native IMS对象
        mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());

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

可以看到Java层的IMS实际上只是对Native层的InputManager的一层包装;其创建主要是native层进行创建,并把native层的InputManager地址赋值给InputManagerService的mPtr变量;
而且注意nativeInit中传入了Looper中的MessageQueue变量;

4、native层的InputManagerService——NativeInputManager类:

/** \\frameworks\\base\\services\\core\\jni\\com_android_server_input_InputManagerService.cpp **/
class NativeInputManager : public virtual RefBase,
public virtual InputReaderPolicyInterface,
public virtual InputDispatcherPolicyInterface,
public virtual PointerControllerPolicyInterface

static jlong nativeInit(JNIEnv* env, jclass clazz,
                        jobject serviceObj, jobject contextObj, jobject messageQueueObj) 
    // 创建一个Message Queue
    sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
    if (messageQueue == NULL) 
        jniThrowRuntimeException(env, "MessageQueue is not initialized.");
        return 0;
    

    // 可以看到NativeInputManager中包含有一个Looper,用以进行事件分派
    NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
            messageQueue->getLooper());
    im->incStrong(0);
    // 返回创建的IMS实例对象的地址(强制转化为long类型)
    return reinterpret_cast<jlong>(im);

可以看到首先通过android_os_MessageQueue_getMessageQueue函数获取到本地端的MessageQueue,这个在Handler机制中的本地解析《Handler机制深入解析》中已经提到,该NativeMessageQueue对象在java层创建Looper时创建实例,然后将地址指针赋值为Looper对应的MessageQueue中的ptr变量中,这里根据指针来获取该NativeMessageQueue对象;
根据NativeMessageQueue对象获取其中对应的Looper(native),用以创建NativeInputManger;来看NativeInputManager的构造函数:

5、NativeInputManager#NativeInputManager:

/** \\frameworks\\base\\services\\core\\jni\\com_android_server_input_InputManagerService.cpp **/
NativeInputManager::NativeInputManager(jobject contextObj,
                                       jobject serviceObj, const sp<Looper>& looper) :
        mLooper(looper), mInteractive(true) 
    JNIEnv* env = jniEnv();

    // 全局引用
    mContextObj = env->NewGlobalRef(contextObj);
    mServiceObj = env->NewGlobalRef(serviceObj);

    
        AutoMutex _l(mLock);
        mLocked.systemUiVisibility = ASYSTEM_UI_VISIBILITY_STATUS_BAR_VISIBLE;
        mLocked.pointerSpeed = 0;
        mLocked.pointerGesturesEnabled = true;
        mLocked.showTouches = false;
    

    // 创建EventHUb
    sp<EventHub> eventHub = new EventHub();
    // 创建InputManager实例
    mInputManager = new InputManager(eventHub, this, this);

NativeInputManager中保存了Looper(native)实例;并且创建了EventHub,以及InputManager两个重要的对象;
EventHub从名字就可以看出,它是用来收集以及存储外部的输入事件的;
而InputManager则是对Event事件进行处理分发;
先来看EventHub:

(一)EventHub:

/*\\frameworks\\native\\services\\inputflinger\\EventHub*/
static const char *DEVICE_PATH = "/dev/input";
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);

    // 创建epoll对象
    mEpollFd = epoll_create(EPOLL_SIZE_HINT);

    // 采用inotify机制监听文件或目录的移动、读取、写入或删除等事件
    // 创建一个inotify对象
    mINotifyFd = inotify_init();
    // 把监控项添加到mINotifyFd对象的监控列表中
    // 这里监听的文件路径为"/dev/input"
    int result = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE);

    struct epoll_event eventItem;
    memset(&eventItem, 0, sizeof(eventItem));
    eventItem.events = EPOLLIN;
    eventItem.data.u32 = EPOLL_ID_INOTIFY;
    // 把inotify对象mINotifyFd添加到epoll对象的兴趣列表中,此处采用inotify与epoll机制结合起来检查文件
    result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem);

    int wakeFds[2];
    // 创建pipe
    result = pipe(wakeFds);

    mWakeReadPipeFd = wakeFds[0];
    mWakeWritePipeFd = wakeFds[1];
    // 设置为非阻塞
    result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);
    result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK);

    eventItem.data.u32 = EPOLL_ID_WAKE;
    // 添加到epoll的兴趣列表中
    result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, &eventItem);

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

在前面进行了一系列的变量的初始化;
然后epoll_create创建了一个epoll对象,可以看到和Handler中一样,IMS中也用到了epoll机制进行监听;
而后可以看到IMS是INotify机制和Epoll机制同时使用的:inotify_init创建iNotify对象,inotify_add_watch则将”/dev/input”路径添加到监听列表中;当”/dev/input”中文件发生变化,将会产生响应;
了解INotifiy文件系统监听机制:
《inotify – Linux 2.6 内核中的文件系统变化通知机制》
《Inotify: 高效、实时的Linux文件系统事件监控框架》
然后将iNotify对象添加到Epoll的兴趣列表中,进行监听;
然后同Handler机制,创建一个Pipe,然后设置为非阻塞形式,然后添加到epoll的兴趣列表中;下面就注意在何时调用epoll_wait来开启监听即可;这里仅进行了初始化;

(二)InputManager:

1)构造函数:

/** \\frameworks\\native\\services\\inputflinger\\InputManager.cpp **/
class InputManagerInterface : public virtual RefBase 
private:
    sp<InputReaderInterface> mReader;
    sp<InputReaderThread> mReaderThread;

    sp<InputDispatcherInterface> mDispatcher;
    sp<InputDispatcherThread> mDispatcherThread;

    // 构造函数
    InputManager::InputManager(
            const sp<EventHubInterface>& eventHub,
            const sp<InputReaderPolicyInterface>& readerPolicy,
            const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) 
        // 创建InputDispatcher
        mDispatcher = new InputDispatcher(dispatcherPolicy);
        // 创建InputReader
        mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
        initialize();
    

    /*** 进行初始化 **/
    void InputManager::initialize() 
        // 创建两个Thread的实例
        mReaderThread = new InputReaderThread(mReader);
        mDispatcherThread = new InputDispatcherThread(mDispatcher);
    

;

InputManager中传入了前面创建的EventHub对象;然后初始化了两个中重要的类,InputDispatcher,以及InputReader;
显然从名字可以看出 InputReader用来读取EventHub中的事件,然后通过InputDiapatcher进行分发(InputReader中持有InputDisptcher的引用);

先看InputDispatcher:

1.1)InputDispatcher:

继承关系:

class InputDispatcher : public InputDispatcherInterface
class InputDispatcherInterface : public virtual RefBase, public InputListenerInterface

构造函数:

/** \\frameworks\\native\\services\\inputflinger\\InputDispatcher.cpp **/
InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy) :
    mPolicy(policy),
    mPendingEvent(NULL), mAppSwitchSawKeyDown(false), mAppSwitchDueTime(LONG_LONG_MAX),
    mNextUnblockedEvent(NULL),
    mDispatchEnabled(false), mDispatchFrozen(false), mInputFilterEnabled(false),
    mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE) 
    // 可以看到这里创建了一个Looper
    mLooper = new Looper(false);

    mKeyRepeatState.lastKeyEntry = NULL;

    policy->getDispatcherConfiguration(&mConfig);

在构造函数中创建了一个Looper(native),注意这里是新创建了一个Looper对象,和ThreadLocal中该线程中的Looper是没有关系的;
再来看InputReader

1.2)InputReader:
class InputReader : public InputReaderInterface
class InputReaderInterface : public virtual RefBase

构造函数:

/** \\frameworks\\native\\services\\inputflinger\\InputReader.cpp **/
InputReader::InputReader(const sp<EventHubInterface>& eventHub, // 前面提到的创建的EventHub
        const sp<InputReaderPolicyInterface>& policy,
        const sp<InputListenerInterface>& listener) :           // 即传入进来的InputDispatcher
        mContext(this), mEventHub(eventHub), mPolicy(policy),   // 一系列初始化
        mGlobalMetaState(0), mGeneration(1),
        mDisableVirtualKeysTimeout(LLONG_MIN), mNextTimeout(LLONG_MAX),
        mConfigurationChangesToRefresh(0) 
        // 创建一个QueuedInputListener对象,赋值给mQueuedListener
    mQueuedListener = new QueuedInputListener(listener);

     // acquire lock
        AutoMutex _l(mLock);

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

InputReader中包含了前面创建的EventHub,以及用以分发事件的InputDispatcher;在InputReader内部,将其封装成了QueuedInputListener类;

继续InputManager构造函数中内容,initialize进行初始化:

2)InputManager#initialize:

/*** 进行初始化 **/
void InputManager::initialize() 
// 创建两个Thread的实例
mReaderThread = new InputReaderThread(mReader);
    mDispatcherThread = new InputDispatcherThread(mDispatcher);

新创建了两个对象,这两个类都是继承Thread的,即对应地使用InputReader,以及InputDispatcher为参数创建了两个线程;
分别来看:

2.1> InputReaderThread:

2.1.1)InputReaderThread类:

/** \\frameworks\\native\\services\\inputflinger\\InputReader.h **/
/** 无限循环从event hub中读取event,然后读取processes他们  */
class InputReaderThread : public Thread 
    public:
    InputReaderThread(const sp<InputReaderInterface>& reader);
    virtual ~InputReaderThread();

    private:
    sp<InputReaderInterface> mReader;
    /** 继承Thread的子类必须实现该函数,因为这个其实是Thread的真正执行函数 **/
    // Derived class must implement threadLoop(). The thread starts its life
    // here. There are two ways of using the Thread object:
    // 1) loop: if threadLoop() returns true, it will be called again if
    //          requestExit() wasn't called.
    // 2) once: if threadLoop() returns false, the thread will exit upon return.
    virtual bool threadLoop();
;

可以看到InputReaderThread是一个Thread类,它的线程函数入口为threadLoop;

2.1.2)InputReaderThread类构造函数:

/** \\frameworks\\native\\services\\inputflinger\\InputReader.cpp **/
    InputReaderThread::InputReaderThread(const sp<InputReaderInterface>& reader) :
    Thread(/*canCallJava*/true), mReader(reader) 
        // 这里初始化重要变量sp<InputReaderInterface> mReader
    

    bool InputReaderThread::threadLoop() 
        // 调用mReader中的loopOnce函数,可以看出InputReaderInterface是该类的核心
        mReader->loopOnce();
        return true;
    

InputReaderThread的核心逻辑为调用InputReader的loopOnce函数;暂且停在这里,因为Thread只是创建,并未运行,等分析到具体运行代码时再作分析;

2.2>InputDispatcherThread

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

class InputDispatcherThread : public Thread 
    public:
    explicit InputDispatcherThread(const sp<InputDispatcherInterface>& dispatcher);
    ~InputDispatcherThread();

    private:
    virtual boolthreadLoop();

    sp<InputDispatcherInterface> mDispatcher;
;

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

该类同样是一个Thread,其主要运行逻辑即调用InputDispatcher中的dispatchOnce函数;

回到InputManagerService在SystemServer进程中的创建过程知道,接下来创建WindowManagerService,然后将InputManagerService实例传递给WMS,然后调用InputManagerService.start开始工作。

7、InputManagerService#start:

/** \\frameworks\\base\\services\\core\\java\\com\\android\\server\\input\\InputManagerService.java **/
public void start() 
    ......
    nativeStart(mPtr);
    // Add ourself to the Watchdog monitors.
    Watchdog.getInstance().addMonitor(this);
    ......

private static native void nativeStart(long ptr);

可以看到start仅是对nativeStart本地方法进行封装,继续通过JNI来调用本地端的start函数;注意这里创建了WatchDog看门狗线程,并且把InputManagerService实例添加到WatchDog的监听;系统创建看门狗线程,每隔一段时间向管道中写入数据唤醒InputReader线程(后面会提到)去读取事件,看门狗WatchDog实际上也是一个线程,只不过会定时发送消息给InputReader线程读取输入事件。

8、NativeInputManager#nativeStart:

/** \\frameworks\\base\\services\\core\\jni\\com_android_server_input_InputManagerService.cpp **/
static void nativeStart(JNIEnv* env, jclass clazz, jlong ptr) 
    // ptr为创建的IMS实例的地址,这里将其强制转化成为NativeInputManager类
    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);

    // 这里进一步调用InputManager的star方法
    status_t result = im->getInputManager()->start();
    if (result) 
        jniThrowRuntimeException(env, "Input manager could not be started.");
    

// @value sp<InputManager> mInputManager;
inline sp<InputManager> getInputManager() const  return mInputManager; 

可以看到这里进一步调用了InputManager的start方法;IMS在Native层的主要实现实体其实是InputManager。

9、InputManager#start:

/** \\frameworks\\native\\services\\inputflinger\\InputManager.cpp **/
class InputManagerInterface : public virtual RefBase 
    private:
    sp<InputReaderInterface> mReader;
    sp<InputReaderThread> mReaderThread;

    sp<InputDispatcherInterface> mDispatcher;
    sp<InputDispatcherThread> mDispatcherThread;

    // start函数
    status_t InputManager::start() 
        // 可以看到这里会开启两个线程mDispatcherThread,与mReaderThread
        // 分别对应InputReaderThread,InputDispatcherThread
        status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);
        ......
        result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);
        if (result) 
            mDispatcherThread->requestExit();
            return result;
        
        return OK;
    
;

回到InputManager中来,来看start函数中所做的工作,在start中调用两个thread的run函数正是开启线程;由Thread的线程入口为threadLoop;前面已经提到了这两个Thread的入口函数,这里来看其中的具体工作逻辑;

10、InputDispatcherThread&InputReaderThread

InputDispatcherThread#threadLoop:
由前面知InputDispatcherThread中主要通过调用InputDispatcher的dispathOnce来实现的;

1)InputDispatcher::dispatchOnce:

/** \\frameworks\\native\\services\\inputflinger\\InputDispatcher.cpp **/
void InputDispatcher::dispatchOnce() 
    nsecs_t nextWakeupTime = LONG_LONG_MAX;
     // acquire lock
        AutoMutex _l(mLock);
        mDispatcherIsAliveCondition.broadcast();

        // 在没有等待的commands事运行一个dispatch loop,这个loop之后可能enqueue commands
        if (!haveCommandsLocked()) 
            dispatchOnceInnerLocked(&nextWakeupTime);
        

        // 如果有等待的commands的话,就运行所有的commands
        // 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);

初始状态下是没有事件的,来到mLooper->pollOnce,了解Handler机制的native层知道,在pollOnce中调用epoll_wait对前面设置的兴趣事件进行监听,然后InputDispatchThread进入休眠等待唤醒;可想而知下面策略是InputReaderThread来对其进行唤醒;

InputReaderThread#threadLoop:
InputReaderThread中的主要逻辑是调用InputReader中的loopOnce函数

1)InputReader#loopOnce :

 /** \\frameworks\\native\\services\\inputflinger\\InputReader.h **/
    class InputReaderInterface : public virtual RefBase
    class InputReader : public InputReaderInterface

    /** \\frameworks\\native\\services\\inputflinger\\InputReader.cpp **/
// loopOnce即事件处理函数
    void InputReader::loopOnce() 
        ......
        // 其实是通过mEventHub来获取Events的
        // @value sp<EventHubInterface> mEventHub;
        size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
        ......
        // @value sp<QueuedInputListener> mQueuedListener;
        mQueuedListener->flush();
    

可以看到这里通过EventHub的getEvents来获取/dev/input中的Event事件,然后用到前面提到的封装了InputDispatcher的QueueListener来分发事件;
EventHub获取Events的具体流程:Android按键事件传递流程(一)
主要工作流程是注册这些监听的devices,然后调用epoll_wait使得InputReaderThread等待唤醒;
获取Events的过于复杂,直接跳过,来看事件的传递;当获取到Event之后,调用mQueuedListener的flush来传递消息;

二、事件分发

前面提到使用EventHub的getEvents来获取Events之后,通过mQueuedListener的flush开始消息的分发;

1、QueueInputListener#flush:

1)先看QueueInputListener的定义:

/** \\frameworks\\native\\services\\inputflinger\\InputListener.h **/
class QueuedInputListener : public InputListenerInterface 
    protected:
    virtual ~QueuedInputListener();

    public:
    QueuedInputListener(const sp<InputListenerInterface>& innerListener);

    virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args);
    virtual void notifyKey(const NotifyKeyArgs* args);
    virtual void notifyMotion(const NotifyMotionArgs* args);
    virtual void notifySwitch(const NotifySwitchArgs* args);
    virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args);

    void flush();

    private:
    sp<InputListenerInterface> mInnerListener;// mInnerListner即是InputDispatcher
    Vector<NotifyArgs*> mArgsQueue; // 后面flush函数中将会用到
;

在InputReader的构造函数中,传递进来的mInnerListener即为InputDispatcher;

2)flush函数:

/** \\frameworks\\native\\services\\inputflinger\\InputListener.cpp **/
void QueuedInputListener::flush() 
    size_t count = mArgsQueue.size();
    for (size_t i = 0; i < count; i++) 
        NotifyArgs* args = mArgsQueue[i];
        // 调用NotifyArgs。notify函数
        args->notify(mInnerListener);
        delete args;
    
    mArgsQueue.clear();

// 这里仅是一个封装函数,最终调用InputListenerInterface的notifyKey函数
void NotifyKeyArgs::notify(const sp<InputListenerInterface>& listener) const 
    listener->notifyKey(this);
前面最终调用InputListenerInterface(即InputDispatcher)的notifyKey回调函数;
总结前面的流程即InputReaderThread通过EventHub不断读取获取event信息,获得事件后,调用InputDispather的notifyKey函数来通知InputDispathcer进行处理。注意这里调用InputDispatcher的notifyKey函数依然是在InputReaderThread线程中进行的,此时InputDispathcerThread仍然是epoll_wait阻塞状态中;

2、InputDispatcher::notifyKey:

/** \\frameworks\\native\\services\\inputflinger\\InputDispatcher.cpp **/
void InputDispatcher::notifyKey(const NotifyKeyArgs* args) 
    if (!validateKeyEvent(args->action))  // 判断event是否合法
        return;
    
    ......
    // 初始化KeyEvent
    KeyEvent event;
    event.initialize(args->deviceId, args->source, args->action,
                     flags, keyCode, args->scanCode, metaState, 0,
                     args->downTime, args->eventTime);
    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

    // 唤醒InputDispatcherThread线程
    if (needWake) 
        mLooper->wake();
    

该部分对传递过来的按键事件进行检查、验证,之后处理特殊按键,将原始按键信息封装成KeyEntry,再调用enqueueInboundEventLocked函数把KeyEntry添加到InboundQueue队列中,最后调用Looper对象的wake往管道中写入字符唤醒InputDispatcherThread线程(类似于Handler机制中的唤醒);
先来看enqueueInboundEventLocked添加事件到InboundQueue队列中:

1)InputDispatcher::enqueueInboundEventLocked:

/** \\frameworks\\native\\services\\inputflinger\\InputDispatcher.cpp **/
bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) 
    // @value Queue<EventEntry> mInboundQueue;
    bool needWake = mInboundQueue.isEmpty();
    // 将entry入队列
    mInboundQueue.enqueueAtTail(entry);

    switch (entry->type)  // 如前面所述,InputEvent分为KeyEvent和MotionEvent进行分别处理
    case EventEntry::TYPE_KEY: ......

    case EventEntry::TYPE_MOTION: .....
    

    return needWake;

将entry添加到InboundQueue队列尾部;然后判断是否需要唤醒,即needWake是否为true;当mInboundQueue不为空,则明显InputDispathcerThread仍处于运行状态来分发事件,因而不用进行唤醒;而当mInboundQueue为空时,测试InputDispatcherThread进行休眠状态,使用wake对其来唤醒;
InputDispatcherThread之前调用Looper的poolOnce函数阻塞休眠,这里调用wake将其唤醒;因为InputDispatcherThread的threadLoop返回值为true,表示该Thread是循环执行的,故继续调用其dispatchOnce函数;

3、InputDispatcher::dispatchOnce:

/** \\frameworks\\native\\services\\inputflinger\\InputDispatcher.cpp **/
void InputDispatcher::dispatchOnce() 
    nsecs_t nextWakeupTime = LONG_LONG_MAX;
     // acquire lock
        AutoMutex _l(mLock);
        mDispatcherIsAliveCondition.broadcast();

        // 在没有等待的commands事运行一个dispatch loop,这个loop之后可能enqueue commands
        if (!haveCommandsLocked()) 
            dispatchOnceInnerLocked(&nextWakeupTime);
        

        // 如果有等待的commands的话,就运行所有的commands
        // 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);

来到dispatchOnceInnerLocked:

4、InputDispathcer#dispatchOnceInnerLocked:

/** \\frameworks\\native\\services\\inputflinger\\InputDispatcher.cpp **/
void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) 
    nsecs_t currentTime = now();

    if (! mPendingEvent) 
        if (mInboundQueue.isEmpty())  // 当前mInboundQueue已经存在元素
            ......
         else 
            // Inbound queue has at least one entry.
            mPendingEvent = mInboundQueue.dequeueAtHead();
            traceInboundQueueLengthLocked();
        
        ......
    

    // 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);
    .......
    // 根据mPendingEvent的Type的不同分别进行处理
    switch (mPendingEvent->type) 
        case EventEntry::TYPE_CONFIGURATION_CHANGED: 
            ......
            done = dispatchConfigurationChangedLocked(currentTime, typedEntry);
            dropReason = DROP_REASON_NOT_DROPPED; // configuration changes are never dropped
            break;
        
            // KeyEvent采用dispatchKeyLocked进行处理
        case EventEntry::TYPE_KEY: 
            KeyEntry* typedEntry = static_cast<KeyEntry*>(mPendingEvent);
            ......
            done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);
            break;
        

            // MotionEvent采用dispatchMotionLocked进行处理
        case EventEntry::TYPE_MOTION: 
            ......
            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
    

可以看到是事件处理机制中常用的处理模式,类似于Handler机制,这里先dequeueAtHead使得InBoundQueue事件队列中的事件出队列(FIFO);然后根据事件的类似进行不同的处理;如TYPE_KEY类型事件采用dispatchKeyLocked;TYPE_MOTION类型事件采用dispatchMotionLocked处理
下面以KeyEvent为例进行分析,下面忽略对event的具体处理细节,具体来看事件是如何传递的;

5、InputDispatcher::dispatchKeyLocked:

/** \\frameworks\\native\\services\\inputflinger\\InputDispatcher.cpp **/
bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry,
        DropReason* dropReason, nsecs_t* nextWakeupTime) 
    ......
    /** 确定事件的接收方(Target) **/
    Vector<InputTarget> inputTargets;
    int32_t injectionResult = findFocusedWindowTargetsLocked(currentTime,
            entry, inputTargets, nextWakeupTime);

    setInjectionResultLocked(entry, injectionResult);
    addMonitoringTargetsLocked(inputTargets);

    /** 将消息dispatch给Target **/
    dispatchEventLocked(currentTime, entry, inputTargets);
    return true;

前面对event的处理细节忽略,重点来看系统是如何查找event对应的接收方(Target)的,这里的InputTarget指定一个输入事件如何被分发到一个特定窗口。该结构体包含了很多特征变量:x,y坐标,输入事件通道InputChannel等;
这里通过findFocusedWindowTargetsLocked来确定InputTarget的,然后调用dispatchEventLocked来将Event分发给具体的Target;
接下来分析函数findFocusedWindowTargetsLocked;

6、InputDispatcher::findFocusedWindowTargetsLocked:

/** \\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;
    String8 reason;
    // mFocusedWindowHandle表示当前焦点窗口的句柄
    // @value sp<InputWindowHandle> mFocusedWindowHandle;
    /** 当获得焦点的窗口为null时,会丢弃这一事件 **/
    if (mFocusedWindowHandle == NULL) 
        if (mFocusedApplicationHandle != NULL) 
        // 如果没有焦点窗口,但焦点窗口所在的应用程序进程存在,说明该应程序还在启动过程中,故等待nextWakeupTime后再重试
            injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
                    mFocusedApplicationHandle, NULL, nextWakeupTime,
                    "Waiting because no window has focus but there is a "
                    "focused application that may eventually add a window "
                    "when it finishes starting up.");
            goto Unresponsive;
        

        injectionResult = INPUT_EVENT_INJECTION_FAILED;
        goto Failed;
    

    /** 如果执行到这里说明当前有焦点窗口 **/
    // 先判断权限
    if (! checkInjectionPermission(mFocusedWindowHandle, entry->injectionState)) 
        injectionResult = INPUT_EVENT_INJECTION_PERMISSION_DENIED;
        goto Failed;
    

    // 如果当前焦点窗口正在处理上一个事件,采取和最上面一样的作法,等待一段时间后重试
    reason = checkWindowReadyForMoreInputLocked(currentTime,
            mFocusedWindowHandle, entry, "focused");
    if (!reason.isEmpty()) 
        injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
                mFocusedApplicationHandle, mFocusedWindowHandle, nextWakeupTime, reason.string());
        goto Unresponsive;
    

    // 成功找到匹配的窗口,通过addWindowTargetLocked添加到inputTargets变量中
    injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED;
    addWindowTargetLocked(mFocusedWindowHandle,
            InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS, BitSet32(0),
            inputTargets);

Failed:
Unresponsive:
    nsecs_t timeSpentWaitingForApplication = getTimeSpentWaitingForApplicationLocked(currentTime);
    updateDispatchStatisticsLocked(currentTime, entry,
            injectionResult, timeSpentWaitingForApplication);
    return injectionResult;

上面查找焦点窗口的逻辑很清晰, 当mFocusedWindowHandle为null时,如果mFocusedApplicationHandle不为null,表示当前没有焦点窗口,但焦点窗口所在的应用程序进程存在,说明该应程序还在启动过程中,故等待nextWakeupTime后再重试;如果mFocusedApplicationHandle为null,则丢弃该事件,因为没有能够接收该事件的窗口;
如果mFocusedWindowHandle不为null,先判断当前窗口是否locked,如果是表示正在处理其他输入事件,这时采用和上面相同的策略,等待一段时间后,然后重试。
当找到匹配的目标窗口之后,赋值给InputTarget;先来看InputTarget的定义:

7、InputTarget:

/** \\frameworks\\native\\services\\inputflinger\\InputDispatcher.h **/
/*
 * An input target specifies how an input event is to be dispatched to a particular window
 * including the window's input channel, control flags, a timeout, and an X / Y offset to
 * be added to input event coordinates to compensate for the absolute position of the
 * window area.
 */
struct InputTarget 
    enum  // 该枚举类列举个关于目标窗口的各种属性值描述
        /* This flag indicates that the event is being delivered to a foreground application. */
        FLAG_FOREGROUND = 1 << 0, // 说明目标窗口是前台应用
        ......
    
    /** InputDispatcher与WMS建立关联通信的地方 */
    sp<InputChannel> inputChannel;
;

这里引出了重要的类InputChannel,InputDispatcher与WMS之间的通信,正是通过InputChannel来实现的。

继续前面的dispatchKeyLocked函数,接下来会调用dispatchEventLocked来传递消息;

8、InputDispatcher#dispatchEventLocked

/** \\frameworks\\native\\services\\inputflinger\\InputDispatcher.cpp **/
void InputDispatcher::dispatchEventLocked(nsecs_t currentTime,
        EventEntry* eventEntry, const Vector<InputTarget>& inputTargets) 
    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);
        // 根据inputChannel(其中的fd)来获取对应的Connection
        ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel);
        if (connectionIndex >= 0) 
            sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
            // 继续向下调用
            prepareDispatchCycleLocked(currentTime, connection, eventEntry, &inputTarget);
        
    

这里根据InputChannel的fd值来获取对应的Connection对象,InputChannel以及Connection的相关知识可以西安看第三章;Connection是用来管理InputChannel的变量;然后接着调用 prepareDispatchCycleLocked;

/** \\frameworks\\native\\services\\inputflinger\\InputDispatcher.cpp **/
void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
        const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) 

    // Split a motion event if needed.
    if (inputTarget->flags & InputTarget::FLAG_SPLIT) 
        ALOG_ASSERT(eventEntry->type == EventEntry::TYPE_MOTION);

        MotionEntry* originalMotionEntry = static_cast<MotionEntry*>(eventEntry);
        if (inputTarget->pointerIds.count() != originalMotionEntry->pointerCount) 
            MotionEntry* splitMotionEntry = splitMotionEvent(
                    originalMotionEntry, inputTarget->pointerIds);
            if (!splitMotionEntry) 
                return; // split event was dropped
            
            enqueueDispatchEntriesLocked(currentTime, connection,
                    splitMotionEntry, inputTarget);
            splitMotionEntry->release();
            return;
        
    

    // Not splitting.  Enqueue dispatch entries for the event as is.
    enqueueDispatchEntriesLocked(currentTime, connection, eventEntry, inputTarget);

最后接着调用 enqueueDispatchEntriesLocked函数:

/** \\frameworks\\native\\services\\inputflinger\\InputDispatcher.cpp **/
void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime,
        const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) 
    bool wasEmpty = connection->outboundQueue.isEmpty();

    // Enqueue dispatch entries for the requested modes.
    // 将dispatch entries入队列
    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);
    

enqueueDispatchEntryLocked创建DispatchEntry(按键事件对象),并且把该对象作为一个发送数据包加入到outboundQueue队列中;
startDispatchCycleLocked取出outboundQueue队列头元素,赋给dispatchEntry,再取出事件对象KeyEntry,根据事件类型确定case语句分支,如果是按键事件,就调用connection的InputPublisher的publishKeyEvent函数发送到inputchannel中,如果publishKeyEvent返回0,表示按键事件发送成功;
InputDispathcer#enqueueDispatchEntryLocked:

/** \\frameworks\\native\\services\\inputflinger\\InputDispatcher.cpp **/
void InputDispatcher::enqueueDispatchEntryLocked(
        const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget,
        int32_t dispatchMode) 
    int32_t inputTargetFlags = inputTarget->flags;
    // 如果inputTargetFlags和dispatchMode不匹配
    if (!(inputTargetFlags & dispatchMode)) 
        return;
    
    inputTargetFlags = (inputTargetFlags & ~InputTarget::FLAG_DISPATCH_MASK) | dispatchMode;

    // 创建DispatchEntry
    DispatchEntry* dispatchEntry = new DispatchEntry(eventEntry, // increments ref
            inputTargetFlags, inputTarget->xOffset, inputTarget->yOffset,
            inputTarget->scaleFactor);

   ......

    // Enqueue the dispatch entry.
    // 添加到outboundQueue中
    connection->outboundQueue.enqueueAtTail(dispatchEntry);

9、InputDispathcer#startDispatchCycleLocked:

/** \\frameworks\\native\\services\\inputflinger\\InputDispatcher.cpp **/
void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
        const sp<Connection>& connection) 

    while (connection->status == Connection::STATUS_NORMAL
            && !connection->outboundQueue.isEmpty()) 
        // 取出outboundQueue的首部元素
        DispatchEntry* dispatchEntry = connection->outboundQueue.head;
        dispatchEntry->deliveryTime = currentTime;

        // Publish the event.
        status_t status;
        EventEntry* eventEntry = dispatchEntry->eventEntry;
        // 根据EventEntry的Type类型进行处理
        switch (eventEntry->type) 
        case EventEntry::TYPE_KEY: 
            KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry);

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

        case EventEntry::TYPE_MOTION: 
    

以上是关于View机制深入学习 事件处理机制一的主要内容,如果未能解决你的问题,请参考以下文章

Android View深入解析事件分发机制

对JS事件机制的深入理解

Android_基于监听的事件处理机制

Android View的事件分发机制

深入理解View知识系列三-Window机制Canvas的由来Android事件的由来

深入理解View知识系列三-Window机制Canvas的由来Android事件的由来