屏幕亮度调节
对于屏幕亮度调节 framework层已经有很多文章,再次主要分析一下hal层。
####1、Framework层主要文件BrightnessController.java
#####1.1、文件位置
frameworks/base/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java
#####1.2、主思路代码追踪
public void onChanged(ToggleSlider view, boolean tracking, boolean automatic, int value,
boolean stopTracking) {
updateIcon(mAutomatic);
if (mExternalChange) return;
if (!mAutomatic) {
final int val = value + mMinimumBacklight;
if (stopTracking) {
MetricsLogger.action(mContext, MetricsEvent.ACTION_BRIGHTNESS, val);
}
setBrightness(val);
if (!tracking) {
AsyncTask.execute(new Runnable() {
public void run() {
Settings.System.putIntForUser(mContext.getContentResolver(),
Settings.System.SCREEN_BRIGHTNESS, val,
UserHandle.USER_CURRENT);
}
});
}
} else {
final float adj = value / (BRIGHTNESS_ADJ_RESOLUTION / 2f) - 1;
if (stopTracking) {
MetricsLogger.action(mContext, MetricsEvent.ACTION_BRIGHTNESS_AUTO, value);
}
setBrightnessAdj(adj);
if (!tracking) {
AsyncTask.execute(new Runnable() {
public void run() {
Settings.System.putFloatForUser(mContext.getContentResolver(),
Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, adj,
UserHandle.USER_CURRENT);
}
});
}
}
for (BrightnessStateChangeCallback cb : mChangeCallbacks) {
cb.onBrightnessLevelChanged();
}
}
当它获取到 设置的 brightness 的值之后,主要调用函数 setbrightness() 函数。通过该服务调用底层与设备打交道的C/C++代码,setLightBrightnes原型如下:
####2、跳转到 LightsService.java
#####2.1、文件位置
frameworks/base/services/core/java/com/android/server/lights/LightsService.java
#####2.2、主要代码分析
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);
}
亮度值在此进行了修改,即亮度值的格式变成:FFRRGGBB,FF是没有的,RR、GG、BB分别是256色的红绿蓝,并且红绿蓝的值都是一样的亮度值。
####3、硬件调用 接口com_android_server_lights_LightsService.cpp
#####3.1、文件位置
frameworks/base/services/core/jni/com_android_server_lights_LightsService.cpp
#####3.2、主要代码分析
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_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 (jlong)devices;
}
用hw_get_module获取ID为LIGHTS_HARDWARE_MODULE_ID的硬件模块,该模块含有6个不同类型的亮度控制。
####4、hardware.c 实现 hw_get_module()函数
#####4.1、文件位置
hardware/libhardware/hardware.c
#####4.2、主要代码分析
static const char variant_keys[] = {
“ro.hardware”, / This goes first so that it can pick up a different
file on the emulator. */
“ro.product.board”,
“ro.board.platform”,
“ro.arch”
};
/* Loop through the configuration variants looking for a module */
for (i=0 ; i<HAL_VARIANT_KEYS_COUNT; i++) {
if (property_get(variant_keys[i], prop, NULL) == 0) {
continue;
}
if (hw_module_exists(path, sizeof(path), name, prop) == 0) {
goto found;
}
}
/* Nothing found, try the default */
if (hw_module_exists(path, sizeof(path), name, "default") == 0) {
goto found;
}
return -ENOENT;
found:
/* load the module, if this fails, we're doomed, and we should not try
* to load a different variant. */
return load(class_id, path, module);
}````````
property_get(variant_keys[i], prop, NULL) 会按如下顺序去获取如下变量所对应的值,然后返回给prop:
"ro.hardware", /* This goes first so that it can pick up a different
file on the emulator. */
"ro.product.board",
"ro.board.platform",
"ro.arch"
它们对应的变量为:
"ro.product.board=$TARGET_BOOTLOADER_BOARD_NAME"
"ro.board.platform=$TARGET_BOARD_PLATFORM"
如vendor/htc/dream-open/BoardConfig.mk里定义的TARGET_BOARD_PLATFORM := msm7k,则prop返回” msm7k ”,所以path = /system/lib/hw/lights. msm7k.so,也就是说要获取的硬件模块为lights. msm7k.so。
(此处可自己定义,不一定需要在BoardConfig.mk中 比如在 :device/项目名/项目名 / device.mk 中
```
PRODUCT_PACKAGES += \
logFileManager
#add lights HAL for adjust backlight
PRODUCT_PACKAGES += lights.abc(项目名或板子名字)
PRODUCT_PROPERTY_OVERRIDES += ro.hardware.lights=abc(项目名或板子名字)
# SIM Toolkit
PRODUCT_PACKAGES += \
Stk
```
比如vendor/htc/dream-open/BoardConfig.mk里定义的TARGET_BOARD_PLATFORM := msm7k ,则prop返回” msm7k ”,所以path = /system/lib/hw/lights. msm7k.so,也就是说要获取的硬件模块为lights. msm7k.so。
####5、硬件原型 lights.c 及 android.mk文件
#####5.1、文件位置
/hardware/qcom/display/项目名/liblight/Android.mk
```
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
# HAL module implemenation, not prelinked and stored in
# hw/<COPYPIX_HARDWARE_MODULE_ID>.<ro.board.platform>.so
LOCAL_SRC_FILES := lights.c
LOCAL_MODULE_RELATIVE_PATH := hw
LOCAL_MODULE_TAGS := optional
LOCAL_SHARED_LIBRARIES := liblog
LOCAL_MODULE := lights.(项目名)
include $(BUILD_SHARED_LIBRARY)
```
hardware/qcom/display/项目名/liblight/lights.c
```
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "lights"
#include <cutils/log.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <hardware/lights.h>
#include <hardware/hardware.h>
#define ALOG_ONCE(mask, op, ...) \
do { \
{ \
ALOGE(__VA_ARGS__); \
mask |= op; \
} \
} while (0);
#define OP_WRITE_OPEN (1 << 0)
#define OP_BRIGHTNESS_PATH (1 << 1)
#define OP_BRIGHTNESS_VALUE (1 << 2)
#define OP_BRIGHTNESS_WRITE (1 << 3)
#define OP_MAX_BRIGHTNESS_PATH (1 << 4)
#define OP_MAX_BRIGHTNESS_OPEN (1 << 5)
#define OP_MAX_BRIGHTNESS_READ (1 << 6)
struct dragon_lights {
struct light_device_t base;
pthread_mutex_t lock;
char const *sysfs_path;
int max_brightness;
unsigned long logged_failures;
};
static char const * kBacklightPath =
"/sys/class/backlight/pwm-backlight.0"; (注意此位置不同的设备可能有不同的设备节点)
static struct dragon_lights *to_dragon_lights(struct light_device_t *dev)
{
return (struct dragon_lights *)dev;
}
static int write_brightness(struct dragon_lights *lights, int brightness)
{
char buffer[20], path[PATH_MAX];
int fd, bytes, amt, ret = 0;
ALOGI("LIGHTS write_brightness %d", brightness);
bytes = snprintf(path, sizeof(path), "%s/brightness",
lights->sysfs_path);
if (bytes < 0 || (size_t)bytes >= sizeof(path)) {
ALOG_ONCE(lights->logged_failures, OP_BRIGHTNESS_PATH,
"failed to create brightness path %d\n", bytes);
return -EINVAL;
}
fd = open(path, O_RDWR);
if (fd < 0) {
ALOG_ONCE(lights->logged_failures, OP_WRITE_OPEN,
"write_int failed to open %s/%d\n", path, errno);
return -errno;
}
bytes = snprintf(buffer, sizeof(buffer), "%d\n", brightness);
if (bytes < 0 || (size_t)bytes >= sizeof(buffer)) {
ALOG_ONCE(lights->logged_failures, OP_BRIGHTNESS_VALUE,
"failed to create brightness value %d/%d\n",
brightness, bytes);
ret = -EINVAL;
goto out;
}
amt = write(fd, buffer, bytes);
if (amt != bytes) {
ALOG_ONCE(lights->logged_failures, OP_BRIGHTNESS_WRITE,
"failed to write brightness value %d/%d\n", amt,
bytes);
ret = amt == -1 ? -errno : -EINVAL;
goto out;
}
out:
close(fd);
return ret;
}
static int read_max_brightness(struct dragon_lights *lights, int *value)
{
char buffer[20], path[PATH_MAX];
int ret = 0, fd, bytes;
bytes = snprintf(path, sizeof(path), "%s/max_brightness",
lights->sysfs_path);
if (bytes < 0 || (size_t)bytes >= sizeof(path)) {
ALOG_ONCE(lights->logged_failures, OP_MAX_BRIGHTNESS_PATH,
"failed to create max_brightness path %d\n", bytes);
return -EINVAL;
}
fd = open(path, O_RDONLY);
if (fd < 0) {
ALOG_ONCE(lights->logged_failures, OP_MAX_BRIGHTNESS_OPEN,
"failed to open max_brightness %s/%d\n", path, errno);
return -errno;
}
bytes = read(fd, buffer, sizeof(buffer));
if (bytes <= 0) {
ALOG_ONCE(lights->logged_failures, OP_MAX_BRIGHTNESS_READ,
"failed to read max_brightness %s/%d\n", path, errno);
ret = -errno;
goto out;
}
*value = atoi(buffer);
out:
close(fd);
return ret;
}
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;
}
static int set_light_backlight(struct light_device_t *dev,
struct light_state_t const *state)
{
struct dragon_lights *lights = to_dragon_lights(dev);
int err, brightness_idx;
int brightness = rgb_to_brightness(state);
if(brightness < 0){
brightness = 0;
}
if(brightness >255){
brightness = 255;
}
pthread_mutex_lock(&lights->lock);
err = write_brightness(lights, brightness);
pthread_mutex_unlock(&lights->lock);
return err;
}
static int close_lights(struct hw_device_t *dev)
{
struct dragon_lights *lights = (struct dragon_lights *)dev;
if (lights)
free(lights);
return 0;
}
static int open_lights(const struct hw_module_t *module, char const *name,
struct hw_device_t **device)
{
struct dragon_lights *lights;
int ret;
// Only support backlight at the moment
if (strcmp(LIGHT_ID_BACKLIGHT, name))
return -EINVAL;
lights = malloc(sizeof(*lights));
if (lights == NULL) {
ALOGE("failed to allocate lights memory");
return -ENOMEM;
}
memset(lights, 0, sizeof(*lights));
pthread_mutex_init(&lights->lock, NULL);
lights->sysfs_path = kBacklightPath;
ret = read_max_brightness(lights, &lights->max_brightness);
if (ret) {
close_lights((struct hw_device_t *)lights);
return ret;
}
lights->base.common.tag = HARDWARE_DEVICE_TAG;
lights->base.common.version = 0;
lights->base.common.module = (struct hw_module_t *)module;
lights->base.common.close = close_lights;
lights->base.set_light = set_light_backlight;
*device = (struct hw_device_t *)lights;
return 0;
}
static struct hw_module_methods_t lights_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 = "jindory lights module",
.author = "thundersoft",
.methods = &lights_methods,
};
```
文件参考:
1、 android 设置系统屏幕亮度
http://blog.csdn.net/zhuangxujun/article/details/8601392#comments