电源管理内核.docx
- 文档编号:5356947
- 上传时间:2022-12-15
- 格式:DOCX
- 页数:15
- 大小:261.58KB
电源管理内核.docx
《电源管理内核.docx》由会员分享,可在线阅读,更多相关《电源管理内核.docx(15页珍藏版)》请在冰豆网上搜索。
电源管理内核
Android电源管理内核模块总体框架2
初始化与接口模块4
earlysuspend/lateresume模块8
Earlysuspend/lateresume概述8
Earlysuspend/lateresume流程9
流程1:
创建earlysuspend的核心工作队列线程suspend_work_queue10
流程2:
系统启动完成后,相关的驱动程序通过register_early_suspend()函数注册了earlysuspend/lateresume特性10
流程3:
用户空间,通过调用set_screen_state函数来触发suspend的流程13
流程4:
先valid_state()一下,这给了平台相关的代码一个机会确认该平台是否支持所请求的电源状态13
流程5:
调用request_suspend_state()函数13
流程6:
early_suspend()完成最主要工作13
Wakelock模块14
Suspend及平台相关驱动模块14
参考资料17
Android电源管理内核模块总体框架
Android电源管理内核模块,主要是由以下几个基本模块组成,详细分析如下:
电源管理内核模块总体组成
电源管理内核模块总体组成图
电源管理内核模块从功能角度出发,各模块关系示意图如下:
电源管理内核模块各模块关系示意图1
简单说明:
内核空间提供3个sys接口,即加锁,解锁,休眠唤醒,当所有的锁解开的时候,会执行标准linux的suspend.
ealry_suspend:
设备:
触摸屏,按键,gpu,电子罗盘,摄像头,led,wifi等
linuxsuspend设备:
usbcpu总线等。
电源管理内核模块各模块关系示意图2
初始化与接口模块
主要涉及文件:
/kernel/power/main.c;
/kernel/power/userwakelock.c
在kernel/power/main.c中,定义了一组sysfs的属性文件,其中一个定义是:
power_attr(state);//line215
把这个宏展开后:
1.kernel/power/main.hline65----73
2.staticstructkobj_attributestate_attr={\
3.
4..attr={\
5.
6..name="state",\
7.
8..mode=0644,\
9.
10.},\
11.
12..show=state_show,\
13..store=state_store,\
14.
15.}
源码位置:
kernel/power/main.c
在此文件中,定义了一组sysfs的属性文件,并且main.c的入口:
1.staticint__initpm_init(void)
2.
3.{
4.
5.......
6.
7.power_kobj=kobject_create_and_add("power",NULL);
8.
9.......
10.
11.}
12.
13.core_initcall(pm_init);
14.
函数执行后,会在生成/sys/power目录,该目录下会建立一系列属性文件,其中一个就是/sys/power/state文件.
从core_initcall(pm_init))可以知道:
函数在初始化时被执行
关于此函数可见[1],
同样,我们从main.c中可以看到,/sys/power目录下应该还有的属性文件有:
如果内核:
#ifdefCONFIG_PM_SLEEP
power_attr(pm_async);//line70
则有:
/sys/power/pm_async
功能:
cat/sys/power/pm_async用于判断当前设备的suspend、resume操作是否是同步操作
echo/sys/power/pm_async用于控制是否异步的执行设备的suspend、resume操作
#ifdefCONFIG_USER_WAKELOCK
power_attr(wake_lock);
power_attr(wake_unlock);
#endif
则有:
/sys/power/wake_lock,sys/power/unwake_lock文件
注意其对应的SHOW与STORE功能实现函数在:
//kernel/power/userwakelock.c
功能:
cat/sys/power/wake_lock查看系统的wakelock情况
echo/sys/power/wake_lock申请一个wakelock
unwake_lock类似。
#ifdefCONFIG_PM_SLEEP
#ifdefCONFIG_PM_DEBUG
power_attr(pm_test);//line132
则有:
/sys/power/pm_test
功能:
none>>core>>processors>>platform>>devices>>freezer, 控制范围示意;
catpm_test,在终端上打印出上面数组中的字符串,当前的模式用[]表示出来。
echodevices>pm_test的时候会最终调用到函数pm_test_store()中去,该函数中设置全局变量pm_test_level的值,可以是0-5,分别代表上none~freezer。
该全局变量会在后面的suspend和resume中被引用到。
#ifdefCONFIG_PM_SLEEP
power_attr(wakeup_count);
则有:
/sys/power/wakeup_count
注意其对应的SHOW与STORE功能实现函数在:
/drivers/base/power/wakeup.c
功能:
cat/sys/power/wakeup_count读取当前已经注册wakeup事件数目
echo/sys/power/wakeup_count写入时,只有写入值和当前已经注册wakeup事件数目相同时,才会有作用,如果成功了,会使内核进入一段连续睡眠如果在写入后没有任何的wakeup事件到来。
#ifdefCONFIG_PM_TRACE
power_attr(pm_trace);
power_attr(pm_trace_dev_match);
则有:
/sys/power/pm_trace,
/sys/power/pm_trace_dev_match
功能:
cat/sys/power/pm_trace下面就会显示 1 或者 0
echo/sys/power/pm_trace
The/sys/power/pm_trace
本文件可以在保存重启过程中RTC中的最后一个PM事件点,这样可以用来调试时使用。
/sys/power/pm_trace则是如果使用了pm_trace,此文件中可以包含和最后的PM事件点有关的设备的名称。
这些文件接口使用例子:
1)cat/sys/power/state-----查看系统状态,
echomem>/sys/power/state----将系统设置为进入休眠
2)echo"name">/sys/power/wake_lock-----申请一个锁
cat/sys/power/wake_lock-----查看系统的wakelock情况
wake_unlock同样。
总结:
cat会调用相应的xxx_show();echo会调用相应的xxx_store()来实现一定的获取状态或设置等功能。
earlysuspend/lateresume模块
Earlysuspend/lateresume概述
android引入了新的机制来管理电源,earlysuspend、lateresume和wakelock。
EarlySuspend和LateResume是Android在标准Linux的基础上增加的一项特性。
当用户空间的向内核请求进入suspend时,这时候会先进入earlysuspend状态,驱动程序可以注册earlysuspend的回调函数,当进入该状态时,内核会逐一地调用这些回调函数。
例如显示屏的驱动程序通常会注册earlysuspend,在他的回调函数中,驱动程序会把屏幕和背光都关闭。
在这种状态下,所有的后台进程都还在活动中,该播放歌曲的播放歌曲,该下载数据的依然在下载,只是显示屏不良而已。
进入earlysuspend状态以后,一旦所有的电源锁(wakelock)被释放,系统马上会进入真正的suspend流程,直到最后系统停止工作,等待外部事件的唤醒。
Earlysuspend用于在关闭显示的时候使一些与显示有关的设备(如LCD背光、重力感受器、触摸屏等)都关掉,但是系统可能仍处于运行状态并处理着任务,在嵌入式设备中,背光会消耗大量的电量,所以android引入了earlysuspend。
进入earlysuspend状态以后,一旦所有的电源锁(wakelock)被释放,系统马上会进入真正的suspend流程,直到最后系统停止工作,等待外部事件的唤醒[2]。
加入后earlysuspend电源状态整体状态转换图:
加入后earlysuspend电源状态整体状态转换图
用户空间的接口创建,见初始化与接口模块部分
存在/sys/power/state的SYS接口
Earlysuspend/lateresume流程
Earlysuspend/lateresume调用流程图
Earlysuspend调用流程详细说明
流程1:
创建earlysuspend的核心工作队列线程suspend_work_queue
源码位置:
(平台不同源码实际位置不定,目录及文件固定
kernel/power/wakelock.c
staticint__initwakelocks_init(void)
{
..........
suspend_work_queue=create_singlethread_workqueue("suspend");
.............
}
流程2:
系统启动完成后,相关的驱动程序通过register_early_suspend()函数注册了earlysuspend/lateresume特性
源码位置:
(平台不同源码实际位置不定,目录及文件固定)
kernel/power/earlysuspend.c
void register_early_suspend(structearly_suspend*handler)
希望执行earlysuspend的设备,他的设备驱动程序需要向电源管理系统注册earlysuspend/lateresume,当电源管理系统启动suspend流程时,回调函数suspend会被调用,相反,resume的最后阶段,回调函数resume会被调用。
所有注册到系统中的early_suspend结构都会按level值按顺序加入到全局链表early_suspend_handlers中。
suspend时,level的数值越小,回调函数的被调用的时间越早,resume时则反过来。
例:
在PANDA平台上,我们通过命令查看可以看到哪些设备在哪里注册了earlysuspend,其中有明显的网上,触摸屏的身影;
1.cd /omap
2.#find -name "*.*"| xargsgrep -rn "register_early_suspend"
3.
4../drivers/staging/brcm80211/brcmfmac/dhd_linux.c:
2023:
register_early_suspend(&dhd->early_suspend);
5../drivers/staging/brcm80211/brcmfmac/dhd_linux.c:
2263:
unregister_early_suspend(&dhd->early_suspend);
6../drivers/staging/msm/mddi.c:
231:
register_early_suspend(&mfd->mddi_early_suspend);
7../drivers/staging/msm/mdp.c:
1087:
register_early_suspend(&early_suspend);
8../drivers/staging/msm/msm_fb.c:
986:
register_early_suspend(&mfd->early_suspend);
9../drivers/staging/msm/mddi_ext.c:
222:
register_early_suspend(&mfd->mddi_ext_early_suspend);
10../drivers/leds/ledtrig-sleep.c:
67:
register_early_suspend(&ledtrig_sleep_early_suspend_handler);
11../drivers/leds/ledtrig-sleep.c:
73:
unregister_early_suspend(&ledtrig_sleep_early_suspend_handler);
12../drivers/video/omap2/dsscomp/gralloc.c:
559:
register_early_suspend(&early_suspend_info);
13../drivers/video/omap2/dsscomp/gralloc.c:
598:
unregister_early_suspend(&early_suspend_info);
14../drivers/misc/akm8975.c:
664:
register_early_suspend(&akm->early_suspend);
15../drivers/input/touchscreen/synaptics_i2c_rmi.c:
539:
register_early_suspend(&ts->early_suspend);
16../drivers/input/touchscreen/synaptics_i2c_rmi.c:
561:
unregister_early_suspend(&ts->early_suspend);
17../drivers/input/misc/gpio_event.c:
177:
register_early_suspend(&ip->early_suspend);
18../drivers/input/misc/gpio_event.c:
203:
unregister_early_suspend(&ip->early_suspend);
19../drivers/input/misc/gpio_event.c:
227:
unregister_early_suspend(&ip->early_suspend);
20../drivers/gpu/pvr/display/omap_sgx_displayclass.c:
1594:
register_early_suspend(&driver_early_suspend);
21../drivers/gpu/pvr/display/omap_sgx_displayclass.c:
1611:
unregister_early_suspend(&driver_early_suspend);
22../drivers/gpu/pvr/omaplfb/omaplfb_linux.c:
841:
register_early_suspend(&psDevInfo->sEarlySuspend);
23../drivers/gpu/pvr/omaplfb/omaplfb_linux.c:
852:
unregister_early_suspend(&psDevInfo->sEarlySuspend);
24../drivers/net/wireless/bcmdhd/dhd_linux.c:
2674:
register_early_suspend(&dhd->early_suspend);
25../drivers/net/wireless/bcmdhd/dhd_linux.c:
3472:
unregister_early_suspend(&dhd->early_suspend);
26../drivers/net/wireless/bcm4329/dhd_linux.c:
2206:
register_early_suspend(&dhd->early_suspend);
27../drivers/net/wireless/bcm4329/dhd_linux.c:
2559:
流程3:
用户空间,通过调用set_screen_state函数来触发suspend的流程
可参考:
Android能耗管理机制及优化--电源键事件处理
流程4:
先valid_state()一下,这给了平台相关的代码一个机会确认该平台是否支持所请求的电源状态
源码位置:
/kernel/power/suspend.c
boolvalid_state(suspend_state_tstate)
{
/*
*Allstatesneedlowlevelsupportandneedtobevalidtothelowlevel
*implementation,novalidcallbackimpliesthatnonearevalid.
*/
returnsuspend_ops&&suspend_ops->valid&&suspend_ops->valid(state);
}
流程5:
调用request_suspend_state()函数
request_suspend_state()只是简单地向suspend_work_queue中加入early_suspend_work或者是late_resume_work并调度他们执行。
源码位置:
kernel/power/earlysuspend.c
voidrequest_suspend_state(suspend_state_tnew_state)
流程6:
early_suspend()完成最主要工作
在early_suspend()函数中,首先要判断当前请求的状态是否还是suspend,若不是,则退出了;若是,early_suspend()遍历early_suspend_handlers链表,从中取出各个驱动程序注册的early_suspend结构,然后调用它的suspend回调函数。
最后,释放main_wake_lock锁,至此整个earlysuspend的流程完成。
这时整个系统只是处于所谓的idle状态,cpu还在工作,后台进程也在工作中,某些设备可以选择进入某种功耗较低的状态,比如LCD可以降低亮度或灭掉。
源码位置:
kernel/power/earlysuspend.c
staticvoidearly_suspend(structwork_struct*work)
Wakelock模块
Wakelock-是一种锁的机制,只要有task拿着这个锁,系统就无法进入休眠,可以被用户态进程和内核线程获得。
这个锁可以是有超时的或者是没有超时的,超时的锁会在时间过去以后自动解锁。
如果没有锁了或者超时了,内核就会启动标准linux的那套休眠机制机制来进入休眠。
详细内核实现可参见:
Wakelock相关机制之wakelock内核实现
Suspend及平台相关驱动模块
在wake_unlock()中(可参见上面wakelock模块内容),删除链表中wake_lock节点,判断当前是否存在wake_lock,若wake_lock的数目为0,则调用工作队列suspend_work,进入suspend状态。
static DECLARE_WORK(suspend_work, suspend);
其详细如下:
suspend总体框架图
其整体流程如下图所示:
suspend准备及结束工作示意图
SUSPEND设备和进入的详细流程如下图:
SUSPEND设备和进入的详细流程图
而上图中的Suspend进入(完全suspend)详细流程如下:
Suspend进入(完全suspend)详细流程图
从上面各图我们可以看出,其实际步骤总结起来就是:
:
首先是enter_suspend函数,这个函数处理进入和退出Suspend状态时的一些常规处理,其过程是:
第一,同步文件系统以保证所有数据都写到了存储设备上而不会因为suspend而丢失数据
sys_sync();
第二,调用suspend_prepare准备进入suspend状态,完成后,系统suspend状态变为PM_SUSPEND_PREPARE。
这个函数主要完成几件事情:
1)切换Console为SUSPEND_CONSOLE。
2)通知pm_chain系统进入PM_SUSPEND_PREPARE状态(通过kernelnotifier机制)。
3)关闭usermodehelper函数以阻止新的helper函数运行。
4)冻结所有可冻结的任务(包括用户空间程序和部分内核空间线程)
pm_prepare_console();
pm_notifier_call_chain(PM_SUSPEND_PREPARE);
usermodehelper_disable();
suspend_freeze_processes();
第三,调用suspend_devices_and_enter(state);进入指定的suspend状态。
第四,系统已经从suspend里唤醒,调用suspend_finish()完成suspend操作。
这个函数的功能与suspend_prepare相反的,目的是恢复suspend_prepare为进入suspend而进行的一些处理,就不详细描述了。
suspend_thaw_processes();
usermodehelper_enable();
pm_notifier_call_chain(PM_POST_SUSPEND);
pm_restore_console();
参考资料
[1]LINUX内核中的xx_initcall初始化标号
[2] 基于Android的Linux内核的电源管理概述
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 电源 管理 内核
![提示](https://static.bdocx.com/images/bang_tan.gif)