Android Framework 输入子系统(03)输入系统框架

系列文章解读&说明:

Android Framework 输入子系统 的 分析主要分为以下部分:

(01)核心机制 inotify和epoll

(02)核心机制 双向通信(socketpair+binder)

(03)输入系统框架

(04)InputManagerService启动分析

(04)InputReader 线程解读

(05)InputDispatcher 线程解读

(06)APP建立联系

(07)activity window decor view

(08)InputStage简介

本模块分享的内容:输入系统框架

本章关键点总结 & 说明:

本章节 导图主要关注➕ IMS 框架部分即可,通过启动过程的分析捋清楚 输入子系统的框架:就是一个从kernel中断,产生事件,/dev/input目录下文件变化,到读取数据,再到派发数据,最后到处理数据这样完整的流程。

1 IMS(InputManagerService)简介

下面这张图(《深入理解Android 卷III》)很清楚的描述了输入子系统的整体架构:

说明:输入事件的源头是位于/dev/input/下的设备节点,输入系统的终点是由WMS管理的某个窗口。Android输入系统的主要工作是读取设备节点中原始事件,加工封装后派发给一个特定的窗口以及窗口中的控件。接下来针对图中几个模块进行说明:

模块 简介说明
Linux内核 接受输入设备中断,将原始事件数据写入到设备节点
设备节点 IMS可以从中读取事件
InputManagerService 分为Java层和Native层两部分,Java层负责与WMS的通信;Native层是InputReader和InputDispatcher两个输入系统关键组件的运行容器。
EventHub 直接访问所有的设备节点。通过一个名为getEvents()的函数将所有输入系统相关的待处理底层事件返回给使用者。
InputReader 运行于独立线程,负责管理输入设备的列表与配置,以及进行输入事件的加工处理。通过线程循环不断地通过getEvents()函数从EventHub中将事件取出并进行处理。对于设备节点的增删事件,它会更新输入设备列表于配置。对于原始输入事件,InputReader对其进行翻译、组装、封装为包含了更多信息、更具可读性的输入事件,然后交给InputDispatcher进行派发。
InputReaderPolicy 为InputReader事件加工处理提供策略配置。
InputDispatcher 是IMS中的另一个关键组件。它也运行于一个独立的线程中。InputDispatcher中保管了来自WMS的所有窗口的信息,收到来自InputReader的输入事件后,会寻找合适的窗口,将事件派发给它。
InputDispatcherPolicy 它为InputDispatcher的派发过程提供策略控制。
WMS 对InputDispatcher的正常工作起到了至关重要的作用。新建窗口时,WMS为新窗口和IMS创建了事件传递所用的通道。另外,WMS还将所有窗口的信息,包括窗口的可点击区域,焦点窗口等信息,实时地更新到IMS的InputDispatcher中,使得InputDispatcher可以正确地将事件派发到指定的窗口。
ViewRootImpl 对于某些窗口,如壁纸窗口、SurfaceView的窗口来说,窗口即是输入事件派发的终点。而对于其他的如Activity、对话框等使用了Android控件系统的窗口来说,输入事件的终点是控件(View)。ViewRootImpl将窗口所接收到的输入事件沿着控件树将事件派发给对应的控件。

流程总结:内核将原始事件写入到设备节点中,InputReader不断地通过EventHub将原始事件取出来并加工成Android输入事件,交给InputDispatcher。InputDispatcher根据WMS提供的窗口信息将事件交给合适的窗口。窗口的ViewRootImpl对象再沿着控件树将事件派发给感兴趣的控件。控件对其收到的事件作出响应,更新自己的画面、执行特定的动作。

2 IMS(InputManagerService)启动流程分析

Android的输入子系统是在InputManagerService中启动的,而InputManagerService是在system_server中启动的。接下来从SystemServer的启动开始逐步分析:

