Android Input子系统 -- InputManagerService启动
InputManagerService是Android framework中核心service之一,Android framework层涉及的代码也是非常多,
123456789101112131415161718frameworks/native/services/inputflinger/ - InputDispatcher.cpp - InputReader.cpp - InputManager.cpp - EventHub.cpp - InputListener.cppframeworks/native/libs/input/ - InputTransport.cpp - Input.cpp - InputDevice.cpp - Keyboard.cpp - KeyCharacterMap.cpp - IInputFlinger.cppframeworks/base/services/core/ - java/com/android/server/input/InputManagerService.java - jni/com_android_ser ...
Android Input子系统 -- Linux
前言上一节有展示Android Input子系统的架构图,这里我们关心Linux kernel层
可以看到kernel层分为三层:
输入子系统设备驱动:处理与硬件相关的信息,调用input API注册输入设备,并把数据往上报
输入子系统核心层:为事件处理层和设备驱动层提供API接口调用
输入子系统事件处理:通过核心层的API获取输入事件上报的数据,定义input API与应用层交互
数据结构
数据结构
代码位置
描述
struct input_dev
input.h
input设备驱动中的实例
struct evdevstruct mousedevstruct keybdev
evdev.cmousedev.ckeybdev.c
Event Handler层逻辑input设备的数据结构
struct input_handler
input.h
Event Handler的结构,handler层实例化对象
struct input_handle
input.h
用于创建驱动层input_dev和handler链表
123456789101112131415 ...
Android Input子系统开篇
前言Input子系统在整个Android 系统中主要管理一些输入设备:按键、触摸屏鼠标等,他是建立在Linux的input子系统上的一套应用层软件架构,主要是处理用户的一些输入行为,反馈给前台的应用或者系统窗口。
Linux的input子系统的范围要更广,包含sensor等设备。
Input子系统系统框架
从框架上看出来,主要分为三部分
Linux 输入设备驱动:处理硬件的输入事件,通过文件系统发送到用户态程序
Android EventHub:通过监控/dev/input/设备节点,来获取Linux输入事件,转化为Android的KeyCode
Android Input Manager Service:将EventHub转化的Android KeyCode发送到合适的window上
分别对应下面的文章进行阐述。
Android ION内存管理(2) -- 共享内存使用
内存共享和大块内存的使用,在实际场景下面的需求是很多的,这里,举三个简单的应用场景:
用户态和内核态共享内存
用户态不同进程内存共享
内核态中使用ION分配buffer
用户态和内核态共享内存
在Android的BSP代码中有一个ion的library封装了一些对ion驱动设备操作的接口system/core/libion/
123456789101112int ion_open();int ion_close(int fd);int ion_alloc(int fd, size_t len, size_t align, unsigned int heap_mask, unsigned int flags, ion_user_handle_t *handle);int ion_alloc_fd(int fd, size_t len, size_t align, unsigned int heap_mask, unsigned int flags, int *handle_fd);int ion_sync_fd(int fd, i ...
Android ION 内存管理
ION的设计初衷Android为了更好的针对移动设备内存的管理,设计出了ION内存管理机制,主要是为了解决以下几个问题:
预留大块连续内存,比如camera,display,GPU等模块
避免内存随便花
用户控件和硬件之间实现”零拷贝”(zero-copy)的内存共享
做Android系统的,特别是跟Display,camera模块相关的
ION的官方介绍和历史由来查看下面的介绍:
https://lwn.net/Articles/480055/
ION的实现Android系统的ION实现依赖于不同的CPU/GPU硬件,Android提供了ION的框架供CPU厂商(NXP, Qualcomm, MTK, 海思等)在自己的BSP里面实现ION机制。
默认的ION驱动会提供以下三种不同的ION heaps实现:
ION_HEAP_TYPE_SYSTEM: memory allocated via vmalloc_user()
ION_HEAP_TYPE_SYSTEM_CONFIG: memory allocated via kzalloc
ION_HEAP_TYPE_CARVEOUT ...
Android HIDL学习(6)---Fast Message Queue
想聊聊FMQ的,无意中看到下面这篇文章,写的很好,所以就直接拿来用了,笑纳笑纳~
https://www.jianshu.com/p/5c6e35c7c346
快速消息队列 (FMQ)HIDL 的远程过程调用 (RPC) 基础架构使用 Binder 机制,这意味着调用涉及开销、需要内核操作,并且可以触发调度程序操作。
不过,对于必须在开销较小且无内核参与的进程之间传输数据的情况,则使用快速消息队列 (FMQ) 系统。
FMQ 会创建具有所需属性的消息队列。MQDescriptorSync 或 MQDescriptorUnsync 对象可通过 HIDL RPC 调用发送,并可供接收进程用于访问消息队列。
MessageQueue 类型Android 支持两种队列类型(称为“风格”):
未同步队列: 可以溢出,并且可以有多个读取器;每个读取器都必须及时读取数据,否则数据将会丢失。
已同步队列: 不能溢出,并且只能有一个读取器。
这两种队列都不能下溢(从空队列进行读取将会失败),并且只能有一个写入器。
未同步未同步队列只有一个写入器,但可以有任意多个读取器。此类队列有一个写入位置 ...
Android HIDL学习(5) ---- 设计要素
前面我们学习了如何使用HIDL来设计或者重构之前在HAL层的代码,而且也对比了一些高性能的编程方式,这里我们在来一下Android的HIDL在设计上的一些考虑。
HIDL指定了数据结构和方法的命名,这些命名类似于JAVA中的类,所以HIDL的语法对于C++和JAVA程序员来说是非常熟悉的,尽管有些关键字不怎么相同,HIDL还使用JAVA的注释方式。
HIDL设计目标HIDL的设计目标是为以后系统更新的时候不用重新编译HAL的模块,HALs被供应商或者SOC厂商负责被编译成vendor.img烧录到系统的/vendor 分区。这样子在后面系统更新的时候只需要更新vendor分区,不需要更新整个OTA包。
HIDL的设计理念平衡一下三个要素:可互操作性:在进程中创建可靠的可互相调用的接口,这种接口偶可以通过不同的交叉编译和和配置来编译成不同的架构。HIDL接口是通过版本来定义的,不同版本的接口可以在发布之后改变。
效率:HIDL的设计在进程通信间尽可能最小化拷贝的动作。HIDL定义的数据在C++标准布局数据结构中被传递到C++代码,这些数据结构可以在不解包的情况下使用。由于使用进程间通 ...
Android HIDL学习(4) ---- 高性能比较(HIDL, FMQ, MMAP)
写在前面公司一些方案,在Andoird P上架构必须要修改成HIDL,不然会遇到一系列的Selinux的问题,所以决定还是按照标准的Android HIDL的架构重新写了方案(因为比较机密,所以不透露具体方案代码)。但是我们的这个模块对性能的要求非常高,不然咱们的设备怎么能打败竞争对手呢,怎么屹立在世界500强呢,对吧。^_^因为我们做的工业设备,对实时性要求比较高,但是HIDL的设计毕竟是需要进程间通信来调用到比较low level的接口的,肯定会有一些性能损失,但是好在还有一些别的机制来挽回损失,本文就来探讨一下这个问题,以及对不同的方式做一下性能的比对。
几种不同的方式对比我们的需求是,应用层需要调用一些接口到kernel中的驱动,有一个HAL层封装了对驱动的操作,应用层去调用HAL层接口,其实就跟标准的AOSP的模块类似。那么问题就来了,以前是直接调用HAL接口,然后通过open/read/write/ioctl来跟驱动通信就好了,比较关心性能损耗就是系统调用到kernel中的时间损耗,其他都还好。但是一旦改成HIDL接口的写法,应用层就变成了HIDL的client端,调用 ...
Android HIDL学习(3) ---- 注册回调
回顾一下上一节我们学会了如何创建HIDL的server端和client端,对于那些没玩过Android O或者以上的BSP开发者而言,可以吹上一阵子牛逼了,毕竟比人家多了一个技能,面试的时候也可以装一下了^_^
OK,我们还知道了在Android O或者以上的Android版本上创建一个HAL模块的一般流程是如何的,我们这一节来看一个比较简单的东西,也是每个模块基本必不可少的一个玩意儿,那就是回调函数。
注册回调怎么个回事呢,我们来举一个栗子
我们把HAL独立为一个单独的进程,client也是一个单独的进程,那么对于一般的模块而言,都是需要从底层(HAL以及以下)获取数据,比如sensor,需要获取sensor数据,Camera,需要获取camera的raw、yuv等数据流,那么对于软件设计而言,如果是同步的话,很简单,我们通过getXXX()函数来获取即可,但是如果是异步的,比如底层的实现是中端的机制,你不知道他什么时候会出来数据,那么这个时候通常的,我们会通过callback来实现异步的回调。
看下面的图就比较清楚了
我们这一节就来实现简单的回调机制。
实战演练这个例子很简 ...
Android HIDL学习(2) ---- HelloWorld
写在前面程序员有个癖好,无论是学习什么新知识,都喜欢以HelloWorld作为一个简单的例子来开头,咱们也不例外。
OK,咱这里都是干货,废话就不多说啦,学习HIDL呢咱们还是需要一些准备工作和门槛的。
准备工作:
Android BSP编译环境
Android设备的BSP代码
Android设备,用来跑测试代码
我这边使用的是公司的设备,打个小广告哈,咱们是世界500强做Android工业手机的,这里使用最近的项目使用的设备,基于Qualcomm 骁龙660芯片,基于这个平台来做开发。
当然了,如果手头上没有设备的话,你也可以使用Andnroid模拟器做开发,Android模拟器的镜像可以使用官方的AOSP代码来编译,但是注意的是如果使用模拟器,kernel要去下载goldfish的代码,这个我这里就不赘述了,可以google了解一下。
Naruto我们需要给这个简单的例子起一个牛逼的名字,我这里叫Naruto,不要问我为什么,哥是一个铁打的火影迷,哈哈,就这么定了,就叫Naruto了,那么那么我们就来说一段故事吧:
咱们可是要写一个Android的HAL, ...