Android lights system

来源:互联网 发布:php 缺省值 编辑:程序博客网 时间:2024/06/03 08:42
Android 中的灯光子系统采用的是硬件访问服务框架,JNI 层的文件是 com_android_server_lights_LightsService.cpp (frameworks\base\services\core\jni)
Java 程序通过 JNI 调用 setLight_native 来控制背光、通知灯、电池灯灯。 

Java: frameworks/base/services/core/java/com/android/server/lights/LightsService.java
JNI:  frameworks/base/services/core/jni/com_android_server_lights_LightsService.cpp
Hal:  lights.c

默认配色:frameworks/base/core/res/res/values/config.xml
电池灯:frameworks/base/services/core/java/com/android/server/BatteryService.java
通知灯:frameworks/base/services/core/java/com/android/server/notification/NotificationManagerService.java

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;
    }
}

static jlong init_native(JNIEnv *env, jobject clazz)
{
    int err;
    hw_module_t* module;
    Devices* devices;
    
    devices = (Devices*)malloc(sizeof(Devices));

    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_BATTERY]
                = get_device(module, LIGHT_ID_BATTERY);
        devices->lights[LIGHT_INDEX_ATTENTION]
                = get_device(module, LIGHT_ID_ATTENTION);
        ...
    } else {
        memset(devices, 0, sizeof(Devices));
    }

    return (jlong)devices;
}

JNI 文件通过多次调用 open 函数,获得多个不同的 light_device_t ,存入 devices->lights 数组,通过不同的 light_device_t 
调用 devices->lights[light]->set_light(devices->lights[light], &state);
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);
        if (0 == strcmp(LIGHT_ID_BACKLIGHT, name)) {
                set_light = set_light_backlight;
        }
        else if (0 == strcmp(LIGHT_ID_BATTERY, name)) {
                set_light = set_light_battery;
        }
        else if (0 == strcmp(LIGHT_ID_NOTIFICATIONS, name)) {
                set_light = set_light_notifications;
        }
        else {
                return -EINVAL;
        }
        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;
        dev->common.version = 0;
        dev->common.module         = (struct hw_module_t*)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 struct hw_module_methods_t lights_module_methods = {
        .open = open_lights,
}; 
以背光为例:
char const*const LCD_BACKLIGHT_FILE     = "/dev/backlight-1wire";
static int rgb_to_brightness (struct light_state_t const* state) {
        int color = state->color & 0x00ffffff;
        return ((77*((color>>16)&0x00ff))
                        + (150*((color>>8)&0x00ff)) + (29*(color&0x00ff))) >> 8;
}
/* The actual lights controlling section */
static int set_light_backlight (struct light_device_t *dev, struct light_state_t const *state) {
        int brightness = rgb_to_brightness(state);
        ALOGV("%s brightness=%d color=0x%08x", __func__,brightness,state->color);
        pthread_mutex_lock(&g_lock);

        /* brightness 0-255 */
        /* LCD_BACKLIGHT_FILE能接收是0-127 */
        
        write_int (LCD_BACKLIGHT_FILE, brightness/2);
        
        pthread_mutex_unlock(&g_lock);
        return 0;
}
电池灯和通知灯使用的是同一个硬件(RGB三颗led),使用开发板上的3个普通led进行模拟
char const*const RED_LED_FILE                         = "/sys/class/leds/led1/brightness";
char const*const GREEN_LED_FILE                       = "/sys/class/leds/led2/brightness";
char const*const BLUE_LED_FILE                         = "/sys/class/leds/led3/brightness";
代码不在分析

设置LED状态:
struct light_state_t {
    /**
     * The color of the LED in ARGB.
     *
     * 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.
     *
     * The high byte should be ignored.  Callers will set it to 0xff (which
     * would correspond to 255 alpha).
     */
    unsigned int color;  // 把灯设为什么颜色, 或 把LCD的亮度设为什么

