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

本文深入探讨Android的事件处理机制,从事件的获取、InputManagerService的启动,到事件的分发过程。详细介绍了从事件源采集、前期处理、WMS分配,再到应用程序处理的整个流程,包括InputDispatcher和InputReader的角色,以及InputChannel在View和ViewGroup中的作用。通过对InputEvent接口、KeyEvent和MotionEvent的分析,揭示了Android系统如何处理和传递不同类型的输入事件。
摘要由CSDN通过智能技术生成

以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: {
            MotionEntry* motionEntry = static_cast<MotionEntry*>(eventEntry);
            ....
            // 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;
        }

        }

        .....

        // Re-enqueue the event on the wait queue.
        // 事件处理完,将该Entry移除队列
        connection->outboundQueue.dequeue(dispatchEntry);
        traceOutboundQueueLengthLocked(connection);
        connection->waitQueue.enqueueAtTail(dispatchEntry);
        traceWaitQueueLengthLocked(connection);
    }
}

典型的事件处理函数,从outBoundQueue中取出EventEntry,然后根据其Type,是TypeEvent,还是MotionEvent分别进行处理;可以看到KeyEvent使用publishKeyEvent来处理;而MotionEvent采用publishMotionEvent来处理;

10、InputPublisher#publishMotionEvent:

/** \frameworks\native\libs\input\InputTransport.cpp **/ 
status_t InputPublisher::publishMotionEvent(
        uint32_t seq,
        int32_t deviceId,
        ......
        const PointerProperties* pointerProperties,
        const PointerCoords* pointerCoords) {
    .....
    // 一系列的赋值操作
    InputMessage msg;
    msg.header.type = InputMessage::TYPE_MOTION;
    msg.body.motion.seq = seq;
    msg.body.motion.deviceId = deviceId;
    ......
    return mChannel->sendMessage(&msg);
}

InputPublisher的publishMotionEvent中创建一个InputMessage,然后根据传递进来的EventEntry中的值进行赋值,然后调用InputChannel的sendMessage进行事件发送;这里的InputChannel即是下面将会提到的在ViewRootImpl中创建的Server端的InputChannel;

11、InputChannel#sendMessage:

/** \frameworks\native\libs\input\InputTransport.cpp **/
status_t InputChannel::sendMessage(const InputMessage* msg) {
    size_t msgLength = msg->size();
    ssize_t nWrite;
    do {
    // mFd对应socket fd;则例相当于往服务器socket中发送消息
        nWrite = ::send(mFd, msg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL);
    } while (nWrite == -1 && errno == EINTR);

    // 发送失败
    if (nWrite < 0) {
       .....
        return -error;
    }
    // 发送成功
    return OK;
}

InputChannel的sendMessage操作即是使用服务器socket send一个Message;下面将会提到socket服务端没有往inputchannel中写入数据时,客户端暂时处于阻塞状态,一旦服务端有了数据后,客户端也被唤醒了。

这里先来了解下这个重要类InputChannel是如何被初始化的;

三、重要的类InputChannel:

1、InputChannel定义:

/** \frameworks\native\include\input\InputTransport.h **/
/*
 * An input channel consists of a local unix domain socket used to send and receive
 * input messages across processes.  Each channel has a descriptive name for debugging purposes.
 *
 * Each endpoint has its own InputChannel object that specifies its file descriptor.
 *
 * The input channel is closed when all references to it are released.
 */
// 上面提到InputChannel是使用unix domain socket(UDS)进行通信的,而非Binder
class InputChannel : public RefBase {
protected:
    virtual~InputChannel();


public:
    InputChannel(const String8& name, int fd); // fd类似设备描述符
    // 用于打开一个InputChannel对(Pair),用以实现双向通信
    static status_t openInputChannelPair(const String8& name,
            sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel);

    inline String8 getName() const { returnmName; }
    inlineint getFd() const { returnmFd; }

    // 发送接收信息
    status_t sendMessage(const InputMessage* msg);
    status_t receiveMessage(InputMessage* msg);

    /* Returns a new object that has a duplicate of this channel's fd. */
    sp<InputChannel> dup() const;

private:
    String8 mName;
    int mFd;  // 重点要弄清该变量代表的含义
};

InputChannel是可以双向通信的,它通过openInputChannelPair来打开一个InputChannel对,然后sendMessage或者receiveMessage来发送接收消息;
InputChannel是通过UDS来实现通信的,Android系统中最为常用的进程间通信时Binder通信,其次便是UDS进行单机内的进程间通信,也称IPC Socket。
来看InputChannel的初始化:
了解Window的创建过程后,之后有一个重要的对象ViewRootImpl,这里从其setView开始探索:

