前面我们分析了休眠的第一个阶段即浅度休眠,现在我们继续看休眠的第二个阶段 — 深度休眠。在深度休眠的过程中系统会首先冻结所有可以冻结的进程,然后依次挂起所有设备的电源,
挂起顺序与设备注册的顺序相反,这样保证了设备之间电源的依赖性;直至最后进入省电模式,等待用户或者RTC唤醒;在唤醒过程中则会按照设备注册的顺序依次恢复每个设备的电源进入正常工作状态,解冻相关的进程,然后再进行浅度休眠的唤醒流程。
1、深度休眠入口
根据wake_lock一节的分析我们知道driver层进入深度休眠的入口有4个,分别为expire_timer、wake_lock、wake_lock_timeout、wake_unlock,这几个入口函数将根据相应的条件启动suspend_work里面的pm_suspend()函数进入深度休眠流程,代码在linux/kernel/power/suspend.c中:
[cpp]
view plaincopy
-
-
int
enter_state(suspend_state_t state)
-
{
-
int error;
-
-
if (!valid_state(state))
-
return -ENODEV;
-
-
if (!mutex_trylock(&pm_mutex))
-
return -EBUSY;
-
-
printk(KERN_INFO
"PM: Syncing filesystems ... ");
-
sys_sync();
-
printk("done.
");
-
-
pr_debug("PM: Preparing
system for %s sleep
", pm_states[state]);
-
-
error = suspend_prepare();
-
if (error)
-
goto Unlock;
-
-
if (suspend_test(TEST_FREEZER))
-
goto Finish;
-
-
pr_debug("PM: Entering
%s sleep
", pm_states[state]);
-
-
error = suspend_devices_and_enter(state);
-
-
Finish:
-
pr_debug("PM: Finishing
wakeup.
");
-
suspend_finish();
-
Unlock:
-
mutex_unlock(&pm_mutex);
-
return error;
-
}
-
-
int
pm_suspend(suspend_state_t state)
-
{
-
if (state > PM_SUSPEND_ON && state <= PM_SUSPEND_MAX)
-
return enter_state(state);
-
return -EINVAL;
-
}
-
EXPORT_SYMBOL(pm_suspend);
在enter_state()中首先进入状态的判断,根据平台的特性判断是否支持此状态;然后再同步缓存;接着调用suspend_prepare()冻结大部分进程;然后再通过suspend_devices_and_enter()开始挂起设备。
2、冻结进程
[cpp]
view plaincopy
-
static
int
suspend_prepare(void)
-
{
-
int error;
-
-
if (!suspend_ops || !suspend_ops->enter)
-
return -EPERM;
-
-
pm_prepare_console();
-
-
-
error = pm_notifier_call_chain(PM_SUSPEND_PREPARE);
-
if (error)
-
goto Finish;
-
-
error = usermodehelper_disable();
-
if (error)
-
goto Finish;
-
-
error = suspend_freeze_processes();
-
if (!error)
-
return 0;
-
-
-
suspend_thaw_processes();
-
-
usermodehelper_enable();
-
Finish:
-
-
pm_notifier_call_chain(PM_POST_SUSPEND);
-
pm_restore_console();
-
return error;
-
}
这里有一个notifier机制后面要专门分析下。
3、挂起设备
[cpp]
view plaincopy
-
int
suspend_devices_and_enter(suspend_state_t state)
-
{
-
int error;
-
-
if (!suspend_ops)
-
return -ENOSYS;
-
-
if (suspend_ops->begin) {
-
error = suspend_ops->begin(state);
-
if (error)
-
goto Close;
-
}
-
-
suspend_console();
-
suspend_test_start();
-
-
error = dpm_suspend_start(PMSG_SUSPEND);
-
if (error) {
-
printk(KERN_ERR
"PM: Some devices failed to suspend
");
-
&nb