框架图

一、先看framework层提供的API
LightsService中的一些注释
路径frameworks/base/services/java/com/android/server/LightsService.java
//灯的定义
public static final int LIGHT_ID_BACKLIGHT = 0;//LCD背光灯
public static final int LIGHT_ID_KEYBOARD = 1;//键盘灯
public static final int LIGHT_ID_BUTTONS = 2;//按键灯
public static final int LIGHT_ID_BATTERY = 3;//电池灯
public static final int LIGHT_ID_NOTIFICATIONS = 4;//消息通知等灯
public static final int LIGHT_ID_ATTENTION = 5;//警示灯
public static final int LIGHT_ID_BLUETOOTH = 6;//蓝牙灯
public static final int LIGHT_ID_WIFI = 7;//Wifi灯
//闪烁方式
public static final int LIGHT_FLASH_NONE = 0;//不闪烁
public static final int LIGHT_FLASH_TIMED = 1;//根据设定的时间闪烁
public static final int LIGHT_FLASH_HARDWARE = 2;//根据硬件控制的闪烁
/**
* Light brightness is managed by a user setting.
* 背光亮度由用户设置
*/
public static final int BRIGHTNESS_MODE_USER = 0;
/**
* Light brightness is managed by a light sensor.
*背光亮度由光线传感器自动设置
*/
public static final int BRIGHTNESS_MODE_SENSOR = 1;
//存放Light对象的数组
private final Light mLights[] = new Light[LIGHT_ID_COUNT];
//构造方法
LightsService(Context context) {
mNativePointer = init_native();
mContext = context;
ServiceManager.addService("hardware",mLegacyFlashlightHack);
for (int i = 0; i < LIGHT_ID_COUNT; i++) {
mLights[i] = new Light(i);
}
}
/*
*根据id获取对应的Light对象
*/
public Light getLight(int id) {
return mLights[id];
}
//本地方法
private static native int init_native(); //初始化
private static native void finalize_native(int ptr); //释放资源
//设置灯参数
private static native void setLight_native(int ptr, int light, int color, int mode,
int onMS, int offMS, int brightnessMode);
LightsService中的内部类Light的一些注释
Light的方法定义有如下几个:
public void setBrightness(int brightness);
public void setBrightness(int brightness, int brightnessMode);
public void setColor(int color);
public void setFlashing(int color, int mode, int onMS, int offMS);
public void pulse();
public void pulse(int color, int onMS);
public void turnOff();
Light类的方法详解
setBrightness
/*
*这个方法是设置灯的亮度值,它最终会将这个亮度brightness(取值范围0~255)转换成色彩值
*color(ARGB)。我们知道颜色都是三基色RGB组成的,我们要控制的灯基本上都是单色的,
*要么是红色,要么是绿色。所以在转换过程中,是将亮度值对应的数值分别设置到RGB三色
*中,也就是每一个单色上都设置为跟亮度相同的数值,这样无论控制的是什么颜色的灯,都会将
*亮度值设置为brightness。其中0xff000000表示的是ARGB模式,A表示的是透明度。在实际操作过程中,只要亮度值大于0,设置任意数值都会起到相同的作用,都能够达到点亮灯的效果。
*/
public void setBrightness(int brightness, int brightnessMode) {
synchronized (this) {
int color = brightness & 0x000000ff;
color = 0xff000000 | (color << 16) | (color << 8) | color;
setLightLocked(color, LIGHT_FLASH_NONE, 0, 0, brightnessMode);
}
}
setLightLocked
这个方法名中之所以要加上Locked,是因为在调用这个方法的时候都要放在关键字synchronized的作用域中
private void setLightLocked(int color, int mode, int onMS, int offMS, int brightnessMode) {
if (color != mColor || mode != mMode || onMS != mOnMS || offMS != mOffMS) {
if (DEBUG) Slog.v(TAG, "setLight #" + mId + ": color=#"
+ Integer.toHexString(color));
mColor = color;
mMode = mode;
mOnMS = onMS;
mOffMS = offMS;
setLight_native(mNativePointer, mId, color, mode, onMS, offMS, brightnessMode);
}
}
例如其它方法都同步调用setLightLocked方法:
public void turnOff() {
synchronized (this) {
setLightLocked(0, LIGHT_FLASH_NONE, 0, 0, 0);
}
}
private void stopFlashing() {
synchronized (this) {
setLightLocked(mColor, LIGHT_FLASH_NONE, 0, 0, BRIGHTNESS_MODE_USER);
}
}
二、JNI层com_android_server_LightsService.cpp
路径:frameworks/base/services/jni/com_android_server_LightsService.cpp
LightsService调用了LightsService.cpp的本地方法,下面看一下该类。
com_android_server_LightsService.cpp的一些注释
//关键引入hardware模块和lights模块接口
#include <hardware/hardware.h>
#include <hardware/lights.h>
//入口函数,注册方法
int register_android_server_LightsService(JNIEnv *env)
{
return jniRegisterNativeMethods(env, "com/android/server/LightsService",
method_table, NELEM(method_table));
}
//注册方法表
static JNINativeMethod method_table[] = {
{ "init_native", "()I", (void*)init_native },
{ "finalize_native", "(I)V", (void*)finalize_native },
{ "setLight_native", "(IIIIIII)V", (void*)setLight_native },
};
//LIGHT_ID定义,与LightsService.java中定义的必须一致
// These values must correspond with the LIGHT_ID constants in LightsService.java
enum {
LIGHT_INDEX_BACKLIGHT = 0,
LIGHT_INDEX_KEYBOARD = 1,
LIGHT_INDEX_BUTTONS = 2,
LIGHT_INDEX_BATTERY = 3,
LIGHT_INDEX_NOTIFICATIONS = 4,
LIGHT_INDEX_ATTENTION = 5,
LIGHT_INDEX_BLUETOOTH = 6,
LIGHT_INDEX_WIFI = 7,
LIGHT_COUNT
};
//定义结构体
struct Devices {
light_device_t* lights[LIGHT_COUNT];
};
//初始化方法
static jint init_native(JNIEnv *env, jobject clazz)
{
int err;
hw_module_t* module;
Devices* devices;
//为Light设备分配内存
devices = (Devices*)malloc(sizeof(Devices));
//根据模块ID获取Lights模块,LIGHTS_HARDWARE_MODULE_ID定义在lights.h中
//#define LIGHTS_HARDWARE_MODULE_ID "lights"
err = hw_get_module(LIGHTS_HARDWARE_MODULE_ID, (hw_module_t const**)&module);
if (err == 0) { //err=0表示获取Lights模块成功
//Light设备内存的初始化,根据不同的LIGHT_ID获取对应的设备,LIGHT_ID_XX 定义在lights.h中
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);
} else {
memset(devices, 0, sizeof(Devices));
}
return (jint)devices;
}
//根据ID获取设备
static light_device_t* get_device(hw_module_t* module, char const* name)
{
int err;
hw_device_t* device;
//打开设备,err=0表示打开成功
err = module->methods->open(module, name, &device);
if (err == 0) {
return (light_device_t*)device;
} else {
return NULL;
}
}
/*设置Light设备的参数
* env: jni环境变量
* clazz:调用该本地方法的java对象
* ptr: light设备的地址指针
* light: light的id值
* colorARGB:颜色值
* flashMode:闪烁模式(不闪烁/根据设置时间闪烁/硬件控制闪烁)
* onMS: 闪烁时light打开时长
* offMS: 闪烁时light关闭时长
* brightnessMode:背光亮度模式(传感器/用户设置)
*/
static void setLight_native(JNIEnv *env, jobject clazz, int ptr,
int light, int colorARGB, int flashMode, int onMS, int offMS, int brightnessMode)
{
Devices* devices = (Devices*)ptr; //根据指针获取到实例对象
light_state_t state;
//判断light id值是否合法必须>=0并且小于LIGHT_COUNT,设备的light对象不能为空
if (light < 0 || light >= LIGHT_COUNT || devices->lights[light] == NULL) {
return ;
}
//生成参数写入到state对象
memset(&state, 0, sizeof(light_state_t));
state.color = colorARGB;
state.flashMode = flashMode;
state.flashOnMS = onMS;
state.flashOffMS = offMS;
state.brightnessMode = brightnessMode;
{
ALOGD_IF_SLOW(50, "Excessive delay setting light");
//将state对象设置到light对象中
devices->lights[light]->set_light(devices->lights[light], &state);
}
}
//销毁LightService
static void finalize_native(JNIEnv *env, jobject clazz, int ptr)
{
Devices* devices = (Devices*)ptr;
if (devices == NULL) { //对象指向空地址
return;
}
free(devices);//释放内存空间
}
三、Lights Hardware Interfaces
由com_android_server_LightsService.cpp源码中可知,它引入了hardware中的lights.h
路径hardware/libhardware/include/hardware/lights.h
lights.h的一些注释
//关键定义,暂时不知道是做什么用的
#ifndef ANDROID_LIGHTS_INTERFACE_H
#define ANDROID_LIGHTS_INTERFACE_H
/**
* The id of this module 定义模块ID
*/
#define LIGHTS_HARDWARE_MODULE_ID "lights"
/*
* These light IDs correspond to logical lights, not physical.
* So for example, if your INDICATOR light is in line with your
* BUTTONS, it might make sense to also light the INDICATOR
* light to a reasonable color when the BUTTONS are lit.
* 这些LIGHT ID对应着逻辑上的Light,非物理上的。例如,如果您的指示灯与按钮一致,那么当按钮被点亮时,将指示灯点亮到一个合理的颜色也是有意义的
*/
#define LIGHT_ID_BACKLIGHT "backlight"
#define LIGHT_ID_KEYBOARD "keyboard"
#define LIGHT_ID_BUTTONS "buttons"
#define LIGHT_ID_BATTERY "battery"
#define LIGHT_ID_NOTIFICATIONS "notifications"
#define LIGHT_ID_ATTENTION "attention"
/*
* These lights aren't currently supported by the higher
* layers, but could be someday, so we have the constants
* here now.
* 这几个类在将来可以能会被使用,先定义在这里
*/
#define LIGHT_ID_BLUETOOTH "bluetooth"
#define LIGHT_ID_WIFI "wifi"
//关键引入
#include <hardware/hardware.h>
//模式定义
/*
* Flash modes for the flashMode field of light_state_t.
* 不闪烁
*/
#define LIGHT_FLASH_NONE 0
/**
* To flash the light at a given rate, set flashMode to LIGHT_FLASH_TIMED,
* and then flashOnMS should be set to the number of milliseconds to turn
* the light on, followed by the number of milliseconds to turn the light
* off.
* 根据设定的时间闪烁
*/
#define LIGHT_FLASH_TIMED 1
/**
* To flash the light using hardware assist, set flashMode to
* the hardware mode.
* 由硬件控制进行闪烁
*/
#define LIGHT_FLASH_HARDWARE 2
/**
* Light brightness is managed by a user setting. 由用户设定背光亮度
*/
#define BRIGHTNESS_MODE_USER 0
/**
* Light brightness is managed by a light sensor. 由传感器自动设置背光亮度
*/
#define BRIGHTNESS_MODE_SENSOR 1
//定义light_state_t 结构体
/**
* The parameters that can be set for a given light.
* 定义了Light对象所有可以设置的参数
* Not all lights must support all parameters. If you
* can do something backward-compatible, you should.
*/
struct light_state_t {
/**
* The color of the LED in ARGB.
* LED灯ARGS模式的颜色值
* Do your best here.
* - If your light can only do red or green, if they ask for blue,
* you should do green.
* 如果你的灯只能做红色或绿色,如果他们要求蓝色,你应该设置为绿色
* - If you can only do a brightness ramp, then use this formula:
* 如果你只做亮度渐变,那么使用下面这个公式:
* unsigned char brightness = ((77*((color>>16)&0x00ff))
* + (150*((color>>8)&0x00ff)) + (29*(color&0x00ff))) >> 8;
* - If you can only do on or off, 0 is off, anything else is on.
* 如果你只是开关LED,0为关闭,其它值 为打开
* The high byte should be ignored. Callers will set it to 0xff (which
* would correspond to 255 alpha).
*/
unsigned int color;
/**
* See the LIGHT_FLASH_* constants
*/
int flashMode; //闪烁模式
int flashOnMS; //点亮时间
int flashOffMS; //熄灭时间
/**
* Policy used by the framework to manage the light's brightness.
* 框架使用的策略来管理灯光的亮度
* Currently the values are BRIGHTNESS_MODE_USER and BRIGHTNESS_MODE_SENSOR.
*/
int brightnessMode;
};
//定义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. 设置light参数
*/
int (*set_light)(struct light_device_t* dev, struct light_state_t const* state);
};
/*函数名称前面加指针符号“*”,代表它是函数指针。
*函数指针是一个指向函数的指针,函数指针表示一个函数的入口地址。使用函数指针的好处就是在处理“在运行时根据数据的具体状态来选择相应的处理方式”这种需求时更加灵活。
*/
hardware.h
light.h中引用了hardware.h
路径hardware/libhardware/include/hardware/hardware.h
hardwared.h的一些注释
只看一些重要的方法
/**
* Get the module info associated with a module by id.
* 根据module id获取对应的module,例如获取Lights module的ID 就是LIGHTS_HARDWARE_MODULE_ID
* @return: 0 == success, <0 == error and *module == NULL
*/
int hw_get_module(const char *id, const struct hw_module_t **module);
//根据class id获取module,这里暂时不讨论
int hw_get_module_by_class(const char *class_id, const char *inst,
const struct hw_module_t **module);
//重要结构体有三个
struct hw_module_t; //数据结构的字段必须以hw_module_t开头
struct hw_module_methods_t; //然后公共方法
struct hw_device_t; //最后是模块特定信息
//第一个重要结构体
/**
* Every hardware module must have a data structure named HAL_MODULE_INFO_SYM
* and the fields of this data structure must begin with hw_module_t
* followed by module specific information.
* 每个硬件模块都必须有一个名为HAL_MODULE_INFO_SYM的数据结构,该数据结构的字段必须以
* hw_module_t开头,然后是模块特定的信息。
*/
typedef struct hw_module_t {
/** tag must be initialized to HARDWARE_MODULE_TAG */
uint32_t tag; //TAG信息
uint16_t module_api_version; //module 的API版本信息
#define version_major module_api_version
uint16_t hal_api_version; //hal层的API版本信息
#define version_minor hal_api_version
/** Identifier of module */
const char *id; //module id
/** Name of this module */
const char *name; //module名称
/** Author/owner/implementor of the module */
const char *author; //作者
/** Modules methods */
struct hw_module_methods_t* methods; //定义的方法
/** module's dso */
void* dso;
/** padding to 128 bytes, reserved for future use */
uint32_t reserved[32-7];
} hw_module_t;
//可以看到,hw_module_t定义了一些版本,作者和定义的方法等相关信息
//第二个结构体
typedef struct hw_module_methods_t {
/** Open a specific device */
//函数指针
int (*open)(const struct hw_module_t* module, const char* id, struct hw_device_t** device);
} hw_module_methods_t;
//第三个结构体
/**
* Every device data structure must begin with hw_device_t
* followed by module specific public methods and attributes.
* 每个设备数据结构都必须以hw_device_t开头,然后是模块特定的公共方法和属性。
*/
typedef struct hw_device_t {
/** tag must be initialized to HARDWARE_DEVICE_TAG */
uint32_t tag;
uint32_t version;
/** reference to the module this device belongs to */
struct hw_module_t* module;
/** padding reserved for future use */
uint32_t reserved[12];
/** Close this device */
int (*close)(struct hw_device_t* device);//函数指针
} hw_device_t;
抽象接口实现 lights.c
路径vendor/xxx/open-source/libs/liblights/lights.c
注意:linux中的所有操作都是通过文件的形式,所以LED的最终操作也是通过读写节点文件来实现的
该类中提供了操作LED灯节点文件的方法,通过向节点文件写入数据,位于kernel下面的LED灯的驱动程序会检测到文件的改动,进而对LED的状态根据写入的值进行重新设定。
lights.c的一些注释
//定义所有的LED灯类型
//all lights
enum {
RED_LED, //红灯
GREEN_LED, //绿灯
BLUE_LED, //蓝灯
LCD_BACKLIGHT, //LCD背光灯
BUTTONS_LED, //按键背光灯
NUM_LEDS, //LED灯个数
};
//定义LED灯可操作的类型,实际对应了多个节点文件
struct led {
struct led_prop brightness; //设置亮度
struct led_prop high_time;
struct led_prop low_time;
struct led_prop rising_time;
struct led_prop falling_time;
struct led_prop on_off; //开关
};
//定义生成的节点路径
//light nodes
struct led leds[NUM_LEDS] = {
[RED_LED] = {
.brightness = { "/sys/class/leds/red/brightness", -1},
.high_time = { "/sys/class/leds/red_bl/high_time", -1},
.low_time = { "/sys/class/leds/red_bl/low_time", -1},
.rising_time = { "/sys/class/leds/red_bl/rising_time", -1},
.falling_time = { "/sys/class/leds/red_bl/falling_time", -1},
.on_off = { "/sys/class/leds/red_bl/on_off", -1},
},
[GREEN_LED] = {
.brightness = { "/sys/class/leds/green/brightness", -1},
.high_time = { "/sys/class/leds/green_bl/high_time", -1},
.low_time = { "/sys/class/leds/green_bl/low_time", -1},
.rising_time = { "/sys/class/leds/green_bl/rising_time", -1},
.falling_time = { "/sys/class/leds/green_bl/falling_time", -1},
.on_off = { "/sys/class/leds/green_bl/on_off", -1},
},
[BLUE_LED] = {
.brightness = { "/sys/class/leds/blue/brightness", -1},
.high_time = { "/sys/class/leds/blue_bl/high_time", -1},
.low_time = { "/sys/class/leds/blue_bl/low_time", -1},
.rising_time = { "/sys/class/leds/blue_bl/rising_time", -1},
.falling_time = { "/sys/class/leds/blue_bl/falling_time", -1},
.on_off = { "/sys/class/leds/blue_bl/on_off", -1},
},
[LCD_BACKLIGHT] = {
.brightness = { "/sys/class/backlight/sprd_backlight/brightness", -1},
},
[BUTTONS_LED] = {
.brightness = {"/sys/class/leds/keyboard-backlight/brightness", -1},
},
};
//初始化所有节点
void init_globals(void)
{
int i;
for (i = 0; i < NUM_LEDS; ++i) {
init_prop(&leds[i].brightness);
init_prop(&leds[i].high_time);
init_prop(&leds[i].low_time);
init_prop(&leds[i].rising_time);
init_prop(&leds[i].falling_time)
init_prop(&leds[i].on_off);
}
}
//看一下与hardwared.h对应的结构体
/*第一个结构体
* The lights Module
*/
struct hw_module_t HAL_MODULE_INFO_SYM = {
.tag = HARDWARE_MODULE_TAG,
.version_major = 1,
.version_minor = 0,
.id = LIGHTS_HARDWARE_MODULE_ID,
.name = "lights Module",
.author = "Google, Inc.",
.methods = &lights_module_methods,
};
//第二个结构体,通过open_lights获取所有公用函数
static struct hw_module_methods_t lights_module_methods = {
//open是一个函数指针,这里赋值为open_lights,open_lights函数下面有介绍
.open = open_lights,
//打开LED灯函数
static int open_lights(const struct hw_module_t *module, char const *name,
struct hw_device_t **device)
{
int (*set_light)(struct light_device_t *dev, struct light_state_t const *state);
ALOGV("file:%s, func:%s name=%s\n", __FILE__, __func__, name);
//从前面分析lights.h知道,set_light是一个函数指针,其作用就是这里根据不同的LED灯类型,设置不同的处理函数
if (0 == strcmp(LIGHT_ID_BACKLIGHT, name))
set_light = set_light_backlight;
else if (0 == strcmp(LIGHT_ID_KEYBOARD, name))
set_light = set_light_keyboard;
else if (0 == strcmp(LIGHT_ID_BUTTONS, name))
set_light = set_light_buttons;
else if (0 == strcmp(LIGHT_ID_NOTIFICATIONS, name))
set_light = set_light_leds_notifications;
else if (0 == strcmp(LIGHT_ID_ATTENTION, name))
set_light = set_light_leds_attention;
else if (0 == strcmp(LIGHT_ID_BATTERY,name))
set_light = set_light_leds_notifications;
else
return -EINVAL;
pthread_once(&g_init, init_g_lock);
// pthread_once(&g_init, init_globals);
struct light_device_t *dev = malloc(sizeof(struct light_device_t));
memset(dev, 0, sizeof(*dev));
dev->common.tag = HARDWARE_DEVICE_TAG; //设置TAG信息
dev->common.version = 0; //设置版本信息
dev->common.module = (struct hw_module_t *)module; //设置module
dev->common.close = (int (*)(struct hw_device_t *))close_lights; //设置关闭方法
dev->set_light = set_light; //设置设置方法
*device = (struct hw_device_t *)dev;
return 0;
}
//写节点的函数,通过该方法可以向节点写入数据
static int write_int(struct led_prop *prop, int value)
{
int fd;
static int already_warned;
already_warned = 0;
ALOGE("file:%s, func:%s, path=%s, value=%d\n", __FILE__, __func__, prop->filename, value);
// fd = open(path, O_RDWR);
fd = open(prop->filename, O_RDWR);
if (fd >= 0) {
char buffer[20];
int bytes = sprintf(buffer, "%d\n", value);
int amt = write(fd, buffer, bytes);
close(fd);
return amt == -1 ? -errno : 0;
} else {
if (already_warned == 0) { ALOGE("file:%s, func:%s, failed to open %s,fd = %d\n", __FILE__, __func__, prop->filename,fd);
already_warned = 1;
}
return -errno;
}
}
//其它的就是一些设置方法了,简述一下
static int set_light_backlight(struct light_device_t *dev, struct light_state_t const *state)
static int set_light_keyboard(struct light_device_t* dev, struct light_state_t const* state)
static int is_lit(struct light_state_t const* state)
static int set_light_buttons(struct light_device_t* dev, struct light_state_t const* state)
static int set_breath_light(struct light_device_t* dev, struct light_state_t const* state)
....
该文件可能需要根据具体使用的LED灯设备节点进行修改,可参考我另一篇文章Android4.4移植-LED灯驱动适配
四、驱动层
驱动文件一般位于kernel下面,根据不同的硬件厂商而有所不同。
驱动程序会监测上面提到的所有节点文件是否被写入,如果节点文件有写入不同的值,那么驱动程序会读取该值 ,并依据具体情况设定不同的LED灯状态。驱动文件详情不再详述。
如有问题,欢迎交流!!!