2、ViewRootImpl#setView:

/** \frameworks\base\core\java\android\view\ViewRootImpl.java **/
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
    synchronized (this) {
        .....
        if ((mWindowAttributes.inputFeatures
                & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
            mInputChannel = new InputChannel();
        }
        try {
            // 在Session addToDisplay时,传入mInputChannel
            res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                    getHostVisibility(), mDisplay.getDisplayId(),
                    mAttachInfo.mContentInsets, mAttachInfo.mStableInsets, mInputChannel);
        }
        .....
    }
}

其实Java层的InputChannel只是对native层的封装,如下所示:

/** \frameworks\base\core\java\android\view\InputChannel.java **/
public final class InputChannel implements Parcelable {
    @SuppressWarnings("unused")
    private long mPtr; // used by native code

    private static native InputChannel[] nativeOpenInputChannelPair(String name);
    private native void nativeDispose(boolean finalized);
    private native void nativeTransferTo(InputChannel other);
    private native void nativeReadFromParcel(Parcel parcel);
    private native void nativeWriteToParcel(Parcel parcel);
    private native void nativeDup(InputChannel target);
    private native String nativeGetName();
}

WindowSession的具体细节参见《View机制深入学习(一)》,addToDisplay会继续调用WindowManagerService的addWindow函数:

/** \frameworks\base\core\java\android\view\WindowManagerService.java **/
public int addWindow(Session session, IWindow client, int seq,
                     WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
                     Rect outContentInsets, Rect outStableInsets, InputChannel outInputChannel) {
    .....
    if (outInputChannel != null && (attrs.inputFeatures
            & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
        String name = win.makeInputChannelName();
        // 打开InputChannel对
        InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
        // WindowState设置inputChannel变量
        win.setInputChannel(inputChannels[0]);
        // 设置outputChannel
        inputChannels[1].transferTo(outInputChannel);

        // InputManager注册InputChannel
        mInputManager.registerInputChannel(win.mInputChannel, win.mInputWindowHandle);
    }
    ....
}

可以看到在这里通过openInputChannelPair打开InputChannel,前面提到openInputChannelPair就是调用native端InputChannel的openInputChannelPair函数;
从这里面还可以看到,创建的InputChannel对,一个用来设置给WindowState,即供Window使用;一个设置给InputManagerService,其实是设置给native端的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");
    }
    return nativeOpenInputChannelPair(name);
}

private static native InputChannel[] nativeOpenInputChannelPair(String name);

下面来看native端的InputChannel;

3、InputChannel::openInputChannelPair:

/** \frameworks\native\libs\input\InputTransport.cpp **/
status_t InputChannel::openInputChannelPair(const String8& name,
                                            sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) {
    // 建立UDS
    int sockets[2];
    // 创建一个饱含2个元素的socket数组,socketpair创建一对socket对象,SOCK_SEQPACKET表示创建连续可靠的数据包连接,如果创建成功,返回0,如果返回-1,出错。
    if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) {
        status_t result = -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));

    // 创建Server与Client端实例
    String8 serverChannelName = name;
    serverChannelName.append(" (server)");
    outServerChannel = new InputChannel(serverChannelName, sockets[0]);

    String8 clientChannelName = name;
    clientChannelName.append(" (client)");
    outClientChannel = new InputChannel(clientChannelName, sockets[1]);
    return OK;
}

上面创建了一对InputChannel:分别为服务端管道对象outServerChannel和客户端管道对象outClientChannel;inputChannels[0]作为服务端管道提供给InputDispatcher使用,用来发送按键事件;inputChannels[1]作为客户端管道提供给应用程序主线程使用,用来接收、消费按键事件。

创建好InputChannel之后,继续来看addWindow中的InputManagerService注册InputChannel的过程;前面提到,创建的inputChannels[0]即outServerChannel是供IMS中的InputDispatcher使用的,因此这里需要进行注册;

4、InputManagerService#registerInputChannel:

直接来到本地端的nativeRegisterInputChannel,

