通过前面的学习,我们知道 Android系统框架大致如下图所示
总的来说可以分为四个层次
1. app应用层:(主要由java语言编写)
2. Framework层:该层主要是实现的是JNI,让APP具有调用C语言的能力(涉及java,c++,c语言)
3. 硬件操控层:一般都是操作硬件的封装库,其实就是相当于llinux系统中的应用层(一般由C语言编写,少数也可以使用C++)
4. linux驱动:和linux系统中基本一(由C语言编写)
在第二章的讲解中,为我们操控LED,我们也实现了以下四个部分:
1.app:就是我们的AS工程,主要涉及文件为MainActivity.java
2.JNI:向上(APP)提供访问硬件的接口,向下访问HAL主要涉及文件为com_android_server_LedService.cpp
3.HAL:具体硬件操作,主要涉及文件led_hal.c
4.底层驱动:主要涉及文件led_drv.c
这样我们就能通过android系统的硬件访问服务操控LED了,但是这里存在一个问题,com_android_server_LedService.cpp文件,是由我们根据硬件设计编写的,那么,也只有我们自己才知道怎么使用,或者说,我们需要告诉别人怎么使用,别人根据我们的规定,调用我们的接口才能点亮LED,这样通用性就变得十分的低下了,别人以前编写的点灯APP很难适用于我们的开发板,那么下面我们就开始讲解灯光系统,我们使用系统给我们提供的com_android_server_xxxService.cpp去编写HAL文件,这样达成统一标准,在其他手机或者开发板运行APP不用做修改,就能直接在我们的开发板上运行并且操控LED了
灯光系统框架
灯管系统框架也和我们之前的一样,如果需要通过APP操控LED,他也仍然要实现之前的四个层次:
1. APP(电池灯,通知灯,背光灯:根据客户需求进行编写)
2. com_android_server_LightsService.cpp(系统已经完成)
3. HAL,需要我们自己编写light.c
4. led_gec3399_drv.c:之前的led_drv已经不再适用,需要进行修改
既然了解了整体框架,我们分析一下看看JNI,即com_android_server_lights_LightsService.cpp文件,只有我们知道这个框架需要什么,我们才能很好的去编写 HAL以及硬件驱动,打开文件:
static const JNINativeMethod method_table[] = {
{ "init_native", "()J", (void*)init_native },
{ "finalize_native", "(J)V", (void*)finalize_native },
{ "setLight_native", "(JIIIIII)V", (void*)setLight_native },
};
可以看到为java程序提供了3个接口,以后我们的java程序则可以通过这3个接口调用C函数,达到访问硬件的目的。在第二张的时候,我们已经讲解了JNI通过hw_get_module等,去访问HAL文件,在com_android_server_lights_LightsService.cpp中由类似代码:
err = hw_get_module(LIGHTS_HARDWARE_MODULE_ID, (hw_module_t const**)&module);
if (err == 0) {
devices->lights[LIGHT_INDEX_BACKLIGHT]
= get_device(module, LIGHT_ID_BACKLIGHT);
devices->lights[LIGHT_INDEX_KEYBOARD]
= get_device(module, LIGHT_ID_KEYBOARD);
devices->lights[LIGHT_INDEX_BUTTONS]
= get_device(module, LIGHT_ID_BUTTONS);
devices->lights[LIGHT_INDEX_BATTERY]
= get_device(module, LIGHT_ID_BATTERY);
devices->lights[LIGHT_INDEX_NOTIFICATIONS]
= get_device(module, LIGHT_ID_NOTIFICATIONS);
devices->lights[LIGHT_INDEX_ATTENTION]
= get_device(module, LIGHT_ID_ATTENTION);
devices->lights[LIGHT_INDEX_BLUETOOTH]
= get_device(module, LIGHT_ID_BLUETOOTH);
devices->lights[LIGHT_INDEX_WIFI]
= get_device(module, LIGHT_ID_WIFI);
}
其中hw_get_module函数返回一个hw_module_t结构体,那么我们在HAL文件中,就需要实现一个hw_module_t结构体。其中get_device函数的实现如下:
static light_device_t* get_device(hw_module_t* module, char const* name)
{
int err;
hw_device_t* device;
err = module->methods->open(module, name, &device);
if (err == 0) {
return (light_device_t*)device;
} else {
return NULL;
}
}
其作用是从hw_module_t根据传入的名字 name获取不同的light_device_t结构体,在后续中,我们只需要实现LIGHT_ID_BACKLIGHT以及LIGHT_ID_BATTERY对应的light_device_t结构体,其余的返回NULL即可。
根据我们分析com_android_server_lights_LightsService.cpp文件之后,我们大致知道,HAL文件编写的需求
1. 实现一个hw_module_t结构体
2. 实现一个open函数,他会根据传入的name返回不同light_device_t
light_device_t结构体定义如下:
struct light_device_t {
struct hw_device_t common;
/**
* Set the provided lights to the provided values.
*
* Returns: 0 on succes, error code on failure.
*/
int (*set_light)(struct light_device_t* dev,
struct light_state_t const* state);
};
很显然。对于不同的灯,对应的set_light函数也不一样,所以我需要为背光灯,通知灯,电池灯等实现不同的set_light函数,然后在该函数内去操控驱动程序。
那么对于驱动程序应该怎么编写呢,实现那些功能呢?
1.对于RGB灯:实现亮,灭,闪烁三个功能
2.对于背光灯:一般实现PWM。
该小节主要讲解了灯光系统的框架,以及对应的JNI文件com_android_server_lights_LightsService.cpp的需求分析,在接下来的几个小节,我们会讲解1.写驱动,2.写HAL,3.分析电池灯的使用过程,4.分析通知灯使用过程,5.分析背光灯使用过程。