    /**
     * See the LIGHT_FLASH_* constants
     */
    int flashMode; // 是否闪烁, LIGHT_FLASH_NONE表示不闪
    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;  // 表示LCD的背光亮度模式
};

完整 HAL 代码
#define LOG_NDEBUG 0
#define LOG_TAG "lights"
#include <cutils/log.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <hardware/lights.h>

char const*const RED_LED_FILE                  = "/sys/class/leds/led1/brightness";
char const*const GREEN_LED_FILE                = "/sys/class/leds/led2/brightness";
char const*const BLUE_LED_FILE                 = "/sys/class/leds/led3/brightness";
char const*const RED_LED_FILE_TRIGGER          = "/sys/class/leds/led1/trigger";
char const*const GREEN_LED_FILE_TRIGGER        = "/sys/class/leds/led2/trigger";
char const*const BLUE_LED_FILE_TRIGGER         = "/sys/class/leds/led3/trigger";
char const*const RED_LED_FILE_DELAYON          = "/sys/class/leds/led1/delay_on";
char const*const GREEN_LED_FILE_DELAYON        = "/sys/class/leds/led2/delay_on";
char const*const BLUE_LED_FILE_DELAYON         = "/sys/class/leds/led3/delay_on";
char const*const RED_LED_FILE_DELAYOFF         = "/sys/class/leds/led1/delay_off";
char const*const GREEN_LED_FILE_DELAYOFF       = "/sys/class/leds/led2/delay_off";
char const*const BLUE_LED_FILE_DELAYOFF        = "/sys/class/leds/led3/delay_off";
char const*const LCD_BACKLIGHT_FILE            = "/dev/backlight-1wire";

/* Synchronization primities */
static pthread_once_t g_init = PTHREAD_ONCE_INIT;
static pthread_mutex_t g_lock = PTHREAD_MUTEX_INITIALIZER;
/* Mini-led state machine */
static struct light_state_t g_notification;
static struct light_state_t g_battery;


