打印
[资料分享]

安卓底层开发学习经验第二十八期(上)

[复制链接]
817|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 xiaohai8856 于 2015-12-15 11:24 编辑

从这一期我们来分析一下Android Input,首先我们来看一下他的一个框架图
安卓的Input包括触摸屏事件,按键消息,还可以配上一些游戏手柄的一些输入消息,或者是鼠标键盘,这个都是Linux系统的一个标准的Input事件。我们来看一下这张图,首先是上层APP,每一个Activity都能够收到我们底层发上来的Input消息,包括我们的返回键、home键、音量键等,那么我们当前活动的应用,他的消息是通过我们WindowManagerService来进行分发的,因为我们可能在一个手机上集N个应用,但是有的应用被压在后台,但是WindowManagerService这一层级会把底层发出来的Input事件只发送给当前的活动窗口,而这一整套管理机制是由WindowManagerService以及InputChannelViewRootImplPhoneWindowManager等一系列的类和对象来共同维护的。当我们在SystemServer启动的时候我们初始化WindowManagerService就会创建一个InputManager,并且把InputManager对象传给WindowManagerService,在WindowManagerService初始化的时候,就会得到InputManager的对象,这样就可以处理底层的消息,而我们WindowManagerService这一层级,它是通过JNI方法来对我们底层的时间进行捕获的,这个捕获就是我们InputManager来实现的。我们Jni的方法包括我们InputManager的初始化,start,以及注册InputChannel,这个Channel的作用就是从底层C++层,接收按键消息,传给我们上层的应用,上层的应用也就是frameworkjava部分他会处理按键消息,并且把按键消息发送给当前的ActivityJNI以下就是我们的InputManager,他用来管理我们底层所有的输入事件,在这一部分有四个比较重要的对象:mDispatcher负责分发,mReader负责消息的读,mReaderThreadmDispatcherThread是用来启动的,他在线程里不断地读取分发消息。在我们最底层InputReader,他在读消息的时候进入的是我们EventHub这个对象,这个对象在初始化的时候会获取我们device Input下面的所有输入设备,并且根据底层的输入设备可以实时的检测dev/input这个目录,如果这个目录有热插拔设备,比如一个USB的鼠标插过来,它能够快速的捕捉到这这个input设备,捕获到之后他会把新添加的设备添加到我们整个设备列表中,然后根据设备的属性,创建和他相应对象的一系列匹配的方法,接收这个方法,并且把这些键值通过InputReader来向上分发,InputReader获取到这个按键之后做一系列处理,在传给我们的mDispatcherThread这个线程,而这个线程会通过InputDispatcher这个对象拿到相应的输入消息,然后通过InputChannel发送给我们的java层,java层收到消息之后就会做一些处理,或者是发送给我们的Activity,如果Activity注册了这个事件,那么他就会捕获到当前的按键消息。比如我们应用层写一个onclick事件,注册的时候就会捕获到这个click消息,还有就是有时候捕获到back这个事件,点完返回键他会提示你再点一次,这都是我们上层来做的,但是这个分发机制也就是和按键和Input事件的一个处理机制,是由frameworkjava)层来做的,他会知道他应该把当前的Input事件传给那个Activity。这就是我们Android Input子系统的一个框架图。当然我们的/dev/input对应的就是我们最底层的驱动设备了,而我们底层设备是由我们内核这边来实现的。比如我们手机支持基本的按键,音量键和电源键,这些都会在我们dev/input目录下映射出一个相对应的设备,然后我们的EventHub去获取这个设备,然后监听这几个设备。下面我们再来看一下Input的主要模块
下面我们来看一下Input和我们的WindowManagerService最开始初始化的一个流程,打开framework/base/services/java/com/android/server/SystemServer.java文件
在我们SystemServer启动的时候会创建一个inputManager的一个对象,创建完之后把inputManager当做一个参数,传递给WindowManagerService。首先我们来看一下InputManagerService
在初始化的时候会调用一个native的方法进行初始化,在初始化的时候会传一个queue过去,我们来看一下他具体初始化的地方,打开framework/base/services/jni/com_android_server_input_InputManagerService.cpp我们找到他的nativeInit方法
首先他会拿到一个消息队列messageQueue,然后在下面会做一些初始化的工作,首先第一个就是NativeInputManager,他在初始化的时候传了一个serviceObj的对象和一个looper的对象。首先new了一个EventHub,然后又new了一个InputManager,并且EventHub当做一个参数传给了我们的InputManager,我们首先看一下InputManager的初始化过程
他创建了一个InputDispatcher和一个InputReader,以及这里有一个readerPolicy,读的一个代理,并且有一个DispatcherPolicy的代理,然后做了一个初始化。在这个initialize()里面创建了两个线程,一个是InputReaderThread,另一个是InputDispatcherThread,在我们初始化read的时候,会把eventHub当做一个参数传给InputReader。这个就是InputManager的初始化过程,当他初始化完成之后就返回了,我们再看一下EventHub
他初始化的时候直接创建了一个参数,然后创建了一些mEpollFd,然后在下面会监控我们的device,如果这个目录有变化,我们会通过Poll的方法知道哪里有变化。然后返回我们来看一下WindowManagerService
他在初始化的时候new了一个WindowManagerService,并且传了一个参数,我们看一下inputManager这个参数,他传给本地的一个成员mInputManagermInputManager会做一件事情,也就是monitorInput,我们来看一下这个monitorInput,他是我们InputChannel所做的一个事情
他返回了一个inputchannel,这个inputchannel就是打开了一对ChannelPair,这个openInputChannel的具体实现就是一个native的方法,这个native的方法就是创建了一个套接字,和我们上一节课讲的Sensor都是类似的,当我们创建完成之后就返回了一个inputchannels1】,这个Channel1】就是来读取消息的,当我们拿到这个返回的描述符之后,创建了一个PointerEventDispatcher,这样就能从我们的底层获取消息,获取之后,我们的WindowManagerService来进行一系列处理。比如说我们的button控件,之所以能截获到button控件是因为经过WindowManagerService经过一些处理转化成一个click事件,而这个事件的入口就是在这块发上来的,发送上来之后,WindowManagerService会做处理,这样就能理解WindowManagerServiceInput设备他们是如何挂接起来的。
由于帖子有限制所以将帖子分开了,后边内容见二十八期(下)

相关帖子

发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

102

主题

315

帖子

16

粉丝