Android休眠喚醒驅動流程分析
阿新 • • 發佈:2018-12-30
在wakelock中,有2個地方可以讓系統從early_suspend進入suspend狀態。分別是:
在suspend_freeze_processes()函式中呼叫了freeze_processes()函式,而freeze_processes()函式中又呼叫了try_to_freeze_tasks()來完成凍結任務。在凍結過程中,會判斷當前程序是否新增wakeup event,若有,則凍結失敗,函式會放棄凍結。
到現在,所有的程序(也包括workqueue/kthread) 都已經停止了,核心態程序有可能在停止的時候握有一些訊號量,所以如果這時候在外設裡面去解鎖這個訊號量有可能會發生死鎖, 所以在外設suspend()函式裡面作lock/unlock鎖要非常小心,建議不要在外設的suspend()裡面等待鎖。而且suspend的過程中,有一些log是無法輸出的,所以一旦出現問題,非常難除錯。
i2c_new_device()->
client->dev.bus = &i2c_bus_type;
client->dev.type = &i2c_client_type;
client->dev.of_node = info->of_node;
ACPI_HANDLE_SET(&client->dev, info->acpi_node.handle);
/* For 10-bit clients, add an arbitrary offset to avoid collisions */
dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adap),
client->addr | ((client->flags & I2C_CLIENT_TEN)
? 0xa000 : 0));
再例如:[ [email protected]] suspend adc_key.10+ @ 865, parent: platform
platform_device_add()->
pdev->dev.bus = &platform_bus_type;
沒有定義pdev->dev.type。
state_store()->request_suspend_state()->early_suspend()->wake_unlock()->expire_wake_locks()->suspend()->pm_suspend()->enter_state()->suspend_devices_and_enter()->suspend_enter()
resum:
suspend_devices_and_enter()->dpm_resume_end()->dpm_resume()->device_resume()
LIST_HEAD(dpm_list);//extern
static LIST_HEAD(dpm_prepared_list);
static LIST_HEAD(dpm_suspended_list);
static LIST_HEAD(dpm_late_early_list);//略過
static LIST_HEAD(dpm_noirq_list);//略過
device_initialize()->device_pm_init()->device_pm_sleep_init()->INIT_LIST_HEAD(&dev->power.entry)
device初始化時,初始化&dev->power.entry。
device_add()->device_pm_add()->list_add_tail(&dev->power.entry, &dpm_list);
新增device時,將entry加入到dpm_list,按照device的新增順序。
suspend()->pm_suspend()->enter_state()->suspend_devices_and_enter()->dpm_suspend_start()->
dpm_prepare()->list_move_tail(&dev->power.entry, &dpm_prepared_list)
suspend prepare階段,將dpm_list轉移到dpm_prepared_list,順序不變。
dpm_suspend()->list_move(&dev->power.entry, &dpm_suspended_list)
suspend階段,將dpm_prepared_list轉移到dpm_suspended_list,順序反轉。
dpm_resume_end()->dpm_resume()->list_move_tail(&dev->power.entry, &dpm_prepared_list)
resum階段,將dpm_suspended_list轉移到dpm_prepared_list,順序不變。
dpm_resume_end()->dpm_complete()->list_move(&dev->power.entry, &list);
list_splice(&list, &dpm_list);
resum complete階段,將dpm_prepared_list再轉移回到dpm_list,順序再次反轉。
當所有的喚醒已經結束以後,使用者程序都已經開始運行了,但沒點亮螢幕,喚醒通常會是以下的幾種原因:
如果是來電,那麼Modem會通過傳送命令給rild來讓rild通知WindowManager有來電響應,這樣就會遠端呼叫PowerManagerService來寫”on”到 /sys/power/state 來呼叫late resume(),執行點亮螢幕等操作。
使用者按鍵事件會送到WindowManager中,WindowManager會處理這些按鍵事件,按鍵分為幾種情況,如果按鍵不是喚醒鍵,那麼WindowManager會主動放棄wakeLock來使系統進入再次休眠;如果按鍵是喚醒鍵,那麼WindowManger就會呼叫PowerManagerService中的介面來執行late resume。
- 在wake_unlock中,解鎖之後,若沒有其他的wakelock,則進入suspend。
- 在超時鎖的定時器超時後,定時器的回撥函式,會判斷有沒有其他的wakelock,若沒有,則進入suspend。
3.5 suspend()
state_store()呼叫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這兩個佇列的先後順序了。static void suspend(struct work_struct *work) { int ret; int entry_event_num; struct timespec ts_entry, ts_exit; //如果有不是自動到期的lock還沒有unlock或者自動到期的lock還沒有到期 if (has_wake_lock(WAKE_LOCK_SUSPEND)) { if (debug_mask & DEBUG_SUSPEND) pr_info("suspend: abort suspend\n"); return; } entry_event_num = current_event_num; if (debug_mask & DEBUG_SUSPEND) pr_info("suspend: sys_sync..."); sys_sync(); if (debug_mask & DEBUG_SUSPEND) pr_info("done.\n"); if (debug_mask & DEBUG_SUSPEND) pr_info("suspend: enter suspend\n"); getnstimeofday(&ts_entry); ret = pm_suspend(requested_suspend_state); getnstimeofday(&ts_exit); if (debug_mask & DEBUG_EXIT_SUSPEND) { struct rtc_time tm; rtc_time_to_tm(ts_exit.tv_sec, &tm); pr_info("suspend: exit suspend, ret = %d " "(%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)\n", ret, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, ts_exit.tv_nsec); } if (ts_exit.tv_sec - ts_entry.tv_sec <= 1) { ++suspend_short_count; if (suspend_short_count == SUSPEND_BACKOFF_THRESHOLD) { suspend_backoff(); suspend_short_count = 0; } } else { suspend_short_count = 0; } if (current_event_num == entry_event_num) { if (debug_mask & DEBUG_SUSPEND) pr_info("suspend: pm_suspend returned with no event\n"); } wake_lock_timeout(&unknown_wakeup,2* HZ); }
3.6 pm_suspend()
int pm_suspend(suspend_state_t state) { int error; if (state <= PM_SUSPEND_ON || state >= PM_SUSPEND_MAX) return -EINVAL; pm_suspend_marker("entry"); error = enter_state(state); if (error) { suspend_stats.fail++; dpm_save_failed_errno(error); } else { suspend_stats.success++; } pm_suspend_marker("exit"); return error; }
suspend()呼叫了pm_suspend(),通過判斷當前的狀態,選擇enter_state(),在enter_state()中,經過了suspend_prepare(),suspend_test()和suspend_device_and_enter(),在suspend_device_and_enter()中呼叫了device_suspend()來儲存狀態和結束系統的裝置,到了dpm_suspend()中結束所有的device。static int enter_state(suspend_state_t state) { int error; if (!valid_state(state)) return -ENODEV; if (!mutex_trylock(&pm_mutex)) return -EBUSY; if (state == PM_SUSPEND_FREEZE) freeze_begin(); printk(KERN_INFO "PM: Syncing filesystems ... "); sys_sync(); printk("done.\n"); pr_debug("PM: Preparing system for %s sleep\n", pm_states[state]); error = suspend_prepare(state); if (error) goto Unlock; if (suspend_test(TEST_FREEZER)) goto Finish; pr_debug("PM: Entering %s sleep\n", pm_states[state]); pm_restrict_gfp_mask(); error = suspend_devices_and_enter(state); pm_restore_gfp_mask(); Finish: pr_debug("PM: Finishing wakeup.\n"); suspend_finish(); Unlock: mutex_unlock(&pm_mutex); return error; }
3.6.1 suspend_prepare()
static int suspend_prepare(suspend_state_t state)
{
int error;
//平臺相關
if (need_suspend_ops(state) && (!suspend_ops || !suspend_ops->enter))
return -EPERM;
pm_prepare_console();
error = pm_notifier_call_chain(PM_SUSPEND_PREPARE);
if (error)
goto Finish;
//凍結程序
error = suspend_freeze_processes();
if (!error)
return 0;
suspend_stats.failed_freeze++;
dpm_save_failed_step(SUSPEND_FREEZE);
Finish:
pm_notifier_call_chain(PM_POST_SUSPEND);
pm_restore_console();
return error;
}
在suspend_prepare()函式中,先通過pm_prepare_console()給suspend分配一個虛擬終端來輸出資訊,再廣播一個系統進入suspend的通報,關閉使用者態的helper程序,然後呼叫suspend_freeze_processes()來凍結程序,最後會嘗試釋放一些記憶體。在suspend_freeze_processes()函式中呼叫了freeze_processes()函式,而freeze_processes()函式中又呼叫了try_to_freeze_tasks()來完成凍結任務。在凍結過程中,會判斷當前程序是否新增wakeup event,若有,則凍結失敗,函式會放棄凍結。
到現在,所有的程序(也包括workqueue/kthread) 都已經停止了,核心態程序有可能在停止的時候握有一些訊號量,所以如果這時候在外設裡面去解鎖這個訊號量有可能會發生死鎖, 所以在外設suspend()函式裡面作lock/unlock鎖要非常小心,建議不要在外設的suspend()裡面等待鎖。而且suspend的過程中,有一些log是無法輸出的,所以一旦出現問題,非常難除錯。
3.6.2 suspend_devices_and_enter()
int suspend_devices_and_enter(suspend_state_t state)
{
int error;
bool wakeup = false;
if (need_suspend_ops(state) && !suspend_ops)
return -ENOSYS;
trace_machine_suspend(state);
//沒定義begin()略過
if (need_suspend_ops(state) && suspend_ops->begin) {
error = suspend_ops->begin(state);
if (error)
goto Close;
}
suspend_console();
ftrace_stop();
suspend_test_start();
error = dpm_suspend_start(PMSG_SUSPEND);//device suspend
if (error) {
printk(KERN_ERR "PM: Some devices failed to suspend\n");
goto Recover_platform;
}
suspend_test_finish("suspend devices");
if (suspend_test(TEST_DEVICES))
goto Recover_platform;
//停在這裡
do {
error = suspend_enter(state, &wakeup);
} while (!error && !wakeup && need_suspend_ops(state)
&& suspend_ops->suspend_again && suspend_ops->suspend_again());
Resume_devices:
suspend_test_start();
dpm_resume_end(PMSG_RESUME);
suspend_test_finish("resume devices");
ftrace_start();
resume_console();
Close:
if (need_suspend_ops(state) && suspend_ops->end)
suspend_ops->end();
trace_machine_suspend(PWR_EVENT_EXIT);
return error;
Recover_platform:
if (need_suspend_ops(state) && suspend_ops->recover)
suspend_ops->recover();
goto Resume_devices;
}
suspend_devices_and_enter()函式讓外設進入休眠。該函式中,首先休眠串列埠(之後不能再顯示log,解決方法為在kernel配置選項的cmd_line中,新增”no_console_suspend”選項),再通過dpm_suspend_start()->dpm_suspend()->device_suspend()函式呼叫各驅動的suspend函式,如果是非同步suspend會呼叫async_suspend()->device_suspend()。3.6.2.1 dpm_suspend_start()
int dpm_suspend_start(pm_message_t state)
{
int error;
error = dpm_prepare(state);
if (error) {
suspend_stats.failed_prepare++;
dpm_save_failed_step(SUSPEND_PREPARE);
} else
error = dpm_suspend(state);
return error;
}
int dpm_prepare(pm_message_t state)
{
int error = 0;
might_sleep();
mutex_lock(&dpm_list_mtx);
while (!list_empty(&dpm_list)) {
struct device *dev = to_device(dpm_list.next);
get_device(dev);
mutex_unlock(&dpm_list_mtx);
//這裡會呼叫 dev->XXXX->prepare(),callback()的選擇順序同dpm_suspend()
error = device_prepare(dev, state);
mutex_lock(&dpm_list_mtx);
if (error) {
if (error == -EAGAIN) {
put_device(dev);
error = 0;
continue;
}
printk(KERN_INFO "PM: Device %s not prepared "
"for power transition: code %d\n",
dev_name(dev), error);
put_device(dev);
break;
}
dev->power.is_prepared = true;
//dpm_list轉移到dpm_prepared_list,新增到結尾,兩個list順序一致
if (!list_empty(&dev->power.entry))
list_move_tail(&dev->power.entry, &dpm_prepared_list);
put_device(dev);
}
mutex_unlock(&dpm_list_mtx);
return error;
}
int dpm_suspend(pm_message_t state)
{
ktime_t starttime = ktime_get();
int error = 0;
might_sleep();
mutex_lock(&dpm_list_mtx);
pm_transition = state;
async_error = 0;
while (!list_empty(&dpm_prepared_list)) {
struct device *dev = to_device(dpm_prepared_list.prev);
get_device(dev);
mutex_unlock(&dpm_list_mtx);
//device suspend
error = device_suspend(dev);
mutex_lock(&dpm_list_mtx);
if (error) {
pm_dev_err(dev, state, "", error);
dpm_save_failed_dev(dev_name(dev));
put_device(dev);
break;
}
if (!list_empty(&dev->power.entry))
//dpm_prepared_list轉移到dpm_suspended_list,新增到list頭,兩個list順序相反
list_move(&dev->power.entry, &dpm_suspended_list);
put_device(dev);
if (async_error)
break;
}
mutex_unlock(&dpm_list_mtx);
async_synchronize_full();
if (!error)
error = async_error;
if (error) {
suspend_stats.failed_suspend++;
dpm_save_failed_step(SUSPEND_SUSPEND);
} else
dpm_show_time(starttime, state, NULL);
return error;
}
suspend callback的選擇順序:
dev->pm_domain->ops.suspend
dev->type->pm->suspend
dev->class->pm->suspend
dev->class->suspend
dev->bus->pm->suspend
dev->bus->suspend
dev->driver->pm->suspend
例如:[ [email protected]] suspend input1+ @ 865, parent: 1-0040
一般這個parent 為none,因為程式碼中
input_device->dev.parent = &client->dev;
所以找了一個parent。
input_allocate_device()->
dev->dev.type = &input_dev_type;
dev->dev.class = &input_class;
device_initialize(&dev->dev);
input_register_device()->
dev_set_name(&dev->dev, "input%ld",
(unsigned long) atomic_inc_return(&input_no) - 1);
static struct device_type input_dev_type = {
.groups = input_dev_attr_groups,
.release = input_dev_release,
.uevent = input_dev_uevent,
#ifdef CONFIG_PM
.pm = &input_dev_pm_ops,
#endif
};
static const struct dev_pm_ops input_dev_pm_ops = {
.suspend = input_dev_suspend,
.resume = input_dev_resume,
.poweroff = input_dev_suspend,
.restore = input_dev_resume,
};
static int input_dev_suspend(struct device *dev)
{
struct input_dev *input_dev = to_input_dev(dev);
mutex_lock(&input_dev->mutex);
if (input_dev->users)
input_dev_toggle(input_dev, false);
mutex_unlock(&input_dev->mutex);
return 0;
}
再例如:[ [email protected]] suspend 1-0040+ @ 865, parent: i2c-1i2c_new_device()->
client->dev.bus = &i2c_bus_type;
client->dev.type = &i2c_client_type;
client->dev.of_node = info->of_node;
ACPI_HANDLE_SET(&client->dev, info->acpi_node.handle);
/* For 10-bit clients, add an arbitrary offset to avoid collisions */
dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adap),
client->addr | ((client->flags & I2C_CLIENT_TEN)
? 0xa000 : 0));
static struct device_type i2c_client_type = {
.groups = i2c_dev_attr_groups,
.uevent = i2c_device_uevent,
.release = i2c_client_dev_release,
};
沒有定義dev_pm_ops,繼續找i2c_bus_type。struct bus_type i2c_bus_type = {
.name = "i2c",
.match = i2c_device_match,
.probe = i2c_device_probe,
.remove = i2c_device_remove,
.shutdown = i2c_device_shutdown,
.pm = &i2c_device_pm_ops,
};
static const struct dev_pm_ops i2c_device_pm_ops = {
.suspend = i2c_device_pm_suspend,
.resume = i2c_device_pm_resume,
.freeze = i2c_device_pm_freeze,
.thaw = i2c_device_pm_thaw,
.poweroff = i2c_device_pm_poweroff,
.restore = i2c_device_pm_restore,
SET_RUNTIME_PM_OPS(
pm_generic_runtime_suspend,
pm_generic_runtime_resume,
pm_generic_runtime_idle
)
};
static int i2c_device_pm_suspend(struct device *dev)
{
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
//如果device對應的driver定義了pm,pm->suspend存在,呼叫pm->suspend(dev)
if (pm)
return pm_generic_suspend(dev);
//如果沒有定義pm,如果driver->suspend存在,呼叫driver->suspend(client, mesg)
else
return i2c_legacy_suspend(dev, PMSG_SUSPEND);
}
如果driver->pm定義了,就不會執行driver->suspend了。再例如:[ [email protected]] suspend adc_key.10+ @ 865, parent: platform
platform_device_add()->
pdev->dev.bus = &platform_bus_type;
沒有定義pdev->dev.type。
struct bus_type platform_bus_type = {
.name = "platform",
.dev_attrs = platform_dev_attrs,
.match = platform_match,
.uevent = platform_uevent,
.pm = &platform_dev_pm_ops,
};
static const struct dev_pm_ops platform_dev_pm_ops = {
.runtime_suspend = pm_generic_runtime_suspend,
.runtime_resume = pm_generic_runtime_resume,
.runtime_idle = pm_generic_runtime_idle,
USE_PLATFORM_PM_SLEEP_OPS
};
#define USE_PLATFORM_PM_SLEEP_OPS \
.suspend = platform_pm_suspend, \
.resume = platform_pm_resume, \
.freeze = platform_pm_freeze, \
.thaw = platform_pm_thaw, \
.poweroff = platform_pm_poweroff, \
.restore = platform_pm_restore,
int platform_pm_suspend(struct device *dev)
{
struct device_driver *drv = dev->driver;
int ret = 0;
if (!drv)
return 0;
if (drv->pm) {
if (drv->pm->suspend)
ret = drv->pm->suspend(dev);
} else {
ret = platform_legacy_suspend(dev, PMSG_SUSPEND);
}
return ret;
}
同樣,如果driver->pm定義了,就不會執行driver->suspend了。3.6.2.2 suspend_enter()
static int suspend_enter(suspend_state_t state, bool *wakeup)
{
int error;
//平臺相關
if (need_suspend_ops(state) && suspend_ops->prepare) {
error = suspend_ops->prepare();
if (error)
goto Platform_finish;
}
// Execute "late" and "noirq" device suspend callbacks.
error = dpm_suspend_end(PMSG_SUSPEND);
if (error) {
printk(KERN_ERR "PM: Some devices failed to power down\n");
goto Platform_finish;
}
if (need_suspend_ops(state) && suspend_ops->prepare_late) {
error = suspend_ops->prepare_late();
if (error)
goto Platform_wake;
}
if (suspend_test(TEST_PLATFORM))
goto Platform_wake;
/*
* PM_SUSPEND_FREEZE equals
* frozen processes + suspended devices + idle processors.
* Thus we should invoke freeze_enter() soon after
* all the devices are suspended.
*/
if (state == PM_SUSPEND_FREEZE) {
freeze_enter();
goto Platform_wake;
}
error = disable_nonboot_cpus();
if (error || suspend_test(TEST_CPUS))
goto Enable_cpus;
//關中斷
arch_suspend_disable_irqs();
BUG_ON(!irqs_disabled());
error = syscore_suspend();
if (!error) {
*wakeup = pm_wakeup_pending();
if (!(suspend_test(TEST_CORE) || *wakeup)) {
// enter(state)使CPU進入省電狀態,整個休眠過程完成,程式碼停止
error = suspend_ops->enter(state);
events_check_enabled = false;
}
syscore_resume();
}
arch_suspend_enable_irqs();
BUG_ON(irqs_disabled());
Enable_cpus:
enable_nonboot_cpus();
Platform_wake:
if (need_suspend_ops(state) && suspend_ops->wake)
suspend_ops->wake();
dpm_resume_start(PMSG_RESUME);
Platform_finish:
if (need_suspend_ops(state) && suspend_ops->finish)
suspend_ops->finish();
return error;
}
suspend:state_store()->request_suspend_state()->early_suspend()->wake_unlock()->expire_wake_locks()->suspend()->pm_suspend()->enter_state()->suspend_devices_and_enter()->suspend_enter()
resum:
suspend_devices_and_enter()->dpm_resume_end()->dpm_resume()->device_resume()
3.7 enter_state()->suspend_devices_and_enter()->dpm_resume_end()
void dpm_resume_end(pm_message_t state)
{
dpm_resume(state);
dpm_complete(state);
}
3.7.1 dpm_resume()
void dpm_resume(pm_message_t state)
{
struct device *dev;
ktime_t starttime = ktime_get();
might_sleep();
mutex_lock(&dpm_list_mtx);
pm_transition = state;
async_error = 0;
//非同步resum
list_for_each_entry(dev, &dpm_suspended_list, power.entry) {
INIT_COMPLETION(dev->power.completion);
if (is_async(dev)) {
get_device(dev);
async_schedule(async_resume, dev);
}
}
//resum的list和suspend是相反的
while (!list_empty(&dpm_suspended_list)) {
dev = to_device(dpm_suspended_list.next);
get_device(dev);
if (!is_async(dev)) {
int error;
mutex_unlock(&dpm_list_mtx);
//callback選擇順序同suspend
error = device_resume(dev, state, false);
if (error) {
suspend_stats.failed_resume++;
dpm_save_failed_step(SUSPEND_RESUME);
dpm_save_failed_dev(dev_name(dev));
pm_dev_err(dev, state, "", error);
}
mutex_lock(&dpm_list_mtx);
}
if (!list_empty(&dev->power.entry))
list_move_tail(&dev->power.entry, &dpm_prepared_list);
put_device(dev);
}
mutex_unlock(&dpm_list_mtx);
async_synchronize_full();
dpm_show_time(starttime, state, NULL);
}
無論是同步resum,還是非同步resum都會呼叫device_resume();3.7.2 dpm_complete()
void dpm_complete(pm_message_t state)
{
struct list_head list;
might_sleep();
INIT_LIST_HEAD(&list);
mutex_lock(&dpm_list_mtx);
//包括新增加的device
while (!list_empty(&dpm_prepared_list)) {
struct device *dev = to_device(dpm_prepared_list.prev);
get_device(dev);
dev->power.is_prepared = false;
list_move(&dev->power.entry, &list);
mutex_unlock(&dpm_list_mtx);
//執行callbacks
device_complete(dev, state);
mutex_lock(&dpm_list_mtx);
put_device(dev);
}
list_splice(&list, &dpm_list);
mutex_unlock(&dpm_list_mtx);
}
睡眠喚醒過程中的一些list:LIST_HEAD(dpm_list);//extern
static LIST_HEAD(dpm_prepared_list);
static LIST_HEAD(dpm_suspended_list);
static LIST_HEAD(dpm_late_early_list);//略過
static LIST_HEAD(dpm_noirq_list);//略過
device_initialize()->device_pm_init()->device_pm_sleep_init()->INIT_LIST_HEAD(&dev->power.entry)
device初始化時,初始化&dev->power.entry。
device_add()->device_pm_add()->list_add_tail(&dev->power.entry, &dpm_list);
新增device時,將entry加入到dpm_list,按照device的新增順序。
suspend()->pm_suspend()->enter_state()->suspend_devices_and_enter()->dpm_suspend_start()->
dpm_prepare()->list_move_tail(&dev->power.entry, &dpm_prepared_list)
suspend prepare階段,將dpm_list轉移到dpm_prepared_list,順序不變。
dpm_suspend()->list_move(&dev->power.entry, &dpm_suspended_list)
suspend階段,將dpm_prepared_list轉移到dpm_suspended_list,順序反轉。
dpm_resume_end()->dpm_resume()->list_move_tail(&dev->power.entry, &dpm_prepared_list)
resum階段,將dpm_suspended_list轉移到dpm_prepared_list,順序不變。
dpm_resume_end()->dpm_complete()->list_move(&dev->power.entry, &list);
list_splice(&list, &dpm_list);
resum complete階段,將dpm_prepared_list再轉移回到dpm_list,順序再次反轉。
3.8 enter_state()->suspend_finish()
static void suspend_finish(void)
{
suspend_thaw_processes();
pm_notifier_call_chain(PM_POST_SUSPEND);
pm_restore_console();
}
在suspend_finish()函式中,解凍程序和任務,使能使用者空間helper程序,廣播一個系統從suspend狀態退出的notify,喚醒終端。當所有的喚醒已經結束以後,使用者程序都已經開始運行了,但沒點亮螢幕,喚醒通常會是以下的幾種原因:
如果是來電,那麼Modem會通過傳送命令給rild來讓rild通知WindowManager有來電響應,這樣就會遠端呼叫PowerManagerService來寫”on”到 /sys/power/state 來呼叫late resume(),執行點亮螢幕等操作。
使用者按鍵事件會送到WindowManager中,WindowManager會處理這些按鍵事件,按鍵分為幾種情況,如果按鍵不是喚醒鍵,那麼WindowManager會主動放棄wakeLock來使系統進入再次休眠;如果按鍵是喚醒鍵,那麼WindowManger就會呼叫PowerManagerService中的介面來執行late resume。