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

二、 Brightness 的调节

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

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

setting/sound & display settings/brightness

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

1 android 层的调用流程。 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 模式,则 isChecked 1 MANUAL 0 )。当 isChecked 0 时,即当前模式为手动调节模式,则会调用 setBrightness 调节亮度。

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

 

2 )、 PowerManagerService.java

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

 

手动调用的范围是 MINI MAX 。而 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 backlight keyboard 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 分别传入了 dev state

让我们来看一下 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";

 

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

 

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;

      }

 

 

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

你可能感兴趣的:(Android电源管理系统调研报告-(4))