Android4.4 LightsService使用笔记(二)

简介: 笔记

三、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灯状态。驱动文件详情不再详述。

如有问题,欢迎交流!!!

目录
相关文章
|
7天前
|
Linux 编译器 Android开发
FFmpeg开发笔记(九)Linux交叉编译Android的x265库
在Linux环境下,本文指导如何交叉编译x265的so库以适应Android。首先,需安装cmake和下载android-ndk-r21e。接着,下载x265源码,修改crosscompile.cmake的编译器设置。配置x265源码,使用指定的NDK路径,并在配置界面修改相关选项。随后,修改编译规则,编译并安装x265,调整pc描述文件并更新PKG_CONFIG_PATH。最后,修改FFmpeg配置脚本启用x265支持,编译安装FFmpeg,将生成的so文件导入Android工程,调整gradle配置以确保顺利运行。
26 1
FFmpeg开发笔记(九)Linux交叉编译Android的x265库
|
5天前
|
存储 Java API
Android系统 文件访问权限笔记
Android系统 文件访问权限笔记
37 1
|
6月前
|
Java Android开发
[笔记]Android 学习一之转场动画+ViewPager+ListView简单Demo
[笔记]Android 学习一之转场动画+ViewPager+ListView简单Demo
|
6月前
|
Android开发
[笔记]Android开发之相机开发 Camera1、2、X
[笔记]Android开发之相机开发 Camera1、2、X
|
10月前
|
Java Android开发 容器
Android实战开发--小慕笔记UI设计(Fragment布局的使用)
Android实战开发--小慕笔记UI设计(Fragment布局的使用)
Android实战开发--小慕笔记UI设计(Fragment布局的使用)
|
存储 前端开发 Shell
Android Jetpack Compose——一个简单的笔记APP
此项目功能较为简单,基本就是使用Room数据库实现CRUD,但是此项目实现了一个干净的架构,项目使用MVVM架构进行设计,每一个模块的职责划分清晰,功能明确,没有冗余的代码。其中涉及了Hilt依赖注入,对于数据库的的操作,使用接口实现类进行获取,然后将实现类的CRUD操作封装在一个数据类中,最后通过Hilt自动注入依赖,供外部调用。
583 1
Android Jetpack Compose——一个简单的笔记APP
|
编解码 Java Linux
|
Java Android开发 安全