博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
i.mx android6 输入子系统分析(未完)
阅读量:4448 次
发布时间:2019-06-07

本文共 5158 字,大约阅读时间需要 17 分钟。

 

参考:http://blog.csdn.net/u010312937/article/details/53285286

   https://www.jianshu.com/p/7fca94b330ea

 注意:关于下面的一些时序图,如果看不清,可以使用下载后再看,源码我已经放在GitHub上,工具为bouml,

GitHub地址为:https://github.com/maogefff/Other/tree/master

也可以使用我将时序图转化为PNG图片以后的,GitHub地址为:https://github.com/maogefff/Other/tree/inputSystem

 

1. 框架

 

InputManagerService(IMS)

Linux内核,接受输入设备的中断,并将原始事件的数据写入设备节点中,设备节点作为内核与IMS的桥梁,将原始事件的数据暴露给用户空间,以便IMS可以从中读取事件

InputManagerService一个android系统服务,分为Java层和Native层两部分,java层负责与WMS通信,而Native层则是InputReader和InputDispatcher两个输入系统关键组件的运行容器

EventHub,直接访问所有的设备节点,通过一个名为getEvents()的函数将所有输入系统相关的待处理的底层事件返回给使用者,包括原始输入事件,设备节点的增删等

InputReader,是IMS中的关键组件之一,它运行一个独立的线程中,负责管理输入设备的列表和配置,以及进行输入事件的加工处理,它通过其线程循环不断地通过getEvents()函数从EventHub中将事件取出并进行处理,对于设备节点的增删事件,它会更新输入设备列表与配置,对于原始输入事件,InputReader对其进行翻译,组装,封装为包含更多信息,更多可读性的输入事件,然后交给InputDispatcher进行派发

InputReaderPolicy,为InputReader的事件加工处理提供一些策略配置,例如键盘布局信息等。

InputDispatcher,是IMS中的另一个关键组件,运行于一个独立的线程中,InputDispatcher中保管来自WMS的所有窗口的信息,收到InputReader的输入事件后,会在其保管的窗口中寻找合适的窗口,并将事件派发给此窗口

InputDispatcherPolicy,为InputDispatcher的派发过程提供策略控制,例如HOME键被InputDispatcherPolicy截取到PhoneWindowManager中处理,并阻止窗口收到HOME键按下的事件

WMS,并不是输入系统的一员,新建窗口时,WMS为新窗口和IMS创建了事件传递所用的通道,会将窗口的可点击区域,焦点窗口等信息实时更新到IMS的InputDispatcher中,使得InputDispatcher可以正确将事件派发到指定窗口

ViewRootImpl,对某些窗口,如壁纸窗口,SurfaceView的窗口来说,窗口就是输入事件派发的终点,而对其他的如Activity,对话框等使用了Android控件系统的窗口来说,输入事件的终点是控件

 

运行流程

简单来说,内核将原始事件写入到设备节点中,InputReader不断地通过EventHub将原始事件取出来并翻译加工成Android输入事件,然后交给InputDispatcher。InputDispatcher根据WMS提供的窗口信息将事件交给合适的窗口。窗口的ViewRootImpl对象再沿着控件树将事件派发给感兴趣的控件。控件对其收到的事件作出响应,更新自己的画面、执行特定的动作。所有这些参与者以IMS为核心,构建了Android庞大而复杂的输入体系。

 

2. 阅读代码后的总结

2.1 启动创建流程

图2.1非常重要;就是Android层输入子系统的创建流程,看不清可以github上下载下来看,黄色为JAVA代码,红色为CPP代码,蓝色为CPP代码所在文件

 

大致思路:

SystemServer创建整个输入子系统InputManagerService类用来管理整个输入子系统    (JAVA层)

InputManagerService调用构造函数然后调用nativeInit(调用到C++层)创建本地管理者NativeInputManager,然后创建各种累

下面有三个重要的功能类(这三个功能详看第一节)

EventHub:    实例化对象为eventHub

InputReader:   实例化对象为mReader

InputDispatcher:实例化对象为mDispatcher

 

还有三个重要的类:

InputManager:       实例化对象为minputManager     ;主要作用为管理下面两个线程,mReaderThread和mDispathcerThread

InputReaderThread:     实例化对象为mReaderThread    ;为一个线程的对象,主要作用为管理mReader

InputDispatcherThread:  实例化对象为mDispathcerThread ;为一个线程的对象,主要作用为管理mDispatcher

 图2.1 创建输入系统时序图

 图2.2 类之间的包含关系

 

2.2 InputReaderThread和EventHub的流程

(一). InputReaderThread流程:

InputReader如下图2.3所示,主要负责三个方面的工作:

