Android硬件访问服务框架
一 概括
前边内容做了,安卓应用程序通过加载C库,访问硬件驱动程序最终点亮或熄灭LED,我们称为,通过JNI接口直接访问
实际上,安卓系统有可能几个应用程序同时访问一个硬件,可能就会出现问题,怎么办呢,我们一个应用程序访问硬件,这个应用程序就是SystemServer,由它来访问硬件,其他的应用程序APP将访问硬件的请求发给systemserver,由它统一管理,这就是硬件访问服务。
-
SystemServer通过loadlibrary 加载C库。
硬件底层都是用C写的,systemserver用java写的,中间肯定要通过JNI接口,所以加载C库 -
在C库的JNI_Onload 函数中注册本地方法。
系统中有许多硬件,LED,LCD声卡等,每个硬件的本地操作函数都不一样,在这个函数中,分别调用各个硬件的函数来注册本地方法 -
SystemServer,对每个硬件使用本地方法来构造Service,添加服务addService到系统当中
-
最终 APP怎么使用,首先获得服务getService,然后使用服务即执行Service方法,这样应用程序获得Service之后就可以通过本地方法来操作硬件了
二 结合安卓源代码分析
- 过程框图
- 从Android源代码中提取其中文件夹,建立sourceinsight工程
第一步
- 在SystemServer.java文件中main 调用了SystemServer的run方法,在run中可以找
System.loadLibrary("android servers")
用于加载C库,对应的C库文件是onload.cpp
第二🙅步
- 我们知道只要一加载c库,就会调用JNI_Onload, 在onload.cpp中肯定有一个
JNI_Onload()
函数,分别调用各个硬件有关的函数来注册本地方法,如下:
这些函数是分别在某个文件中定义的,有个共同的特点,函数名加上com前缀就是对应的C文件,比如VibratorService 对应的C文件就是 com_android_server_VibratorService.cpp,
第三步
- 在这个文件中可以看到com_android_server_VibratorService.cpp 中调用了
jniRegisterNativeMethods()
方法,注册本地方法,每个硬件函数的本地方法都不一样,每个硬件对应的这个.cpp文件称之为JNI文件
第四步
操作比较简单的可以直接在.cpp的JNI文件中直接调用操作硬件的函数比如open write等函数来访问驱动程序,但是如果硬件操作比较复杂,可以单独把对硬件的操作写在hal文件中,比如 hal_led.c led_driver,Hal是表示硬件抽象层
- 容易修改。这样以后如果修改了硬件操作只需要修改Hal文件就可以了,将对应的so文件放到系统中去就可以了,但是如果在JNI文件中修改硬件的话,一旦需要修改就要编译整个系统。
- 保密。很多公司并不愿意开发硬件操作,只提供so库,让jni直接加载so文件就可以用了
第五步
- 对每个硬件都构造一个Service,然后addService,这个Service肯定会用到上步注册的本地方法
在SystemServer.java中 加载完c库后有调用 startOtherServices() 在这个方法中定义了各种Service
例如:振动器的服务 VibratorService 查找 vibrator
首先是实例化了一个振动器的服务对象,这就是构造Service,会调用到本地方法,然后通过addService() 将这个服务告诉系统,这个系统就是service_manager.c 管理了系统中的所有服务,要想硬件的Service被系统应用使用,必须注册进service_manager 。
怎么实例化Service服务,里边肯定会调用到本地方法,是个java文件 VibratorService.java
搜索native方法,肯定被用到了,这就是服务还是调用的native方法
第六步
- 应用程序就可以通过向service_manager 查询获得某个Service,获取的是ILedService这样的接口,从框图可以看出来,addService的时候是LedService.java,而应用程序getService的时候操作的是ILedService.java,所以应用程序获得的是接口,I表示接口。
第七步
- 应用程序通过ILedService这样的接口把对硬件的操作请求发送给LedService这样的的服务,由这个服务实现对硬件的操作。
整个操作过程涉及到三个进程
- 第一个进程是SystemServer向service_manger注册添加各种Service服务,对应第五步
- 然后应用程序实际上就是客户端,向server_manger查询获得某一个服务的接口,对应第六步
- 应用程序将对硬件操作的服务请求发送给SystemServer,对应第七步
- 这些进程间的通信时通过linux内核的Binder driver实现的,以上几步都涉及到Binder driver,这个驱动程序并不是内核自带的,而是谷歌公司对linux内核做了修改添加了,添加了一个驱动程序,它可以更高效的实现进程间通信
总结:怎么实现硬件访问服务
1. JNI 和HAL
- 写出 com_android_server_LedService.cpp
- 在其中添加
jniRegisterNativeMethods()
实现注册JNI本地方法。 - hal_led.c 中可以调用硬件访问函数,open write等
- 在JNI文件中加载hal
2. 修改onload.cpp
- 调用JNI文件实现的函数
3. 修改SystemServer.java
- 构造硬件服务 new LedService
- 添加服务到系统 addService
4. LedService.java
- 调用本地方法实现硬件操作
5. ILedService.java
- 应用程序要获得服务接口,给APP使用