ohos设备休眠原理及流程
在ohos中电源节能模式有两种状态:熄屏状态和休眠状态 整个电源管理子系统 包括内核态以及用户态的相互协同工作内核对休眠的支持与相关流程linux内核中常用的休眠方式有freeze,standby,mem,disk freeze: 冻结I/O设备,将它们置于低功耗状态,使处理器进入空闲状态,唤醒最快,耗电比其它standby, mem, disk方式高 standby:除了冻结I/O
在ohos中电源节能模式有两种状态:熄屏状态和休眠状态
整个电源管理子系统 包括内核态以及用户态的相互协同工作
内核对休眠的支持与相关流程
linux内核中常用的休眠方式有freeze,standby,mem,disk
-
freeze: 冻结I/O设备,将它们置于低功耗状态,使处理器进入空闲状态,唤醒最快,耗电比其它standby, mem, disk方式高
-
standby:除了冻结I/O设备外,还会暂停系统,唤醒较快,耗电比其它 mem, disk方式高
-
mem: 将运行状态数据存到内存,并关闭外设,进入等待模式,唤醒较慢,耗电比disk方式高
-
disk: 将运行状态数据存到硬盘,然后关机,唤醒最慢
唤醒方式
主要使用电源按钮的gpio中断来唤醒设备
内核配置文件开启休眠
# Power management options
#
CONFIG_SUSPEND=y
CONFIG_SUSPEND_FREEZER=y
# CONFIG_SUSPEND_SKIP_SYNC is not set
CONFIG_HIBERNATION=y
CONFIG_PM_SLEEP=y
CONFIG_PM_SLEEP_SMP=y
CONFIG_PM_AUTOSLEEP=y
CONFIG_PM_WAKELOCKS=y
CONFIG_PM_WAKELOCKS_LIMIT=100
CONFIG_PM_WAKELOCKS_GC=y
CONFIG_PM=y
CONFIG_PM_DEBUG=y
CONFIG_PM_ADVANCED_DEBUG=y
# CONFIG_PM_TEST_SUSPEND is not set
CONFIG_PM_SLEEP_DEBUG=y
# CONFIG_DPM_WATCHDOG is not set
CONFIG_PM_CLK=y
CONFIG_PM_GENERIC_DOMAINS=y
CONFIG_WQ_POWER_EFFICIENT_DEFAULT=y
CONFIG_PM_GENERIC_DOMAINS_SLEEP=y
CONFIG_PM_GENERIC_DOMAINS_OF=y
CONFIG_CPU_PM=y
CONFIG_ENERGY_MODEL=y
CONFIG_ARCH_HIBERNATION_POSSIBLE=y
CONFIG_ARCH_SUSPEND_POSSIBLE=y
# end of Power management options
内核 休眠代码流程:
//切换休眠状态
kernel\power\main.c
static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,
const char *buf, size_t n)
{
suspend_state_t state;
int error;
error = pm_autosleep_lock();
if (error)
return error;
if (pm_autosleep_state() > PM_SUSPEND_ON) {
error = -EBUSY;
goto out;
}
state = decode_state(buf, n);//将“mem”转为对应的数字
if (state < PM_SUSPEND_MAX) {
if (state == PM_SUSPEND_MEM)
state = mem_sleep_current;
error = pm_suspend(state);//核心的kernel休眠流程
} else if (state == PM_SUSPEND_MAX) {
error = hibernate();
} else {
error = -EINVAL;
}
out:
pm_autosleep_unlock();
return error ? error : n;
}
Suspend 关键流程:
kernel\power\suspend.c
int pm_suspend(suspend_state_t state)
{
error = enter_state(state);
}
static int enter_state(suspend_state_t state)
{
trace_suspend_resume(TPS("suspend_enter"), state, true);
if (state == PM_SUSPEND_TO_IDLE) {
} else if (!valid_state(state)) {//检查平台是否支持电源管理,即全局suspend_ops有没有被赋值,并调用其suspend_ops->valid()
return -EINVAL;
}
error = suspend_prepare(state);//准备挂起
error = suspend_devices_and_enter(state);//让设备进入suspend状态
suspend_finish();
}
kernel\power\suspend.c
static int suspend_prepare(suspend_state_t state)
{
kernel\power\console.c
//切换挂起、恢复执行内核触发的VT开关,切换到SUSPEND_CONSOLE
pm_prepare_console();
//kernel/power/main.c
//通知驱动程序准备suspend
error = __pm_notifier_call_chain(PM_SUSPEND_PREPARE, -1, &nr_calls);
kernel\power\power.h
//冻结App和内核线程
error = suspend_freeze_processes();
}
kernel\power\suspend.c
////挂起设备并进入系统睡眠状态
int suspend_devices_and_enter(suspend_state_t state)
{
//如果平台相关的代码有begin函数就去调用它,suspend_ops->begin(state)
error = platform_suspend_begin(state);
kernel\printk\printk.c
//挂起console子系统,此时不能用printk()调试。
suspend_console();
suspend_test_start();
error = dpm_suspend_start(PMSG_SUSPEND);
suspend_test_finish("suspend devices");
do {
//关闭核心模块,如cpu等,并设置唤醒源,如果电源键按下则会进入唤醒流程。
error = suspend_enter(state, &wakeup);
} while (!error && !wakeup && platform_suspend_again(state));
Resume_devices:
suspend_test_start();
dpm_resume_end(PMSG_RESUME);
suspend_test_finish("resume devices");
resume_console();
}
kernel\power\suspend.c
static void suspend_finish(void)
{
//唤醒应用程序
suspend_thaw_processes();
//通知关注这个事件的App程序,对全局pm_chain_head->head中的每一个都调用其notifier_call()
pm_notifier_call_chain(PM_POST_SUSPEND);
//返回用户空间
pm_restore_console();
}
用户态电源管理子系统对休眠现
电源模式:正常模式,省电模式,性能模式,超级省电
可通过配置文件对详细策略进行修改
base/powermgr/power_manager/services/native/profile/power_mode_config.xml
<!--
Power Mode Definitions: // 电源模式定义
MODE_NORMAL = 600, // 正常模式
MODE_POWER_SAVE = 601, // 省电模式
MODE_PERFORMANCE = 602, // 性能优先
MODE_EXTREME_POWER_SAVE = 603, // 超级省电
-->
<!--
Action Definitions: // 行为定义
DisplayOffTime = 101, // 息屏时间控制
SystemAutoSleepTime = 102, // 系统自动睡眠时间控制
AutoAdjustBrightness = 103, // 亮度自动调整时间控制
AutoWindowRotation = 107, // 窗口自动旋转时间控制
SystemBrightness = 115, // 系统亮度调节
VibratorsState = 120, // 马达(震动)状态
-->
<switch_proxy version="1">
<proxy id="600">
<!-- value[单位:ms],-1表示不设置,如DisplayOffTime设为-1表示不息屏 -->
<switch id="101" value="30000" recover_flag="0"/>
<switch id="102" value="0" recover_flag="0"/>
<switch id="103" value="-1" recover_flag="0"/>
<switch id="107" value="1" recover_flag="0"/>
<switch id="115" value="102" recover_flag="0"/>
<switch id="120" value="1" recover_flag="0"/>
</proxy>
<proxy id="601">
<switch id="101" value="10000" recover_flag="0"/>
<switch id="102" value="5000" recover_flag="0"/>
<switch id="103" value="-1" recover_flag="0"/>
<switch id="107" value="-1" recover_flag="0"/>
<switch id="115" value="50" recover_flag="0"/>
<switch id="120" value="-1" recover_flag="0"/>
</proxy>
<proxy id="602">
<switch id="101" value="-1" recover_flag="0"/>
<switch id="102" value="-1" recover_flag="0"/>
<switch id="103" value="-1" recover_flag="0"/>
<switch id="107" value="1" recover_flag="0"/>
<switch id="115" value="255" recover_flag="0"/>
<switch id="120" value="1" recover_flag="0"/>
</proxy>
<proxy id="603">
<switch id="101" value="5000" recover_flag="0"/>
<switch id="102" value="1000" recover_flag="0"/>
<switch id="103" value="-1" recover_flag="0"/>
<switch id="107" value="-1" recover_flag="0"/>
<switch id="115" value="25" recover_flag="0"/>
<switch id="120" value="-1" recover_flag="0"/>
</proxy>
</switch_proxy>
如下图所示,显示电源管理服务与电源管理服务相互协同管理屏幕亮息屏及通过UHDF对设备电源的状态切换
如下图所示,电源管理服务器包括了电源状态机及运行锁管理器以及系统挂起控制器
在源码中drivers/peripheral/power/interfaces/hdi_service/power_interface_impl.cpp
函数 DoSuspend实现在休眠的关键动作,写入mem到/sys/power/state,让设备真正进入休眠状态,设备启动后读取电源管理配置,默认进入正常模式,以正常模式为例,讲解设备如何进入休眠状态.设备启动进入亮屏状态->30秒后进入息屏模式->0秒后进入休眠模式->电源键中断唤醒进入亮屏状态,通过power-shell setmode 600/601/602/603 可以修改电源模式
运行锁:亮灭屏锁,休眠锁
电源状态机:在九种状态中切换执行
系统挂起控制器:在用户态执行具体的操作进入下一个电源状态
九中状态:AWAKE,FREEZE,INACTIVE,STAND_BY,DOZE,SLEEP,HIBERNATE,SHUTDOWN,UNKNOWN
我们这里重点关注休眠状态SLEEP.当设备进行SLEEP状态里,会释放休眠运行锁,执行动作 echo mem > /sys/power/state,设备正式进入休眠状态。通过电源键的中断唤醒设备到AWAKE状态,加入休眠运行锁,运行锁可以防止正常休眠唤醒逻辑之外的非法休眠操作,状态机保证每一个状态出现时能正常执行对应的动作.
更多推荐
所有评论(0)