电源管理
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Android电源管理系统调研报告-(1)
2011-02-17 09:18
转载自carvencao
最终编辑carvencao
如今手持设备中出现的一对不可调和的矛盾就是越来越大的能量消耗与电池容量瓶颈之间的矛盾,就算没有这个瓶颈,相对更持久的续航能力也是众向所归。
Android系统一般应用于高端智能设备,能源消耗尤其突出,因此对Android 的电源管理系统的调研有很必要。
Android系统是基于标准Linux内核之上的,在Linux内核在原有的power manager系统之上增加了相应了文件,为Android系统的power manager提供底层服务支持。
因此,调研工作在两个层面展开:Linux内核层、Android系统层。
Linux内核层:
针对Android系统而增添的power manager文件有如下五个:
/Linux-2.6.29/kernel/power/
|-consoleearlysuspend.c
|-earlysuspend.c
|-fbearlysuspend.c
|-userwakelock.c
|-wakelock.c
这五个文件配合Linux层的power manager柜架和与功耗相关的设备驱动,向Android层提供了power manager的底层支持。
与功耗相关的设备主要包括LCD屏和键盘及其它设备的LED灯。
因些,在这类设备的驱动中应该增加相应的power manager功能。
在该调研报告中,仅简单地罗出列出各文件中定义的功能函数以及向上提供的接口,其具体的功能调用及整个power manager柜架地实现在后期的调研报告中阐述。
1)、consoleearlysuspend.c
功能函数:
static void console_early_suspend(struct early_suspend *h);
static void console_late_resume(struct early_suspend *h);
static int __init console_early_suspend_init(void);
static void __exit console_early_suspend_exit(void);
数据结构:
static struct early_suspend console_early_suspend_desc = { .level = EARLY_SUSPEND_LEVEL_STOP_DRAWING,
.suspend = console_early_suspend,
.resume = console_late_resume,
};
2、earlysuspend.c
功能函数:
void register_early_suspend(struct early_suspend *handler);
void unregister_early_suspend(struct early_suspend *handler);
static void early_suspend(struct work_struct *work);
static void late_resume(struct work_struct *work);
void request_suspend_state(suspend_state_t new_state); suspend_state_t get_suspend_state(void);
供驱动使用的函数接口:
EXPORT_SYMBOL(register_early_suspend);
EXPORT_SYMBOL(unregister_early_suspend);
在earlysuspend.h文件中定义了注册接口函数:
#ifdef CONFIG_HAS_EARLYSUSPEND
void register_early_suspend(struct early_suspend *handler);
void unregister_early_suspend(struct early_suspend *handler);
3、fbearlysuspend.c
功能函数:
static void stop_drawing_early_suspend(struct early_suspend *h);
static void start_drawing_late_resume(struct early_suspend *h);
static ssize_t wait_for_fb_sleep_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf);
static ssize_t wait_for_fb_wake_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf);
static int __init android_power_init(void);
static void __exit android_power_exit(void)
主要的数据结构:
static struct early_suspend stop_drawing_early_suspend_desc = {
.level = EARLY_SUSPEND_LEVEL_STOP_DRAWING,
.suspend = stop_drawing_early_suspend,
.resume = start_drawing_late_resume,
};
在以上面的几个函数中,都调用了__wake_up:
在sched.c中定义了这个函数
/**
* __wake_up - wake up threads blocked on a waitqueue.
* @q: the waitqueue
* @mode: which threads
* @nr_exclusive: how many wake-one or wake-many threads to wake up
* @key: is directly passed to the wakeup function
*/
void __wake_up(wait_queue_head_t *q, unsigned int mode,
int nr_exclusive, void *key)
{
unsigned long flags;
spin_lock_irqsave(&q->lock, flags);
__wake_up_common(q, mode, nr_exclusive, 0, key);
spin_unlock_irqrestore(&q->lock, flags);
}
4、userwakelock.c
static struct user_wake_lock *lookup_wake_lock_name(const char *buf, int allocate, long *timeoutptr);
ssize_t wake_lock_show(struct kobject *kobj, struct
kobj_attribute *attr, char *buf);
ssize_t ssixe_t wake_lock_store(struct kobject *kobj, struct kobj_attribute *attr,
const char *buf, size_t n);
ssize_t wake_unlock_show(struct kobject *kobj, struct
kobj_attribute *attr, char *buf);
ssize_t wake_unlock_store(struct kobject *kobj, struct
kobj_attribute *attr, const char *buf, size_t n);
5、wakelock.c
提供了接口函数有:
EXPORT_SYMBOL(wake_lock_init);
EXPORT_SYMBOL(wake_lock_destroy);
EXPORT_SYMBOL(wake_lock);
EXPORT_SYMBOL(wake_lock_timeout);
EXPORT_SYMBOL(wake_unlock);
EXPORT_SYMBOL(wake_lock_active);
以上函数仅提供了一个android power manager实现的底层柜架,要使其很好的work起来,需要相关设备driver的支持和与Android层power manager 系统很好的配合。
Android系统层
Android层的电源管理主要在framework层实现,其中battery的管理包括充放电状态、电量显示等,但这部分暂不在调研范围之间。
该部分调研的重点在于LCD以及相关设备LED状态的切换。
相关文件包括:
/frameworks/base/services/java/com/android/server/PowerManagerSer vice.java
/platform/frameworks/base/core/java/android/os/PowerManager.java /platform/frameworks/base/core/java/android/os/Power.java
/frameworks/base/core/jni/android_os_Power.cpp
/hardware/libhardware_legacy/power/power.c
引用一张比较全面的power manager框架图,我们可以看到power manager 的核心代码在PowerManagerService.java中,该文件通过利用PowerManager.java提供的类,android_os_Power.cpp提供的一些本地方法以及power.c对底层的调用,完成了android系统power manager的各自服务。
该文件的分析见后续的调研报告。
Android电源管理系统调研报告-(2)
2011-01-04 14:17
1)、PowerManager.java
该文件定义了一个PowerManager类供其它文件使用,该类嵌套了一个nest class:
public class WakeLock,该nest class有如下方法:
该nest class的构造方法为:
WakeLock(int flags, String tag)
其中有一个关键的参数flags,它有如下几种情况:
PARTIAL_WAKE_LOCK: Screen off, keyboard light off
SCREEN_DIM_WAKE_LOCK: screen dim, keyboard light off
SCREEN_BRIGHT_WAKE_LOCK: screen bright, keyboard light off
FULL_WAKE_LOCK: screen bright, keyboard bright
上面4种是互斥的,即只能指定其中之一,但可以与下面两种flag不是互斥的:ACQUIRE_CAUSES_WAKEUP: 一旦有请求锁时强制打开Screen和keyboard light ON_AFTER_RELEASE: 在释放锁时reset activity timer
除了这个内部类,powermanager类定义了如下方法:
该类的构造方法有两个:
private PowerManager()
public PowerManager(IPowerManager service, Handler handler)
2、Power.java
PowerManagerSerivive.java中调用了一些本地方法,该文件作为这些方法的java层与jni的中间层,声明了本地接口。
3、andriod_ow_Power.cpp
该文件编写了本地实现方法,从本地方法列表可以知道该本地方法与power.c 是密切相关的:
4、power.c
该文件作为Android系统的最底层,与Linux内核的power manager交互。
Android电源管理系统调研报告-(3)
2011-01-04 14:18
一、powermanagerservice.java1、nest class
1)、private class UnsynchronizedWakeLock
从类名可以看出这个类实现的是异步获取唤醒锁。
当PowerManager.WakeLock 与 synchronizing on mLocks之间发生死锁的时候,这个类可以重新实现PowerManager.WakeLock。
由于它没有外部同步块,所以只有当拥有锁的时候才调用这个类。
该类实现的方法有:
构造方法:
2)、private final class BatteryReceiver extends BroadcastReceiver
这个类是个广播接收,至于广播的使用,这里不作深入的探讨。
该类重载了接收的方法。
当然,接收的过程是有约束的,即同步mLocks。
3)、private final class BootCompletedReceiver extends BroadcastReceiver
该广播能接收到启动完成后的消息,而后调用bootCompleted()。
4)、private final class DockReceiver extends BroadcastReceiver
5)、private class SettingsObserver implements Observer
6)、private class WakeLock implements IBinder.DeathRecipient
方法public void binderDied()会调用releaseWakeLockLocked
7)、private class PokeLock implements IBinder.DeathRecipient
方法public void binderDied() 调用
setPokeLock(0,this.binder, this.tag);
8)、private class TimeoutTask implements Runnable
该类实现了Runnable接口,有一个run方法。
run方法实现的是Timeout后进行的动作,
setTimeoutLocked(now,SCREEN_DIM);?setTimeoutLocked(now,SCREEN_OFF);
9)、class BrightnessState
该类定义的方法有
10)、private class LightAnimator implements Runnable 该类实现了Runnable接口,有一个run方法
run方法实现的是亮度变化的控制:
这三个设备亮度分步控制。
11)、private class GservicesChangedReceiver extends BroadcastReceiver
该类继承了广播接口的类,方法onReceive调用了updateGservicesValues()。
该类当接收到google service改变的广播时,就受调用updateGservicesValues()。
12)、private class LockList extends ArrayList<WakeLock>
方法:
该类实践上是建立了一了锁队列/锁列表,该队列可以通过addLock新建一个锁,也可以通过removeLock从队列中摘除一个锁,可以通过getIndex查询指定锁在队列中的索引号
定义了一个该类的实例
private final LockList mLocks = new LockList();
整个service中方法的调用都同步这个对象mLocks
synchronized (mLocks)
2、相关的service:BatteryService
mBatteryService.isPowered()
mBatteryService.getBatteryLevel()
BatteryStatsService.getService() GservicesHardwareserviceActivityService
3、参数
//flags for setPowerState
private static final intSCREEN_ON_BIT = 0x00000001; private static final intSCREEN_BRIGHT_BIT = 0x00000002; private static final intBUTTON_BRIGHT_BIT = 0x00000004; private static final intKEYBOARD_BRIGHT_BIT = 0x00000008; private static final intBATTERY_LOW_BIT = 0x00000010;
//SCREEN_OFF == everything off
private static final intSCREEN_OFF = 0x00000000;
//SCREEN_DIM == screen on, screen backlight dim
private static final intSCREEN_DIM = SCREEN_ON_BIT;
//SCREEN_BRIGHT == screen on, screen backlight bright
private static final intSCREEN_BRIGHT = SCREEN_ON_BIT
|SCREEN_BRIGHT_BIT;
//SCREEN_BUTTON_BRIGHT == screen on, screen and button backlights bright
private static final intSCREEN_BUTTON_BRIGHT = SCREEN_BRIGHT
|BUTTON_BRIGHT_BIT;
//SCREEN_BUTTON_BRIGHT == screen on, screen, button and keyboard backlightsbright
private static final intALL_BRIGHT = SCREEN_BUTTON_BRIGHT| KEYBOARD_BRIGHT_BIT;
4、提供的相关服务
提供的这些服务之间并不是独立的,而是相互交织在一起,共同完成电源管理的:1)、光感传感器
LIGHT_SENSOR
定义了光感传感器变化明暗变化的延时:
相关的参数有:
相关的方法:
2)、接近/距离传感器PROXIMITY_SENSOR
定义了接近传感器变化明暗变化的延时:
定义了接近传感器触发的最大距离:
在powermanager类中定义的与接近传感器相关的参数有:
相关参数:
相关方法:
Listener的实例、传感器类型的列表、接收频度;
mSensorManager.registerListener(mProximityList ener, mProximitySensor,
SensorManager.SENSOR_DELAY_NORMAL);
//当挂断电话时会调用该方法
private void disableProximityLockLocked()
......
//缷载传感器
mSensorManager.unregisterListener(mProximityListener) ;
private void proximityChangedLocked(boolean active){
......
//小于触发距离触发接近传感器之后的动作_灭屏。
如打电话时屏幕LCD灯的熄灭
if (active) {
goToSleepLocked(SystemClock.uptimeMillis(),
WindowManagerPolicy.OFF_BECAUSE_OF_PROX_SENSOR );
mProximitySensorActive = true;
......
SensorEventListener mProximityListener = new SensorEventListener()
3)、提供明亮度动态变化:
animation for brightness changes:
定义了可以明暗动态变化设备的宏,可以看出,不外乎这三个部分:屏幕灯、触摸按键灯和键盘灯
明暗变化的级别,分普通级别的较慢级别:
相关类:
101010private class LightAnimator implements Runnable
相关方法:
4)、允许用户用软件自动调节亮度
mUseSoftwareAutoBrightness
在initThread中初始化了这个变量
mUseSoftwareAutoBrightness
=resources.getBoolean(com.android.internal.R.bool.config_automatic_br ightness_available);
当这个变量获取到非零值
自动调节亮度的功能与LIGHT_SENSOR相关,当外界光线强时,屏幕会相应提升
亮度。
Android电源管理系统调研报告-(4)
2011-02-18 11:20
转载自carvencao
最终编辑ch_ff
二、Brightness的调节
现在通过一个具体的电源管理实例来了解从andriod上层到内核驱动层的整个调用流程。
如果你使用过android操作系统,无论是模拟器还是开发板亦或手机,对里面setting这个服务一定很熟悉吧。
其中有一项是用于调节显示屏亮度的:
setting/sound & display settings/brightness。
这个功能是怎么实现的呢。
通过分析,我们可以清晰看到整个调用的流程,上层是如何一步一步到达驱动层,把LCD屏幕亮度改变的。
1、android层的调用流程。
1)、BrightnessPreference.java
/packages/apps/Settings/src/com/android/settings/
当系统检测到调节亮度的调节栏改变时,会重新设置屏幕的亮度:
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进行了修正,从而确保应用程序不能将屏幕全部熄灭。
setBacklightBrightness这个方法会调节lcd backlight、keyboard light、和buttons light这三个设备的亮度,但都是通过调用
setLightBrightness_UNCHECKED实现的。
让我们先看一下第一个设备亮度的调节,注意参数LIGHT_ID_BACKLIGHT,它将决定选择操作哪一个设备。
3)、HardwareService.java
/frameworks/base/services/java/com/android/server/
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;
再来看这个函数指针指向的函数。
在Lights.c这个文件中的open_lights这个函数中,对传入参数的不同对set_light进行了赋值:
在这里,name传入的是LIGHT_ID_BACKLIGHT
set_light_backlight的函数原型如下:
再对比一下函数指针的赋值:
devices->lights[light]->set_light(devices->lights[light],&state); 可见,参数devices->lights[light],&state分别传入了dev和state。
让我们来看一下set_light_backlight的内容:
5)、Lights.c
/hardware/msm7k/liblights/
这个文件已经不陌生了吧,上文刚刚提到呵。
(1)、在这里对brightness进行了特殊的赋值:
之所以这样赋值在struct light_state_t的注释中有解释。
(2)、write_int的参数LCD_FILE
这个路径是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)、
打开设备结点后,最终通过write将brigthness写入到了设备结点。
Android电源管理系统调研报告-(5)
2011-01-04 14:20
2、kernel层sysfs接口函数的建立
这里所分析的代码基于三星公司的手机产品i5700。
涉及到电源管理的设备,该设备驱动应该增添相应的代码以支持相应的电源管理,如suspend、resume。
同时应该有相应的代码向sysfs提供相应的entry供用户使用。
由于该流程分析的是Lcd亮度的调节,所以涉及到Lcd驱动向sysfs提供的entry。
suspend、resume
等功能在android层调用
int release_wake_lock(const char* id);
int acquire_wake_lock(int lock, const char* id);
时起作用。
在i5700中,Lcd驱动包括两个文件,一个是与特定硬件相关的s3cfb_s6d05a.c,该文件实现了与硬件相关的操作,包括GPIO口的初始化和电源管理的相关功能函数等;一个是三星通用的s3cfb.c,作为桥梁作用联系着向sysfs提供的entry 和s3cfb_s6d05a.c中相关功能函数。
1)、/drivers/video/samsung/s3cfb.c
该文件向sys提供了三个entry,让我们来看看这三个entry的建立流程。
(1)、entry对应的读、写功能函数:
三个entry分别是lcd_power、backlight_power、backlight_level,这几个entry 在android系统起来后,在终端通过adb shell,敲入如下命令就可以看到:
# ls /sys/devices/platform/s3c-lcd
其中*show*表示读操作的功能函数,*store*表示写操作的功能函数。
在后面会对其中一个函数有进行详细的分析。
(2)、entry属性的建立:
在内核中,sysfs 属性一般是由 __ATTR 系列的宏来声明的,如对设备的使
用 DEVICE_ATTR ,对总线使用 BUS_ATTR ,对驱动使用DRIVER_ATTR ,对类别(class)使用 CLASS_ATTR, 这四个高级的宏来自于<include/linux/device.h>。
在s3cfb.c里,使用的是DEVICE_ATTR来建立entry在sysfs中的属性。
static DEVICE_ATTR(lcd_power, 0666,
s3cfb_sysfs_show_lcd_power,
s3cfb_sysfs_store_lcd_power);
static DEVICE_ATTR(backlight_power, 0666,
s3cfb_sysfs_show_backlight_power,
s3cfb_sysfs_store_backlight_power);
static DEVICE_ATTR(backlight_level, 0644,
s3cfb_sysfs_show_backlight_level,
s3cfb_sysfs_store_backlight_level);
DEVICE_ATTR 宏声明有四个参数,分别是名称、权限位、读函数、写函数。
其中读函数和写函数是读写功能函数的函数名。
(3)、entry的创建
entry的创建是通过函数device_create_file完成,在static int
__inits3cfb_probe(struct platform_device *pdev)函数内实现的。
通过以上简单的三个步骤,就可以在shell终端查看到这三个entry了。
当我们将数据echo到这几个entry中时,在上层实际上完成了一次write操作,对应到kernel,分别调用了lcd驱动中的三个*store*。
同理,当我们cat一个entry 时则会调用*show*。
通过在*show*和*store*中插桩就可以看到效果。
到这里,只是简单的建立了android层到kernel的桥梁,真正实现对硬件操作的,还是在*show*和*store*中完成的。
(4)、backlight_level entry写函数分析
这里调用了s3cfb_set_backlight_level(value);
在这个函数里,s3c_fimd.set_brightness是一个函数指针,如果不为空,刚调用(s3c_fimd.set_brightness)(to);。
在这里还看不到到底调用了哪个函数,在s3cfb_s6d05a.c中有能该函数指针的初始化以及最终功能函数的实现。
2)、/drivers/video/samsung/s3cfb_s6d05a.c
上文提到的函数接口的初始化是在static voids3cfb_set_fimd_info(void)中完成的:
s3c_fimd.set_lcd_power = lcd_power_ctrl;
s3c_fimd.set_backlight_power = backlight_power_ctrl;
s3c_fimd.set_brightness = backlight_level_ctrl;
因此(s3c_fimd.set_brightness)(to);实际上是调用了
backlight_level_ctrl(to);
void backlight_level_ctrl(s32 value)
{
if ((value < BACKLIGHT_LEVEL_MIN) || /* Invalid Value */
(value > BACKLIGHT_LEVEL_MAX) ||
(value == backlight_level)) /* Same Value */
return;
if (backlight_power)
backlight_ctrl(value);
backlight_level = value;
}
这个函数实现的是LCD背光的调节,可以参考程杰SX的博客:。