static int write_int (const char *path, int value) {
        int fd;
        static int already_warned = 0;
        fd = open(path, O_RDWR);
        if (fd < 0) {
                if (already_warned == 0) {
                        ALOGE("write_int failed to open %s\n", path);
                        already_warned = 1;
                }
                return -errno;
        }
        char buffer[20];
        int bytes = snprintf(buffer, sizeof(buffer), "%d\n", value);
        int written = write (fd, buffer, bytes);
        close(fd);
        return written == -1 ? -errno : 0;
}
static int write_string (const char *path, const char *value) {
        int fd;
        static int already_warned = 0;
        fd = open(path, O_RDWR);
        if (fd < 0) {
                if (already_warned == 0) {
                        ALOGE("write_string failed to open %s\n", path);
                        already_warned = 1;
                }
                return -errno;
        }
        char buffer[20];
        int bytes = snprintf(buffer, sizeof(buffer), "%s\n", value);
        int written = write (fd, buffer, bytes);
        close(fd);
        return written == -1 ? -errno : 0;
}
/* Color tools */
static int is_lit (struct light_state_t const* state) {
        return state->color & 0x00ffffff;
}
static int rgb_to_brightness (struct light_state_t const* state) {
        int color = state->color & 0x00ffffff;
        return ((77*((color>>16)&0x00ff))
                        + (150*((color>>8)&0x00ff)) + (29*(color&0x00ff))) >> 8;
}
/* The actual lights controlling section */
static int set_light_backlight (struct light_device_t *dev, struct light_state_t const *state) {
        int brightness = rgb_to_brightness(state);
        ALOGV("%s brightness=%d color=0x%08x", __func__,brightness,state->color);
        pthread_mutex_lock(&g_lock);

        /* brightness 0-255 */
        /* LCD_BACKLIGHT_FILE能接收是0-127 */
        
        write_int (LCD_BACKLIGHT_FILE, brightness/2);
        
        pthread_mutex_unlock(&g_lock);
        return 0;
}
static void set_shared_light_locked (struct light_device_t *dev, struct light_state_t *state) {
        int r, g, b;
        int delayOn,delayOff;
        r = (state->color >> 16) & 0xFF;
        g = (state->color >> 8) & 0xFF;
        b = (state->color) & 0xFF;
        delayOn = state->flashOnMS;
        delayOff = state->flashOffMS;
        if (state->flashMode != LIGHT_FLASH_NONE) {
                write_string (RED_LED_FILE_TRIGGER, "timer");
                write_string (GREEN_LED_FILE_TRIGGER, "timer");
                write_string (BLUE_LED_FILE_TRIGGER, "timer");
                write_int (RED_LED_FILE_DELAYON, delayOn);
                write_int (GREEN_LED_FILE_DELAYON, delayOn);
                write_int (BLUE_LED_FILE_DELAYON, delayOn);
                write_int (RED_LED_FILE_DELAYOFF, delayOff);
                write_int (GREEN_LED_FILE_DELAYOFF, delayOff);
                write_int (BLUE_LED_FILE_DELAYOFF, delayOff);
        } else {
                write_string (RED_LED_FILE_TRIGGER, "none");
                write_string (GREEN_LED_FILE_TRIGGER, "none");
                write_string (BLUE_LED_FILE_TRIGGER, "none");
        }
        write_int (RED_LED_FILE, r);
        write_int (GREEN_LED_FILE, g);
        write_int (BLUE_LED_FILE, b);
}
static void handle_shared_battery_locked (struct light_device_t *dev) {
        if (is_lit (&g_notification)) {
                set_shared_light_locked (dev, &g_notification);
        } else {
                set_shared_light_locked (dev, &g_battery);
        }
}
static int set_light_battery (struct light_device_t *dev, struct light_state_t const* state) {

        ALOGV("%s flashMode=%d onMS = %d offMS = %d color=0x%08x", __func__,state->flashMode,state->flashOnMS,state->flashOffMS,state->color);

        pthread_mutex_lock (&g_lock);
        g_battery = *state;
        handle_shared_battery_locked(dev);
        pthread_mutex_unlock (&g_lock);
        return 0;
}
static int set_light_notifications (struct light_device_t *dev, struct light_state_t const* state) {
        ALOGV("%s flashMode=%d onMS = %d offMS = %d color=0x%08x", __func__,state->flashMode,state->flashOnMS,state->flashOffMS,state->color);
        pthread_mutex_lock (&g_lock);
        g_notification = *state;
        handle_shared_battery_locked(dev);
        pthread_mutex_unlock (&g_lock);
        return 0;
}
/* Initializations */
void init_globals () {
        pthread_mutex_init (&g_lock, NULL);
}
/* Glueing boilerplate */
static int close_lights (struct light_device_t *dev) {
        if (dev)
                free(dev);
        return 0;
}
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);
        if (0 == strcmp(LIGHT_ID_BACKLIGHT, name)) {
                set_light = set_light_backlight;
        }
        else if (0 == strcmp(LIGHT_ID_BATTERY, name)) {
                set_light = set_light_battery;
        }
        else if (0 == strcmp(LIGHT_ID_NOTIFICATIONS, name)) {
                set_light = set_light_notifications;
        }
        else {
                return -EINVAL;
        }
        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;
        dev->common.version = 0;
        dev->common.module         = (struct hw_module_t*)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 struct hw_module_methods_t lights_module_methods = {
        .open = open_lights,
};
struct hw_module_t HAL_MODULE_INFO_SYM = {
        .tag = HARDWARE_MODULE_TAG,
        .version_major = 1,
        .version_minor = 0,
        .id = LIGHTS_HARDWARE_MODULE_ID,
        .name = "Sony lights module",
        .author = "Diogo Ferreira <defer@cyanogenmod.com>, Andreas Makris <Andreas.Makris@gmail.com>",
        .methods = &lights_module_methods,
};

原创粉丝点击