源出处:http://www.61ic.com/Mobile/Android/201102/29414.html
Android 的电源管理还是比较简单的 , 主要就是通过锁和定时器来切换系统的状态 , 使系统的功耗降至最低 , 整个系统的电源管理架构图如下 : ( 注该图来自 Steve Guo)
static struct platform_driver mxcbl_driver = {
.probe = mxcbl_probe,
.remove = mxcbl_remove,
.suspend = mxcbl_suspend,
.resume = mxcbl_resume,
.driver = {
.name = "mxc_mc13892_bl",
},
};
取一个例子
加入 suspend 和 resume
mxc_board_init-->mxc_init_bl()-->platform_device_register()-->platform_device_add()-->device_add()-->device_pm_add()--> ,最终加入到了 dpm_list 的链表中,在其中的 dpm_suspend 和 dpm_suspend 中通过遍历这个链表来进行查看哪个 device 中包含 suspend 和 resume 项。
系统唤醒和休眠
Kernel 层 [ 针对 Android Linux2.6.28 内核 ]:
其主要代码在下列位置 :
Drivers/base /main.c
kernel/power /main.c
kernel/power/wakelock.c
kernel/power/earlysuspend.c
其对 Kernel 提供的接口函数有
EXPORT_SYMBOL(wake_lock_init); // 初始化 Suspend lock, 在使用前必须做初始化
EXPORT_SYMBOL(wake_lock); // 申请 lock, 必须调用相应的 unlock 来释放它
static DEFINE_TIMER(expire_timer, expire_wake_locks, 0, 0);// 定时时间到,加入到 suspend 队列中;
EXPORT_SYMBOL(wake_unlock); // 释放 lock
EXPORT_SYMBOL_GPL(device_power_up);// 打开特殊的设备
EXPORT_SYMBOL_GPL(device_power_down);// 关闭特殊设备
EXPORT_SYMBOL_GPL(device_resume);// 重新存储设备的状态;
EXPORT_SYMBOL_GPL(device_suspend);: 保存系统状态,并结束掉系统中的设备;
EXPORT_SYMBOL(register_early_suspend); // 注册 early suspend 的驱动
EXPORT_SYMBOL(unregister_early_suspend); // 取消已经注册的 early suspend 的驱动
函数的流程如下所示:
应用程序通过对 state_store 的写入操作可以使系统进行休眠的状态。 pm_states 包括 PM_SUSPEND_ON , PM_SUSPEND_STANDBY , PM_SUSPEND_M 满足个状态。当状态位 PM_SUSPEND_ON 的状态的时候,调用 request_suspend_state() ;当满足休眠的状态的时候,调用 queue_work(suspend_work_queue,&early_suspend_work), 调用了 early_suspend ,然后在其中通过 wake_unlock() 启动了 expire_timer 定时器,当定时时间到了,则执行 expire_wake_locks ,将 suspend_work 加入到队列中,分析到这里就可以知道了 early_suspend_work 和 suspend_work 这两个队列的先后顺序了, suspend 调用了 pm_suspend ,通过判断当前的状态,选择 enter_state() ,在 enter_state 中,经过了 suspend_prepare , suspend_test 和 suspend_device_and_enter() ,在 suspend_device_and_enter 中调用了 device_suspend 来保存状态和结束系统的设备,到了 dpm_suspend 中结束所有的 device 。到了这里,我们就又可以看见在初始化的时候所看到的队列 dpm_list 。
Android 的电源管理主要是通过 Wake lock 来实现的 , 在最底层主要是通过如下队列来实现其管理 :
LIST_HEAD(dpm_list);
系统正常开机后进入到 AWAKE 状态 , Backlight 会从最亮慢慢调节到用户设定的亮度 , 系统 screen off timer(settings->sound & display-> Display settings -> Screen timeout) 开始计时 , 在计时时间到之前 , 如果有任何的 activity 事件发生 , 如 Touch click, keyboard pressed 等事件 , 则将 Reset screen off timer, 系统保持在 AWAKE 状态 . 如果有应用程序在这段时间内申请了 Full wake lock, 那么系统也将保持在 AWAKE 状态 , 除非用户按下 power key. 在 AWAKE 状态下如果电池电量低或者是用 AC 供电 screen off timer 时间到并且选中 Keep screen on while pluged in 选项 ,backlight 会被强制调节到 DIM 的状态 .
如果 Screen off timer 时间到并且没有 Full wake lock 或者用户按了 power key, 那么系统状态将被切换到 NOTIFICATION, 并且调用所有已经注册的 g_early_suspend_handlers 函数 , 通常会把 LCD 和 Backlight 驱动注册成 early suspend 类型 , 如有需要也可以把别的驱动注册成 early suspend, 这样就会在第一阶段被关闭 . 接下来系统会判断是否有 partial wake lock acquired, 如果有则等待其释放 , 在等待的过程中如果有 user activity 事件发生 , 系统则马上回到 AWAKE 状态 ;如果没有 partial wake lock acquired, 则系统会马上调用函数 pm_suspend 关闭其它相关的驱动 , 让 CPU 进入休眠状态 .
系统在 Sleep 状态时如果检测到任何一个 Wakeup source, 则 CPU 会从 Sleep 状态被唤醒 , 并且调用相关的驱动的 resume 函数 , 接下来马上调用前期注册的 early suspend 驱动的 resume 函数 , 最后系统状态回到 AWAKE 状态 . 这里有个问题就是所有注册过 early suspend 的函数在进 Suspend 的第一阶段被调用可以理解 , 但是在 resume 的时候 , Linux 会先调用所有驱动的 resume 函数 , 而此时再调用前期注册的 early suspend 驱动的 resume 函数有什么意义呢 ?个人觉得 android 的这个 early suspend 和 late resume 函数应该结合 Linux 下面的 suspend 和 resume 一起使用 , 而不是单独的使用一个队列来进行管理 .