/** \frameworks\base\services\core\jni\com_android_server_input_InputManagerService.cpp **/  
static void nativeRegisterInputChannel(JNIEnv* env, jclass clazz,
        jlong ptr, jobject inputChannelObj, jobject inputWindowHandleObj, jboolean monitor) {
    // 将Java端存储的ptr指针地址转化为NativeInputManager对象
    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);

    // 根据传输进来的inputChannelObj获取InputChannel对象
    sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env, inputChannelObj);
    ......
    // 根据传递进来的inputWindowHandleObj来获取InputWindowHandle对象
    sp<InputWindowHandle> inputWindowHandle = android_server_InputWindowHandle_getHandle(env, inputWindowHandleObj);

    // 调用NativeInputManager的registerInputChannel进行注册
    status_t status = im->registerInputChannel(env, inputChannel, inputWindowHandle, monitor);
    ......
}

上面的逻辑很清晰,通过java层传递进来的inputChannelObj,inputWindowHandleObj来获取相对应的InputChannel以及InputWindowHandle对象。
然后将获得的实例传入到NativeInputManager中的registerInputChannel进行注册;

5、NativeInputManager#registerInputChannel:

/** \frameworks\base\services\core\jni\com_android_server_input_InputManagerService.cpp **/  
status_t NativeInputManager::registerInputChannel(JNIEnv* env,
        const sp<InputChannel>& inputChannel,
        const sp<InputWindowHandle>& inputWindowHandle, bool monitor) {
    return mInputManager->getDispatcher()->registerInputChannel(
            inputChannel, inputWindowHandle, monitor);
}

可以看到这里最终是调用InputManager中的InputDispatcher的registerInputChannel进行注册,这也验证了前面所叙述的服务器端的InputChannel是供以InputDispatcher来使用的。

6、InputDispatcher#registerInputChannel:

/** \frameworks\native\services\inputflinger\InputDispatcher.cpp **/  
status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel,
        const sp<InputWindowHandle>& inputWindowHandle, bool monitor) {
    { // acquire lock
        AutoMutex _l(mLock);

        if (getConnectionIndexLocked(inputChannel) >= 0) {
            return BAD_VALUE;
        }

        // 创建一个Connection来管理对应的InputChannel以及WindowHandler
        sp<Connection> connection = new Connection(inputChannel, inputWindowHandle, monitor);

        // 获取InputChannel对应的socket Fd;
        int fd = inputChannel->getFd();
        // 类似于key,value形式,将connection与inputChannel的fd建立起关联
        mConnectionsByFd.add(fd, connection);

        if (monitor) {
            mMonitoringChannels.push(inputChannel);
        }

        // 将InputChannel的fd添加到Looper中epoll的兴趣事件列表中
        mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
    } // release lock

    // Wake the looper because some connections have changed.
    // 因为connection已经发生了变化,则唤醒Looper
    mLooper->wake();
    return OK;
}

这里通过InputChannel以及InputWindowHandle来创建相对应的Connection;Connetction是用来管理InputChannel的,Connection存储在 mConnectionsByFd的,它通过key-value形式进行存储,Connection的关键字使用InputChannel创建时的socket的fd来标识。

然后将InputChannel的fd添加到Looper的epoll兴趣列表中,注意这里的Looper对应的是InputDispatcherThread中的Looper;当server端的InputChannel有事件传递时,这时Looper会被唤醒,执行handleReceiveCallback回调;

服务器端InputChannel使用InputManagerService的registerInputChannel来实现,而客户端的InputChannel则通过

inputChannels[1].transferTo(outInputChannel);

来实现;

7、InputChannel#transferTo:

直接来到对应的native层的transferTo:

/* @path: \frameworks\base\core\jni\android_view_InputChannel.cpp */
static void android_view_InputChannel_nativeTransferTo(JNIEnv* env, jobject obj,
        jobject otherObj) {
    if (android_view_InputChannel_getNativeInputChannel(env, otherObj) != NULL) {
        jniThrowException(env, "java/lang/IllegalStateException",
                "Other object already has a native input channel.");
        return;
    }
    // 创建InputChannel
    NativeInputChannel* nativeInputChannel =
            android_view_InputChannel_getNativeInputChannel(env, obj);
    android_view_InputChannel_setNativeInputChannel(env, otherObj, nativeInputChannel);
    android_view_InputChannel_setNativeInputChannel(env, obj, NULL);
}

注意函数中出现的几个变量对应的含义:
obj:本地方法所在对象的引用,对应inputChannels[1]客户端对象的引用
otherObj:在ViewRootImpl中创建的InputChannel对象
具体不再细述,就是将本地端的InputChannel[1]赋值给Java端的outInputChannel对象;

在前面第二章末已经提出,使用InputPublisher来将Message传递给InputChannel,这里是发送事件;而相对应的,会有一个是用来接收事件的,其类名为InputConsumer;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值