(有不对的地方希望大家给予指正
)
要了解android驱动,很重要的一点就是要熟悉HAL(硬件抽象层),HAL的作用是把Android Framework与linux内核隔离,使android不过度依赖linux kernel,从而让Android Framework开发可以在不考虑驱动程序的前提下进行(我的理解是厂商已经把驱动做在HAL层,他们没有把这一层驱动代码开源,都已经做成现成的驱动模块,我们只需要根据接口调用就可以了)。 HAL中主要有如下三个结构:
struct hw_module_t
struct hw_module_methods_t
struct hw_module_device_t
这三种结果的继承关系是:hw_module_methods_t继承struct hw_module_t,struct hw_module_t继承struct hw_module_device_t;
其中hw_module_device_t主要实现的是设备关闭的一些操作。struct hw_module_t主要实现的是设备一些基本参数,比如id,name,version等。hw_module_methods_t主要实现了设备打开等一些操控方法。我的理解是类似于linux驱动里的file_operation;
hw_get_module():能够根据模块ID寻找硬件模块动态链接库的地址,然后调用load打开动态链接库从中获取硬件模块结构体地址。
mokoid工程分析
mokoid是google提供的一个LedTest示例程序,通过了解这个工程源码,对理解android层次结构,HAL编程方法非常有意义。我们可以从网络获取这个源码。
mokid结构如下:
JNI是Java程序可以调用C/C++写的动态链接库,要通过JNI实现android的HAL层。在android下有如下两种方法访问HAL。
1、app程序直接通过service调用.so格式的JNI:这种方法比较简单,但是不规范。
2、通过manage调用service:此方法实现起来比较复杂,但是符合目前的android框架。
第一种方法:直接调用service方法的实现过程
部分代码经过修改,后面的章节会给出修改的原因。
文件:mokoid-read-only/hardware/modules/include/mokoid/led.h
/***************************************************************************/
struct led_module_t {
struct hw_module_t common;
};
//HAL 规定不能直接使用hw_module_t结构,因此需要做这么一个继承。
struct led_control_device_t {
//自定义的一个针对Led控制的结构,包含hw_device_t和支持的API操作
struct hw_device_t common;
/* attributes */
int fd; //可用于具体的设备描述符
/* supporting control APIs go here */
int (*set_on)(struct led_control_device_t *dev, int32_t led);
int (*set_off)(struct led_control_device_t *dev, int32_t led);
};
#define LED_HARDWARE_MODULE_ID "led"
//定义一个MODULE_ID,HAL层可以根据这个ID找到我们这个HAL stub
文件:mokoid-read-only/hardware/modules/led/led.c
总结:由此可见HAL层主要是对下面三个函数的实现。
struct hw_module_t
struct hw_module_methods_t
struct hw_module_device_t
这三个函数包含的对设备的一些底层的控制操作。
(2)JNI层
文件:mokoid-read-only/frameworks/base/service/jni/com_mokoid_server_LedService.cpp
总结:JNI层首先根据HAL层注册的ID找到hw_module_t,
然后通过hw_module_t找到相应的led_control_t.然后JNI就可
以调用HAL里控制方法。再把这些方法进行注册。
(3)service (属于Framework层)
总结:这一步主要就是sevice加载JNI动态库,调用JNI注册的函数
(4)APP 测试程序 (属于APP层)
文件:apps/LedClient/src/com/mokoid/LedClient/LedClient.java
总结:app通过service调用
5、第二种方法:经过Manager调用service
HAL、JNI两层和第一种方法一样,所以后面只分析其他的层次。
(1)Manager (属于Framework层)
APP通过这个Manager和service通讯。
文件:mokoid-read-only /frameworks/base/core/java/mokoid/hardware/LedManager.java
ILedService.Stub就是ILedService.aidl由aidl工具自动生成的类。
因为LedService和LedManager在不同的进程,所以要考虑到进程通讯的问题。Manager通过增加一个aidl文件来描述通讯接口
文件:mokoid-read-only/frameworks/base/core/java/mokoid/hardware/ILedService.aidl
(2)SystemServer (属于APP层)
文件:mokoid-read-only/apps/LedTest/src/com/mokoid/LedTest/LedSystemServer.java
(3)APP 测试程序(属于APP层)
文件:mokoid-read-only/apps/LedTest/src/com/mokoid/LedTest/LedTest.java
五、实验中需要注意的问题
将下载后的源码放到你的android源码目录下,然后编译系统。本实验用的android版本为2.1。实验的过程中大致出现过以下几个问题:
1、目标系统中没有生成LedClient.apk或LedTest.apk应用程序
编译完成后,没有在目标系统的system/app/目录下找到LedClient.apk或LedTest应用程序。只有通过单独编译LedClient或LedTest才能在目标目录中生成。方法如下:
#mmm mokoid-read-only/apps/LedTest/
检查原因后发现mokoid-read-only/apps/LedTest/Android.mk
LOCAL_MODULES_TAGS :=user
而我们的s5pc100系统在配置时tapas时选择的是eng,所以没有装载到目标系统。
所以修改LedTest和LedClient的Android.mk
LOCAL_MODULES_TAGS :=user eng
再次编译即可自动装载到目标系统/system/app/目录下。
2、启动后没有图标,找不到应用程序
目标系统启动后找不到两个应用程序的图标。仔细阅读logcat输出的信息发现:
E/PackageManager( 2717): Package com.mokoid.LedClient requires unavailable shared library com.mokoid.server; failing!
原因是找不到 com.mokoid.server。检查mokoid-read-only/frameworks/base/Android.mk发现系统将LedManager和LedService编译成 mokoid.jar库文件。为了让应用程序可以访问到这个库,需要通过com.mokoid.server.xml 来设定其对应关系。解决方法:拷贝com.mokoid.server.xml到目标系统的system/etc/permissions/目录下。
此时两个应用的程序的图标都正常出现了。
3、提示找不到 JNI_OnLoad
按照以前的实验加入下列代码:
4、需要针对你的目标平台修改HAL的Makefile
修改mokoid-read-only/hardware/modules/led/Android.mk
LOCAL_MODULE := led.default
5、在eclipse中编译不了LedSystemServer.java
原因是程序中要用到ServiceManager.addService,这需要系统权限。
解决方法可以把应用程序放入Android源码中编译,并确保以下两点:
(1)在应用程序的AndroidManifest.xml中的manifest节点中加入android:sharedUserId="android.uid.system"这个属性。
(2)修改Android 加入LOCAL_CERTIFICATE := platform.
当然:mokoid工程源码中已经做了这些。
(待续)