Android电源管理系统调研报告-(4)

来源:互联网 发布:python pdf下载 编辑:程序博客网 时间:2024/04/30 07:07

二、Brightness的调节

现在通过一个具体的电源管理实例来了解从andriod上层到内核驱动层的整个调用流程。

如果你使用过android操作系统,无论是模拟器还是开发板亦或手机,对里面setting这个服务一定很熟悉吧。其中有一项是用于调节显示屏亮度的:

setting/sound & display settings/brightness

这个功能是怎么实现的呢。通过分析,我们可以清晰看到整个调用的流程,上层是如何一步一步到达驱动层,把LCD屏幕亮度改变的。

1android层的调用流程。1)、BrightnessPreference.java

/packages/apps/Settings/src/com/android/settings/

    // Backlight range is from 0 - 255. Need to make sure that user

    // doesn't set the backlight to 0 and get stuck

    private static final int MINIMUM_BACKLIGHT = android.os.Power.BRIGHTNESS_DIM + 10;

    private static final int MAXIMUM_BACKLIGHT = android.os.Power.BRIGHTNESS_ON;

 

当系统检测到调节亮度的调节栏改变时,会重新设置屏幕的亮度:

    public void (CompoundButton buttonView, boolean isChecked) {

        setMode(isChecked ? Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC

                : Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL);

        if (!isChecked) {

             setBrightness(mSeekBar.getProgress() + MINIMUM_BACKLIGHT);

        }

    }

    private void setBrightness(int brightness) {

        try {

            IPowerManager power = IPowerManager.Stub.asInterface(

                     ServiceManager.getService("power"));

            if (power != null) {

                 power.setBacklightBrightness(brightness);

            }

        } catch (RemoteException doe) {            

        }        

     }

 

首先,onCheckedChanged会检查当前亮度调节的模式,如果是AUTOMATIC模式,则isChecked1MANUAL0)。当isChecked0时,即当前模式为手动调节模式,则会调用setBrightness调节亮度。

可以看到,setBrightness先会通过调用ServiceManager.getService("power")获得power manager service这个服务的对象power,获取成功后会调用power.setBacklightBrightness(brightness);我们进入PowerManagerService.java看这个方法的具体内容。

 

2)、PowerManagerService.java

/frameworks/base/services/java/com/android/server/

 

手动调用的范围是MINIMAX。而setBrightness传进来的参数为 MINI + MINIMUM_BACKLIGHT MAX + MINIMUM_BACKLIGHT,以确保brightness最小为MINIMUM_BACKLIGHT。在setBrightness方法的一开始又对brightness进行了修正,从而确保应用程序不能将屏幕全部熄灭。

    // Don't let applications turn the screen all the way off

         brightness = Math.max(brightness, Power.BRIGHTNESS_DIM)

 

setBacklightBrightness这个方法会调节lcd backlightkeyboard light、和buttons light这三个设备的亮度,但都是通过调用setLightBrightness_UNCHECKED实现的。

mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_BACKLIGHT, brightness, HardwareService.BRIGHTNESS_MODE_USER);

         mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_KEYBOARD,            (mKeyboardVisible ? brightness : 0), HardwareService.BRIGHTNESS_MODE_USER);

         mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_BUTTONS, brightness, HardwareService.BRIGHTNESS_MODE_USER);

 

让我们先看一下第一个设备亮度的调节,注意参数LIGHT_ID_BACKLIGHT,它将决定选择操作哪一个设备。

3)、HardwareService.java

/frameworks/base/services/java/com/android/server/

    void setLightBrightness_UNCHECKED(int light, int brightness, int brightnessMode) {

        int b = brightness & 0x000000ff;

        b = 0xff000000 | (b << 16) | (b << 8) | b;

         setLight_native(mNativePointer, light, b, LIGHT_FLASH_NONE, 0, 0, brightnessMode);

     }

setLightBrightness_UNCHECKED调用了本地方法setLight_native,同时将brightness做了相就的处理,处理后的数据作为colorARGB传入本地方法。

 

4)、com_android_server_HardwareService.java

/frameworks/base/services/jni/

 

setLight_native函数中定义了一个类型为struct light_state_t的结构体,并对这个结构体的成员进行赋值,最后对一个函数指针进行了赋值:

devices->lights[light]->set_light(devices->lights[light],&state);

 

先来看看这个结构体:

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;

   

    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;

};

 

 

 

再来看这个函数指针指向的函数。在Lights.c这个文件中的open_lights这个函数中,对传入参数的不同对set_light进行了赋值:

在这里,name传入的是LIGHT_ID_BACKLIGHT

    if (0 == strcmp(LIGHT_ID_BACKLIGHT, name)) {

        set_light = set_light_backlight;

    }

 

set_light_backlight的函数原型如下:

static int

set_light_backlight(struct light_device_t* dev,

        struct light_state_t const* state)

 

再对比一下函数指针的赋值:

devices->lights[light]->set_light(devices->lights[light],&state);

可见,参数devices->lights[light]&state分别传入了devstate

让我们来看一下set_light_backlight的内容:

 

5)、Lights.c

/hardware/msm7k/liblights/

这个文件已经不陌生了吧,上文刚刚提到呵。

set_light_backlight(struct light_device_t* dev,

        struct light_state_t const* state)

{

    int err = 0;

    int brightness = rgb_to_brightness(state);

     pthread_mutex_lock(&g_lock);

    g_backlight = brightness;

    err = write_int(LCD_FILE, brightness);

    if (g_haveTrackballLight) {

         handle_trackball_light_locked(dev);

    }

    pthread_mutex_unlock(&g_lock);

    return err;

}

 

(1)、在这里对brightness进行了特殊的赋值:

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;

}

之所以这样赋值在struct light_state_t的注释中有解释。

 

(2)write_int的参数LCD_FILE

char const*const LCD_FILE

         = "/sys/class/leds/lcd-backlight/brightness";

 

这个路径是kernelsysfs生成的设备节点,用户可以直接对这个设备节点进行操作。

 

sysfs ~~~~~

When a driver is registered, a sysfs directoryis created in its bus's directory. In this directory, the driver can export aninterface to userspace to control operation of the driver on a global basis;e.g. toggling debugging output in the driver.

A future feature of this directory will be a'devices' directory. This directory will contain symlinks to the directories ofdevices it supports.

 

(3)

err = write_int(LCD_FILE, brightness);

write_int(char const* path, int value)

{

    int fd;

    static int already_warned = 0;

 

    fd = open(path, 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) {

             LOGE("write_int failed to open %s/n", path);

            already_warned = 1;

        }

        return -errno;

     }

 

 

打开设备结点后,最终通过writebrigthness写入到了设备结点。