android 2.3 电源管理

1. 介绍
  这是一篇关于Android电源管理的文章, 适合应用程序开发人员和驱动开发人员和FrameWork开发人员阅读。

2. 前言

  Android系统出于节电的需要, 一般应用在用户一段时间无操作的情况下屏幕变暗, 然后进后休眠状态, 此时cpu处于挂起状态, 屏幕处于关闭状态。 用户只能在”设置->声音和显示”中设置所有应用默认的屏幕亮度和系统无操作多久进入睡眠的时间。  当然这种管理模式并不适合于所有的应用, 比如当看电影的时候总不希望系统隔一段时间就进入睡眠吧。所以Android系统为这种有特殊需求的应用提供了可以不遵守规矩的Api, 通过使用这种Api可以打破默认情况下的电源管理模式。

3.  应用程序开发相关  3.1.  Api的使用

     只需要熟悉android.os.PowerManager和android.os.PowerManager.WakeLock这两个类的Api就足够了, 当需要用到这些Api时, 需要在Manifest.xml添加如下权限:     <uses-permission android:name="android.permission.WAKE_LOCK" />     <uses-permission android:name="android.permission.DEVICE_POWER" />     很重要的一个概念就是WakeLock, 系统中定义了六种WakeLock, 常用的有4个:

  CPU Screen Keyboard Light
PARTIAL_WAKE_LOCK on off off
SCREEN_DIM_WAKE_LOCK on dim off
SCREEN_BRIGHT_WAKE_LOCK on on off
FULL_WAKE_LOCK on on on
    对WakeLock有两种操作:获取和释放。获取后当系统需要睡眠时就会进入所获取的WakeLock代表的状态。 实例代码如下:

PowerManager mPm;
WakeLock mWakeLock;

mWakeLock = mPm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "WhatEver");
mWakeLock.acquire();
//cpu on, screen dim, keyboard light off
//...
		
mWakeLock.release();
    如上面代码所示, 如果系统在获取锁后一段时间无操作就会进入SCREEN_DIM_WAKE_LOCK锁所对应的状态。

  另外还有两个比较特殊的锁:

l          ACQUIRE_CAUSES_WAKEUP:一旦有请求锁时强制打开Screen和keyboard light 
l          ON_AFTER_RELEASE:当lock被释放后,通过reset user activity timer使屏幕多亮一会儿

关于api更加详细的内容请参考官方文档。

  3.24.  注意事项
  l  使用WakeLock会增加系统功耗,所以原则上是只有必要的时候才用
  l  所有的锁必须成对的使用, 如申请了PARTIAL_WAKE_LOCK, 而没有及时释放,那系统就永远进不了Sleep模式,这会严重影响手持设备的待机时间。

4.   驱动程序开发相关
  值得注意的是,写Android的linux驱动时也要记得系统随时都可能suspend。有些驱动需要关心early suspend和later resume, 比如early suspend时framebuffer驱动的dma应该可以休息了。有些驱动则需要在某个过程中系统不能睡眠,比如usb gadget driver向pc传文件的过程中系统就不能睡眠,睡了就传不完了, 这就需要在这个过程前后获得而后释放锁。 有些驱动向某个设备发送命令过程中如果发生suspend, 等到唤醒的时候再接着发可能外设早已timeout,这时也需要锁。

驱动相关的wakelock接口如下, 在inclulde/linux/wakelock.h中定义:

void wake_lock_init(struct wake_lock *lock, int type, const char *name);
void wake_lock_destroy(struct wake_lock *lock);
void wake_lock(struct wake_lock *lock);
void wake_lock_timeout(struct wake_lock *lock, long timeout);
void wake_unlock(struct wake_lock *lock);
int  wake_lock_active(struct wake_lock *lock);
long has_wake_lock(int type);

示例代码如下:

#include <linux/earlysuspend.h>
#include <linux/module.h>

struct wake_lock my_wake_lock;

static int __init my_init(void)
{
	wake_lock_init(&my_wake_lock, WAKE_LOCK_SUSPEND, "mylock");
	wake_lock(&my_wake_lock);
	//we do not want to suspend here!
	wake_unlock(&my_wake_lock);
	return 0;
}

static void  __exit my_exit(void)
{
	wake_lock_destroy(&my_wake_lock)
}

early suspend和later resume是Android对linux内核的扩展机制, 当系统持有wakelock时,如果一段时间无用户操作, 就会进入early suspend状态, 所有驱动注册的early suspend回调函数会被调用。当用户开始操作设备时,所有驱动注册的later resume函数会被调用。 当系统中无wakelock时, 驱动注册的early suspend会先于suspend函数调用, 唤醒时later resume会再resume函数后调用。 early suspend机制给系统提供了一种折中的省电模式,让系统在不能睡眠的情况下各个驱动模块也能有机会调整工作模式。 驱动注册early suspend和later resume回调的代码如下: 

module_init(my_init);
module_exit(my_exit);

#include <linux/earlysuspend.h>
#include <linux/module.h>

static my_early_suspend(struct early_suspend *h)
{

}

static void my_late_resume(struct early_suspend *h)
{

}

static struct early_suspend my_early_suspend_desc = {
	.suspend = my_early_suspend,
	.resume = my_late_resume,
};

static int __init my_init(void)
{
	register_early_suspend(&my_early_suspend_desc);
	return 0;
}

static void  __exit my_exit(void)

{
	unregister_early_suspend(&my_ early_suspend_desc);
}

module_init(my_init);
module_exit(my_exit);

另外,请慎重在驱动的suspend和resume函数中和内核线程(workqueue或tasklet)中操作wakelock。
5. FrameWork相关
  5.1. Linux内核的电源管理
    Linux内核的电源管理有两个阶段suspend和resume, 分别在设备睡眠和唤醒的时候进行,需要关心电源管理的驱动程序可以注册suspend和resume函数在睡眠和唤醒时执行。Linux内核提供给应用层的接口是/sys/power/state, 有如下命令:
l echo mem>/sys/power/state:睡眠,状态保存进ram
l echo on>/sys/power/state:唤醒
l echo standby>/sys/power/state
l echo disk>/sys/power/state:睡眠, 状态保存进disk
还有一些其他命令请查阅网上资料, 有的命令不一定支持。
5.2. Android对linux内核的修改
  Android linux内核的电源管理系统是基于Linux内核的电源管理系统的扩展,添加了锁的概念, 多出了两个阶段early suspend和later resume,在有锁的情况下进入的睡眠是partial lock状态, 只会执行注册的early suspend函数, 唤醒时只会执行注册的later resume函数。只有在无锁时进入睡眠才会真正suspend,注册的early suspend函数会在suspend函数前执行,注册的later resume函数会在resume函数后执行 。 关心电源管理的android驱动程序可以注册early suspend和later resume和suspend和resume函数在相应阶段执行。 Android linux内核提供给应用层得接口如下:
l /sys/power/state:只支持mem(睡眠)和on(唤醒)两个参数 
l /sys/power/power_lock: 写入锁的名字即获得锁
l /sys/power/power_unlock:写入锁的名字即解锁



你可能感兴趣的:(android 2.3 电源管理)