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 |
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) }
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);