1. 获得事件(事件是通过EventHub获取,包括:1. 设备节点的增删事件; 2. 原始输入事件

2. 对事件进行简单的处理(1. 对于设备节点的增删事件(更新设备列表和配置); 2. 原始输入事件(进行翻译和组装)

3. 将处理后的事件分发给dispatch

 

(二). EventHub流程:

 EventHub如2.3所示,主要负责检测设备节点增删事件和原始输入事件

通过inotify检测/dev/input文件夹是否有节点增删,通过epoll分别检测/dev/input/xxx里面的内容是否有修改

1. 通过epoll_wait等待获取事件(无事件等待)

2. 获取增删事件后

3. 获取原始输入事件后

下面是伪代码:

getEvents(RawEvent* buffer){    //检测目录是否有增删    fd1 = inotify.init("/dev/input");        //打开具体设备节点    fd2 = open("/dev/input/event0");    fd3 = open("/dev/input/event1");        //同时检测文件和文件夹    int pollResult = epoll_wait(fd1, fd2, fd3);        switch(){        case 增加了一个设备节点:        buffer.type = DEVICE_ADDED;        fd4 = open("dev/input/xxx");        epoll_wait(fd1, fd2, fd3, fd4);   //在epoll_wait里再增加一个fd4        break;                case 减少了一个设备节点:        buffer.type = DEVICE_REMOVE;        epoll_wait(fd1, fd2, fd3);         //在epoll_wait里再删除掉fd4        break;                case 文件内容修改了:        buffer.xxx = xxx;   //构造RawEvent        break;    }}

 

 

黄色代码类名,蓝色代表所在文件(注意:时序图在EventHub.cpp当中有点问题,loop不是包含第三个,而是包含整个)

图2.3 readThread时序图 

 

 

3. InputManagerService(IMS)流程分析

3.1 启动流程:

frameworks/base/services/java/com/android/server/SystemServer.java

public static void main(String[] args) {        new SystemServer().run();    }    ...    private void run() {    ...      // Start services.        try {            startBootstrapServices();            startCoreServices();            startOtherServices(); //其他服务里面        } catch (Throwable ex) {            Slog.e("System", "******************************************");            Slog.e("System", "************ Failure starting system services", ex);            throw ex;        }     ...        // Loop forever.        Looper.loop();        throw new RuntimeException("Main thread loop unexpectedly exited");    }

 

private void startOtherServices() {        ...        NsdService serviceDiscovery= null;        WindowManagerService wm = null;    //窗口管理服务        ...        InputManagerService inputManager = null;   //输入管理服务        ...            Slog.i(TAG, "Input Manager");            //创建输入系统            inputManager = new InputManagerService(context);            Slog.i(TAG, "Window Manager");            wm = WindowManagerService.main(context, inputManager,                    mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,                    !mFirstBoot, mOnlyCore);            ServiceManager.addService(Context.WINDOW_SERVICE, wm);            //将输入系统加入系统服务当中,以便其他人可以方便的访问(包括应用程序)            ServiceManager.addService(Context.INPUT_SERVICE, inputManager);              mActivityManagerService.setWindowManager(wm);            //设置输入系统的回调函数:设置向WMS发起回调            inputManager.setWindowManagerCallbacks(wm.getInputMonitor());            //启动输入系统服务            inputManager.start();           ...    }

 

 

 

转载于:https://www.cnblogs.com/maogefff/p/8466008.html

你可能感兴趣的文章
跟我一起读postgresql源码(六)——Executor(查询执行模块之——查询执行策略)
查看>>
scala的4中for循环,及while和do while循环
查看>>
vue.js windows下开发环境搭建
查看>>
数据表改变之后数据的迁移
查看>>
雷林鹏分享:Ruby 环境变量
查看>>
掉书袋的东东,我喜欢。。。
查看>>
通过MYSQL命令行直接建数据库
查看>>
safari 插件安装之alipay
查看>>
【语言处理与Python】3.3使用Unicode进行文字处理
查看>>
python+senium+chrome的简单爬虫脚本
查看>>
CoronaSDK场景管理库:Composer library (上)
查看>>
Go语言程序结构
查看>>
【算法导论】第6章堆排序及利用堆建立最小优先级队列
查看>>
Log4Net配置方法
查看>>
ASP.NET禁用一部分验证控件,ValidationGroup的设置与使用
查看>>
JavaScript DOM高级程序设计 5动态修改样式和层叠样式表2--我要坚持到底!
查看>>
[.NET源码学习]实例化Font,遭遇字体不存在的情况。
查看>>
手机如何设置静态IP
查看>>
JS操作文件
查看>>
解放创意——自由人的自由联合
查看>>