Android输入系统源码分析

参考:《深入理解Android 卷III》
 输入事件的源头是位于/dev/input/下的设备节点,而输入系统的终点是由WMS管理的某个窗口。最初的输入事件为内核生成的原始事件,而最终交付给窗口的则是KeyEvent或MotionEvent对象。因此Android输入系统的主要工作是读取设备节点中的原始事件,将其加工封装,然后派发给一个特定的窗口以及窗口中的控件。这个过程由InputManagerService系统服务为核心的多个参与者共同完成。输入系统的总体流程和参与者如图所示。
这里写图片描述

  • Linux内核,接受输入设备的中断,并将原始事件的数据写入到设备节点中。
  • 设备节点,作为内核与IMS的桥梁,它将原始事件的数据暴露给用户空间,以便IMS可以从中读取事件。
  • InputManagerService,一个Android系统服务,它分为Java层和Native层两部分。Java层负责与WMS的通信。而Native层则是InputReader和InputDispatcher两个输入系统关键组件的运行容器。
  • EventHub,直接访问所有的设备节点。并且正如其名字所描述的,它通过一个名为getEvents()的函数将所有输入系统相关的待处理的底层事件返回给使用者。这些事件包括原始输入事件、设备节点的增删等。
  • InputReader,是IMS中的关键组件之一。它运行于一个独立的线程Reader线程中,通过其线程循环不断地通过getEvents()函数从EventHub中将事件取出并进行处理。然后交给InputDispatcher进行派发。
  • InputDispatcher,是IMS中的另一个关键组件。它也运行于一个独立的线程中Dispatcher线程中。InputDispatcher中保管了来自WMS的所有窗口的信息,其收到来自InputReader的输入事件后,会在其保管的窗口中寻找合适的窗口,并将事件派发给此窗口。
  • WMS,虽说不是输入系统中的一员,但是它却对InputDispatcher的正常工作起到了至关重要的作用。当新建窗口时,WMS为新窗口和IMS创建了事件传递所用的通道。另外,WMS还将所有窗口的信息,包括窗口的可点击区域,焦点窗口等信息,实时地更新到IMS的InputDispatcher中,使得InputDispatcher可以正确地将事件派发到指定的窗口。

以下是代码分析,建议用sourceinsight进行代码跟踪。

输入系统会创建Reader线程和Dispatcher线程

Reader线程和Dispatcher线程创建及启动过程源码分析:

SystemServer所有服务被创建的源头,同其他系统服务一样,IMS在SystemServer中被启动。

SystemServer.java (frameworks\base\services\java\com\android\server)
private void startOtherServices() {
    inputManager = new InputManagerService(context);     //创建InputManagerService
    inputManager.start();                                //启动这个服务
}
InputManagerService.java (frameworks\base\services\core\java\com\android\server\input)
public InputManagerService(Context context) {
    mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());       //调用本地方法进行初始化  
}
public void start() {
    nativeStart(mPtr);             //调用本地nativeStart函数
}
调用native方法,创建Reader线程和Dispatcher线程并启动
com_android_server_input_InputManagerService.cpp (frameworks\base\services\core\jni)    
static jlong nativeInit {
    /* 创建了一个NativeInputManager对象,此对象将是Native层组件与Java层IMS进行通信的桥梁 */
    NativeInputManager* im = new NativeInputManager(contextObj, serviceObj, messageQueue->getLooper());
}
NativeInputManager::NativeInputManager {
    //NativeInputManager创建了EventHub,EventHub复杂的构造函数使其在创建后便拥有了监听设备节点的能力(Inotify和epoll机制)
    sp<EventHub> eventHub = new EventHub();

    // 接着创建了Native层的InputManager    
    mInputManager = new InputManager(eventHub, this, this);
}

被InputManagerService的start函数所调用来启动线程。
static void nativeStart(JNIEnv* env, jclass clazz, jlong ptr) {
    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);

    status_t result = im->getInputManager()->start();
}
InputManager统一创建并管理mReader、mReaderThread、mDispatcher、mDispatcherThread这四个实例化对象。
InputManager.cpp (frameworks\native\services\inputflinger)  
class InputManager {
    sp<InputReaderInterface> mReader;
    sp<InputReaderThread> mReaderThread;

    sp<InputDispatcherInterface> mDispatcher;
    sp<InputDispatcherThread> mDispatcherThread;
}
/* 在InputManager中创建InputDispatcher和InputReader实例化对象 */
InputManager::InputManager {
    mDispatcher = new InputDispatcher(dispatcherPolicy);
    mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
    initialize();
}
void InputManager::initialize() {
    //创建Reader线程和Dispatcher线程
    mReaderThread = new InputReaderThread(mReader);
    mDispatcherThread = new InputDispatcherThread(mDispatcher);
}

status_t InputManager::start() {
    /* 启动ReaderThread和DispatcherThread */
    status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);
    result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);
}
mDispatcherThread->run和mReaderThread->run分别会执行InputReaderThread和InputDispatcherThread线程的线程循环体。
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值