从HAL层到Java应用层重写mini6410 led功能
记录了我从HAL层到应用层如何把led这个设备控制实现的过程。如果有遗漏或者错误,请各位高手指点。
led驱动的代码就不说了,以后有空再实现,
第一步,查看linux驱动设备是否工作正常。之后所有的一切,都是在这个leds设备的基础上操作完成的,所以,检查这个设备是不是有用成为了一个很重要的关键。
首先,用adb shell查看Android dev下的目录,发现有leds这个设备:
ls -l /dev/leds 这个设备文件就是android中间层用来操作Linux底层led设备的。
回到android2.3.4源代码目录,在 external目录底下建立testDev目录,在下面分别建立Android.mk 和 testDev.c文件
在testDev.c这个文件里,首先写一个测试程序用来测试Leds这个文件设备能否正常运行;
testDev.c,打开设备关键是ioctl这个函数,其中,第二个参数用来控制是否打开一个led设备,第三个参数用来控制打开的是那个led。(testDev.c 和 Android.mk这2个程序可以见附件。)
全部写完之后,用./build-android编译一下,编译的时候,可以指定特定模块编译,这样比较节省时间。不能用mmm这个命令编译,这个编译了之后product的名称就不是mini6410了,这样很多库都会找不到。编译之后android的out/target/product/mini6410/system/bin/ 目录下面会生成一个叫 testDev的文件,然后将开发板开机,用adb push out/target/product/mini6410/system/bin/testDev system/bin/ 把testDev push到开发板上面去,然后用adb shell命令进入到system/bin/目录下面,运行./testDev 就可以检测leds这个设备是否运行正常。
第二步,为linux的led驱动提供android的HAL层。
HAL是android的硬件逻辑层,在这里,主要是为framework层提供一层Led的操作接口。直接操作leds设备的函数在第一步已经指明了,就是ioctl函数,但是,如何将这个功能增加到android的框架里呢?
首先,增加hardware/libhardware/modules/目录下的mydevice目录,然后在这个目录下再新建Led目录,在led目录下,分别建立led.c和Android.mk文件在mydevice这个目录下,也需要建立Android.mk文件用来搜索mydevice目录下的每个驱动设备目录。在hardware/libhardware/include/hardware 下,建立hardware目录,在下层建立mydevice/led.h,该文件用来实现一些module_id之类的宏和结构体,这里比较重要的是DEVICE_NAME一定要写对,这个就是程序需要读取的设备,还有MODULE_NAME的取名要跟Android.mk里面的LOCAL_MODULE前缀一样,否则程序加载的时候会找不到。硬件结构体是继承hw_device_t这个结构的,在这个结构体里,可以定义leds设备的fd,和这个设备需要操作的一些结构函数,比如这边就增加了set_led,用来控制Led设备的。
最后还要修改hardware/libhardware/ Android.mk,将增加好的led结构添加进去。
include $(addsuffix /Android.mk, $(addprefix $(LOCAL_PATH)/, \
modules/gralloc \
modules/mydevice \ --》增加这行
tests \
))
然后编译一下,out/target/product/mini6410/system/lib/hw目录下会生成led.default.so这个文件,编译就成功了。
第三步,增加jni底层对上层的应用接口。
在这一步当中,封装了底层的.c的接口函数,使得上层Java可以调用, 做到这一步,java应用层应该也可以调用这一步生成的.so,友善提供的.so文件应该就是做到这一步生成的。
这一步当中,首先添加framework/base/services/jni目录下的com_android_server_DeviceService.cpp文件,这个文件用来动态加载jni的接口函数。为java上层提供帮助。Method_table这个表提供了底层到Java层的映射,
static const JNINativeMethod method_table[]=
{
{"openLed", "()Z", (void*)led_init}, --》第一个是java层可以调用的函数名,第二个是函数签名,第三个是本层函数名
{"set_Led", "(II)I", (void*)setLed},
};
java层调用映射之后的字符就可以完成对底层的通讯了。全部写完之后,还要在frameworks/base/services/jni/onload.cpp这个文件当中将method_table这个表加载进系统里(JNI_OnLoad),然后在Android.mk下增加com_android_server_DeviceService.cpp文件就可以编译了。
LOCAL_SRC_FILES:= \
com_android_server_AlarmManagerService.cpp \
com_android_server_BatteryService.cpp \
com_android_server_InputManager.cpp \
com_android_server_LightsService.cpp \
com_android_server_PowerManagerService.cpp \
com_android_server_SystemServer.cpp \
com_android_server_UsbService.cpp \
com_android_server_VibratorService.cpp \
com_android_server_location_GpsLocationProvider.cpp \
com_android_server_DeviceService.cpp \ --》增加这行。
onload.cpp