//systemserver->startOtherServices
private void startOtherServices() {
    //...
    inputManager = new InputManagerService(context);//关键点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);

    inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
    inputManager.start();//关键点2
    //...
}

从这里开始 关注 ➕InputManagerService的构造器和线程启动执行两个部分。

2.1 InputManagerService构造器深入分析

构造器代码如下:

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

        mUseDevInputEventForAudioJack =
                context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
        Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack="
                + mUseDevInputEventForAudioJack);
        //调用nativeInit来执行C++层的初始化操作
        mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());

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

这里关注nativeInit的实现,代码如下:(对应文件 com_android_server_input_InputManagerService.cpp)

static jlong nativeInit(JNIEnv* env, jclass clazz,
        jobject serviceObj, jobject contextObj, jobject messageQueueObj) {
    sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
    if (messageQueue == NULL) {
        jniThrowRuntimeException(env, "MessageQueue is not initialized.");
        return 0;
    }
    //构造一个NativeInputManagera对象
    NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
            messageQueue->getLooper());
    im->incStrong(0);
    return reinterpret_cast<jlong>(im);
}

这里创建一个NativeInputManager的实例,并将其作为返回值保存在InputManagerService 中的mPtr字段里,继续分析NativeInputManager的构造器,代码如下:

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对象,传递给InputManager
    sp<EventHub> eventHub = new EventHub();
    mInputManager = new InputManager(eventHub, this, this);
}

这里继续分析关键对象InputManager,代码如下:

InputManager::InputManager(
        const sp<EventHubInterface>& eventHub,
        const sp<InputReaderPolicyInterface>& readerPolicy,
        const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
    mDispatcher = new InputDispatcher(dispatcherPolicy);
    mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
    initialize();
}

这里创建了InputDispatcher对象 用于分发输入事件,同时创建了一个InputReader对象 用于从EventHub中读取输入事件。同时这里继续分析initialize方法,代码如下:

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

这里创建了一个InputReaderThread和InputDispatcherThread对象,前面构造器中创建的InputReader是通过InputReaderThread来读取输入事件,而InputDispatcher实际通过InputDispatcherThread来分发输入事件。下图(《深入理解Android 卷III》)很清楚描述了输入子系统的整体框架,如下所示:

InputManager的创建过程分别为InputReader与InputDispatcher创建了线程,IMS的各成员准备就绪。

2.2 InputManagerService线程启动分析

线程启动是从这里开始:

 inputManager.start();

继续分析,代码如下:

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

继续分析nativeStart,代码如下:

static void nativeStart(JNIEnv* env, jclass /* clazz */, jlong ptr) {
    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
    status_t result = im->getInputManager()->start();
}

实际调用了InputManager的start函数,继续分析,代码如下:

status_t InputManager::start() {
    status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);
    //...
    result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);
    //...
    return OK;
}

InputManager启动了一个InputReaderThread和InputDispatcherThread来读取和分发输入消息,调用它们的run方法后,会进入threadLoop函数(只要threadLoop函数返回true,该函数就会循环执行)。后面章节 会单独从读取事件、派发事件角度来解读两个线程。

这里start()函数的功能就是启动这两个线程,使得InputReader于InputDispatcher开始工作。当两个线程启动后,InputReader在其线程循环中不断地从EventHub中读取输入事件,加工处理后将事件放入InputDispatcher的派发发队列中,InputDispatcher在线程循环中将派发队列中的事件取出,查找合适窗口,将事件写入。窗口事件接收线程的Looper从管道中将事件取出,交由事件处理函数进行事件响应。过程如下图所示:(《深入理解Android 卷III》)

3 总结 IMS各成员关系(《深入理解Android 卷III》)

该图很好的诠释了IMS相关类的 成员关系,左边是Reader子系统,右边是 Dispatcher子系统。而接下来的两节主要针对两个子系统Reader和Dispatcher进行更加详细的分析。

猜你喜欢

转载自blog.csdn.net/vviccc/article/details/91409810