suspend-resume(3)

来源:互联网 发布:听力复读软件 编辑:程序博客网 时间:2024/06/05 07:19

跟休眠唤醒相关的文件:

[html] view plaincopy
  1. linux_source/kernel/power/main.c  
  2. linux_source/kernel/power/earlysuspend.c  
  3. linux_source/kernel/power/wakelock.c  
  4. linux_source/kernel/power/suspend.c  
  5. linux_source/kernel/power/power.h  
  6. linux_source/kernel/power/process.c  
  7. linux_source/drivers/base/power/main.c  
  8. linux_source/arch/arm/plat-samsung/pm.c  
  9.   
  10. android\hardware\libhardware_legacy\power\power.c  
  11. android\frameworks\base\core\jni\android_os_Power.cpp  
  12. android\frameworks\base\core\java\android\os\Power.java  
  13. android\frameworks\base\core\java\android\os\PowerManager.java  
  14. android\frameworks\base\services\java\com\android\server\PowerManagerService.java  
  15. android\frameworks\base\policy\src\com\android\internal\policy\impl\PhoneWindowManager.java  


Android 休眠过程
当用户读写/sys/power/state时,linux_source/kernel/power/main.c中的state_store()函数会被调用。其中,android的early_suspend会执行request_suspend_state(state); 而标准的linux休眠则执行error = enter_state(state)

[cpp] view plaincopy
  1. linux_source/kernel/power/main.c  
  2. static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,  
  3.                const char *buf, size_t n)  
  4. {  
  5. #ifdef CONFIG_SUSPEND  
  6. #ifdef CONFIG_EARLYSUSPEND  
  7.     suspend_state_t state = PM_SUSPEND_ON;  
  8. #else  
  9.     suspend_state_t state = PM_SUSPEND_STANDBY;  
  10. #endif  
  11.     const char * const *s;  
  12. #endif  
  13.     char *p;  
  14.     int len;  
  15.     int error = -EINVAL;  
  16.   
  17.     p = memchr(buf, '\n', n);  
  18.     len = p ? p - buf : n;  
  19.   
  20.     /* First, check if we are requested to hibernate */  
  21.     if (len == 4 && !strncmp(buf, "disk", len)) {  
  22.         error = hibernate();  
  23.   goto Exit;  
  24.     }  
  25.   
  26. #ifdef CONFIG_SUSPEND  
  27.     for (s = &pm_states[state]; state < PM_SUSPEND_MAX; s++, state++) {  
  28.         if (*s && len == strlen(*s) && !strncmp(buf, *s, len))  
  29.             break;  
  30.     }  
  31.     if (state < PM_SUSPEND_MAX && *s)  
  32. #ifdef <strong><span style="color:#3366ff;">CONFIG_EARLYSUSPEND</span></strong>  
  33.         if (state == PM_SUSPEND_ON || valid_state(state)) {  
  34.             error = 0;  
  35.             <span style="color:#3366ff;"><strong>request_suspend_state(state);</strong></span>  
  36.         }  
  37. #else  
  38.         error = enter_state(state);  
  39. #endif  
  40. #endif  
  41.   
  42.  Exit:  
  43.     return error ? error : n;  
  44. }  


在request_suspend_state(state)函数中,会调用early_suspend_work的工作队列,从而进入early_suspend()函数中

[cpp] view plaincopy
  1. linux_source/kernel/power/earlysuspend.c  
  2. static DECLARE_WORK(early_suspend_work, early_suspend);  
  3. void request_suspend_state(suspend_state_t new_state)  
  4. {  
  5.     unsigned long irqflags;  
  6.     int old_sleep;  
  7.   
  8.     spin_lock_irqsave(&state_lock, irqflags);  
  9.     old_sleep = state & SUSPEND_REQUESTED;  
  10.     if (debug_mask & DEBUG_USER_STATE) {  
  11.         struct timespec ts;  
  12.         struct rtc_time tm;  
  13.         getnstimeofday(&ts);  
  14.         rtc_time_to_tm(ts.tv_sec, &tm);  
  15.         pr_info("request_suspend_state: %s (%d->%d) at %lld "  
  16.             "(%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)\n",  
  17.             new_state != PM_SUSPEND_ON ? "sleep" : "wakeup",  
  18.             requested_suspend_state, new_state,  
  19.             ktime_to_ns(ktime_get()),  
  20.             tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,  
  21.             tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec);  
  22.     }  
  23.     if (!old_sleep && new_state != PM_SUSPEND_ON) {  
  24.         state |= SUSPEND_REQUESTED;  
  25.         <span style="color:#3366ff;"><strong>queue_work(suspend_work_queue, &early_suspend_work);</strong></span>  
  26.     } else if (old_sleep && new_state == PM_SUSPEND_ON) {  
  27.         state &= ~SUSPEND_REQUESTED;  
  28.         wake_lock(&main_wake_lock);  
  29.         <span style="color:#3366ff;"><strong>queue_work(suspend_work_queue, &late_resume_work);</strong></span>  
  30.     }  
  31.     requested_suspend_state = new_state;  
  32.     spin_unlock_irqrestore(&state_lock, irqflags);  
  33. }  


在early_suspend()函数中,首先要判断当前请求的状态是否还是suspend,若不是,则直接退出了;若是,函数会调用已经注册的early_suspend的函数,然后同步文件系统,最后释放main_wake_lock。

[cpp] view plaincopy
  1. linux_source/kernel/power/earlysuspend.c  
  2. static void early_suspend(struct work_struct *work)  
  3. {  
  4.     struct early_suspend *pos;  
  5.     unsigned long irqflags;  
  6.     int abort = 0;  
  7.   
  8.     mutex_lock(&early_suspend_lock);  
  9.     spin_lock_irqsave(&state_lock, irqflags);  
  10.     if (state == SUSPEND_REQUESTED)  
  11.         state |= SUSPENDED;  
  12.     else  
  13.         abort = 1;  
  14.     spin_unlock_irqrestore(&state_lock, irqflags);  
  15.   
  16.     if (abort) {  
  17.         if (debug_mask & DEBUG_SUSPEND)  
  18.             pr_info("early_suspend: abort, state %d\n", state);  
  19.         mutex_unlock(&early_suspend_lock);  
  20.         goto abort;  
  21.     }  
  22.   
  23.     if (debug_mask & DEBUG_SUSPEND)  
  24.         pr_info("early_suspend: call handlers\n");  
  25.     list_for_each_entry(pos, &early_suspend_handlers, link) {  
  26.         if (pos->suspend != NULL) {  
  27.             if (debug_mask & DEBUG_VERBOSE)  
  28.                 pr_info("early_suspend: calling %pf\n", pos->suspend);  
  29.             pos->suspend(pos);  
  30.         }  
  31.     }  
  32.     mutex_unlock(&early_suspend_lock);  
  33.   
  34.     if (debug_mask & DEBUG_SUSPEND)  
  35.         pr_info("early_suspend: sync\n");  
  36.   
  37.     sys_sync();  
  38. abort:  
  39.     spin_lock_irqsave(&state_lock, irqflags);  
  40.     if (state == SUSPEND_REQUESTED_AND_SUSPENDED)  
  41.         <span style="color:#3366ff;"><strong>wake_unlock(&main_wake_lock);</strong></span>  
  42.     spin_unlock_irqrestore(&state_lock, irqflags);  
  43. }  

 

在wake_unlock()中,删除链表中wake_lock节点,判断当前是否存在wake_lock,若wake_lock的数目为0,则调用工作队列suspend_work,进入suspend状态。

[cpp] view plaincopy
  1. linux_source/kernel/power/wakelock.c  
  2. static DECLARE_WORK(suspend_work, suspend);  
  3. void wake_unlock(struct wake_lock *lock)  
  4. {  
  5.     int type;  
  6.     unsigned long irqflags;  
  7.     spin_lock_irqsave(&list_lock, irqflags);  
  8.     type = lock->flags & WAKE_LOCK_TYPE_MASK;  
  9. #ifdef CONFIG_WAKELOCK_STAT  
  10.     wake_unlock_stat_locked(lock, 0);  
  11. #endif  
  12.     if (debug_mask & DEBUG_WAKE_LOCK)  
  13.         pr_info("wake_unlock: %s\n", lock->name);  
  14.     lock->flags &= ~(WAKE_LOCK_ACTIVE | WAKE_LOCK_AUTO_EXPIRE);  
  15.     list_del(&lock->link);  
  16.     list_add(&lock->link, &inactive_locks);  
  17.     if (type == WAKE_LOCK_SUSPEND) {  
  18.         long has_lock = has_wake_lock_locked(type);  
  19.         if (has_lock > 0) {  
  20.             if (debug_mask & DEBUG_EXPIRE)  
  21.                 pr_info("wake_unlock: %s, start expire timer, "  
  22.                     "%ld\n", lock->name, has_lock);  
  23.             mod_timer(&expire_timer, jiffies + has_lock);  
  24.         } else {  
  25.             if (del_timer(&expire_timer))  
  26.                 if (debug_mask & DEBUG_EXPIRE)  
  27.                     pr_info("wake_unlock: %s, stop expire "  
  28.                         "timer\n", lock->name);  
  29.             if (has_lock == 0){  
  30.                 <span style="color:#3366ff;"><strong>queue_work(suspend_work_queue, &suspend_work);</strong></span>  
  31.             }  
  32.         }  
  33.         if (lock == &main_wake_lock) {  
  34.             if (debug_mask & DEBUG_SUSPEND)  
  35.                 print_active_locks(WAKE_LOCK_SUSPEND);  
  36. #ifdef CONFIG_WAKELOCK_STAT  
  37.             update_sleep_wait_stats_locked(0);  
  38. #endif  
  39.         }  
  40.     }  
  41.     spin_unlock_irqrestore(&list_lock, irqflags);  
  42. }  
  43. EXPORT_SYMBOL(wake_unlock);  

 

在suspend()函数中,先判断当前是否有wake_lock,若有,则退出;然后同步文件系统,最后调用pm_suspend()函数。

[cpp] view plaincopy
  1. linux_source/kernel/power/wakelock.c  
  2. static void suspend(struct work_struct *work)  
  3. {  
  4.     int ret;  
  5.     int entry_event_num;  
  6.     struct timespec ts_entry, ts_exit;  
  7.   
  8.     if (has_wake_lock(WAKE_LOCK_SUSPEND)) {  
  9.         if (debug_mask & DEBUG_SUSPEND)  
  10.             pr_info("suspend: abort suspend\n");  
  11.         return;  
  12.     }  
  13.   
  14.     entry_event_num = current_event_num;  
  15.     sys_sync();  
  16.     if (debug_mask & DEBUG_SUSPEND)  
  17.         pr_info("suspend: enter suspend\n");  
  18.     getnstimeofday(&ts_entry);  
  19.     <span style="color:#3366ff;"><strong>ret = pm_suspend(requested_suspend_state);</strong></span>  
  20.     getnstimeofday(&ts_exit);  
  21.   
  22.     if (debug_mask & DEBUG_EXIT_SUSPEND) {  
  23.         struct rtc_time tm;  
  24.         rtc_time_to_tm(ts_exit.tv_sec, &tm);  
  25.         pr_info("suspend: exit suspend, ret = %d "  
  26.             "(%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)\n", ret,  
  27.             tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,  
  28.             tm.tm_hour, tm.tm_min, tm.tm_sec, ts_exit.tv_nsec);  
  29.     }  
  30.   
  31.     if (ts_exit.tv_sec - ts_entry.tv_sec <= 1) {  
  32.         ++suspend_short_count;  
  33.   
  34.         if (suspend_short_count == SUSPEND_BACKOFF_THRESHOLD) {  
  35.             suspend_backoff();  
  36.             suspend_short_count = 0;  
  37.         }  
  38.     } else {  
  39.         suspend_short_count = 0;  
  40.     }  
  41.   
  42.     if (current_event_num == entry_event_num) {  
  43.         if (debug_mask & DEBUG_SUSPEND)  
  44.             pr_info("suspend: pm_suspend returned with no event\n");  
  45.         wake_lock_timeout(&unknown_wakeup, HZ / 2);  
  46.     }  
  47. }  
  48. static DECLARE_WORK(suspend_work, suspend); //stone tag  


在pm_suspend()函数中,enter_state()函数被调用,从而进入标准linux休眠过程。

[cpp] view plaincopy
  1. linux_source/kernel/power/suspend.c  
  2. /** 
  3.  *  pm_suspend - Externally visible function for suspending system. 
  4.  *  @state:     Enumerated value of state to enter. 
  5.  * 
  6.  *  Determine whether or not value is within range, get state 
  7.  *  structure, and enter (above). 
  8.  */  
  9. int pm_suspend(suspend_state_t state)  
  10. {  
  11.     if (state > PM_SUSPEND_ON && state < PM_SUSPEND_MAX){  
  12.         return <span style="color:#3366ff;"><strong>enter_state(state);</strong></span>  
  13.     }  
  14.     return -EINVAL;  
  15. }  
  16. EXPORT_SYMBOL(pm_suspend);  


在enter_state()函数中,首先检查一些状态参数,再同步文件系统,然后调用suspend_prepare()来冻结进程,最后调用suspend_devices_and_enter()让外设进入休眠。

[cpp] view plaincopy
  1. linux_source/kernel/power/suspend.c  
  2. /** 
  3.  *  enter_state - Do common work of entering low-power state. 
  4.  *  @state:     pm_state structure for state we're entering. 
  5.  * 
  6.  *  Make sure we're the only ones trying to enter a sleep state. Fail 
  7.  *  if someone has beat us to it, since we don't want anything weird to 
  8.  *  happen when we wake up. 
  9.  *  Then, do the setup for suspend, enter the state, and cleaup (after 
  10.  *  we've woken up). 
  11.  */  
  12. int enter_state(suspend_state_t state)  
  13. {  
  14.     int error;  
  15.   
  16.     if (!valid_state(state))  
  17.         return -ENODEV;  
  18.   
  19.     if (!mutex_trylock(&pm_mutex))  
  20.         return -EBUSY;  
  21.   
  22.     printk(KERN_INFO "PM: Syncing filesystems ... ");  
  23.     sys_sync();  
  24.     printk("done.\n");  
  25.   
  26.     pr_debug("PM: Preparing system for %s sleep\n", pm_states[state]);  
  27.     <span style="color:#3366ff;"><strong>error = suspend_prepare();</strong> </span>  
  28.     if (error)  
  29.         goto Unlock;  
  30.   
  31.     if (suspend_test(TEST_FREEZER))  
  32.         goto Finish;  
  33.   
  34.     pr_debug("PM: Entering %s sleep\n", pm_states[state]);  
  35.     pm_restrict_gfp_mask();  
  36.     <span style="color:#3366ff;"><strong>error = suspend_devices_and_enter(state);</strong></span>  
  37.     pm_restore_gfp_mask();  
  38.   
  39.  Finish:  
  40.     pr_debug("PM: Finishing wakeup.\n");  
  41.     <span style="color:#3366ff;"><strong>suspend_finish();</strong></span>  
  42.  Unlock:  
  43.     mutex_unlock(&pm_mutex);  
  44.     return error;  
  45. }  


在suspend_prepare()函数中,先通过pm_prepare_console();给suspend分配一个虚拟终端来输出信息,再广播一个系统进入suspend的通报,关闭用户态的helper进程,然后调用suspend_freeze_processes()来冻结进程,最后会尝试释放一些内存。

[cpp] view plaincopy
  1. linux_source/kernel/power/suspend.c  
  2. /** 
  3.  *  suspend_prepare - Do prep work before entering low-power state. 
  4.  * 
  5.  *  This is common code that is called for each state that we're entering. 
  6.  *  Run suspend notifiers, allocate a console and stop all processes. 
  7.  */  
  8. static int suspend_prepare(void)  
  9. {  
  10.     int error;  
  11.   
  12.     if (!suspend_ops || !suspend_ops->enter)  
  13.         return -EPERM;  
  14.   
  15.     pm_prepare_console();  
  16.   
  17.     error = pm_notifier_call_chain(PM_SUSPEND_PREPARE);  
  18.     if (error)  
  19.         goto Finish;  
  20.   
  21.     error = usermodehelper_disable();  
  22.     if (error)  
  23.         goto Finish;  
  24.   
  25.     <span style="color:#3366ff;"><strong>error = suspend_freeze_processes();</strong></span>  
  26.     if (!error)  
  27.         return 0;  
  28.   
  29.     suspend_thaw_processes();  
  30.     usermodehelper_enable();  
  31.  Finish:  
  32.     pm_notifier_call_chain(PM_POST_SUSPEND);  
  33.     pm_restore_console();  
  34.     return error;  
  35. }  

在suspend_freeze_processes()函数中调用了freeze_processes()函数,而freeze_processes()函数中又调用了try_to_freeze_tasks()来完成冻结任务。在冻结过程中,会判断当前进程是否有wake_lock,若有,则冻结失败,函数会放弃冻结。
[cpp] view plaincopy
  1. linux_source/kernel/power/power.h  
  2. static inline int suspend_freeze_processes(void)  
  3. {  
  4.     return freeze_processes(); //stone tag  
  5. }  
[cpp] view plaincopy
  1. linux_source/kernel/power/process.c  
  2. /** 
  3.  *  freeze_processes - tell processes to enter the refrigerator 
  4.  */  
  5. int freeze_processes(void)  
  6. {  
  7.     int error;  
  8.   
  9.     printk("Freezing user space processes ... ");  
  10.     <span style="color:#3366ff;"><strong>error = try_to_freeze_tasks(true);</strong></span>  
  11.     if (error)  
  12.         goto Exit;  
  13.     printk("done.\n");  
  14.   
  15.     printk("Freezing remaining freezable tasks ... ");  
  16.     <span style="color:#3366ff;"><strong>error = try_to_freeze_tasks(false);</strong></span>  
  17.     if (error)  
  18.         goto Exit;  
  19.     printk("done.");  
  20.   
  21.     oom_killer_disable();  
  22.  Exit:  
  23.     BUG_ON(in_atomic());  
  24.     printk("\n");  
  25.   
  26.     return error;  
  27. }  

到现在,所有的进程(也包括workqueue/kthread) 都已经停止了,内核态进程有可能在停止的时候握有一些信号量,所以如果这时候在外设里面去解锁这个信号量有可能会发生死锁, 所以在外设suspend()函数里面作lock/unlock锁要非常小心,建议不要在外设的suspend()里面等待锁。而且suspend的过程中,有一些log是无法输出的,所以一旦出现问题,非常难调试。

回到enter_state()函数中,在冻结进程完成后,调用suspend_devices_and_enter()函数让外设进入休眠。该函数中,首先休眠串口(之后不能再显示log,解决方法为在kernel配置选项的cmd_line中,添加”no_console_suspend”选项,或者直接注释掉suspend_console()函数),再通过dpm_suspend_start(PMSG_SUSPEND);函数调用各驱动的suspend函数。 

[cpp] view plaincopy
  1. linux_source/kernel/power/suspend.c  
  2. /**  
  3.  *  suspend_devices_and_enter - suspend devices and enter the desired system 
  4.  *                  sleep state. 
  5.  *  @state:       state to enter 
  6.  */  
  7. int suspend_devices_and_enter(suspend_state_t state)  
  8. {  
  9.     int error;  
  10.   
  11.     if (!suspend_ops)  
  12.         return -ENOSYS;  
  13.   
  14.     trace_machine_suspend(state);  
  15.     if (suspend_ops->begin) {  
  16.         error = suspend_ops->begin(state);  
  17.         if (error)  
  18.             goto Close;  
  19.     }  
  20.     <span style="color:#ff6666;"><strong>//suspend_console();  
  21. </strong></span>    suspend_test_start();  
  22.     <span style="color:#3366ff;"><strong>error = dpm_suspend_start(PMSG_SUSPEND);</strong></span>  
  23.     if (error) {  
  24.         printk(KERN_ERR "PM: Some devices failed to suspend\n");  
  25.         goto Recover_platform;  
  26.     }  
  27.     suspend_test_finish("suspend devices");  
  28.     if (suspend_test(TEST_DEVICES))  
  29.         goto Recover_platform;  
  30.     <span style="color:#3366ff;"><strong>error = suspend_enter(state);</strong></span>  
  31.   
  32.  Resume_devices:  
  33.     suspend_test_start();  
  34.     <span style="color:#3366ff;"><strong>dpm_resume_end(PMSG_RESUME);</strong></span>  
  35.     suspend_test_finish("resume devices");  
  36.     <span style="color:#ff6666;"><strong>//resume_console();</strong></span>  
  37.  Close:  
  38.     if (suspend_ops->end)  
  39.         suspend_ops->end();  
  40.     trace_machine_suspend(PWR_EVENT_EXIT);  
  41.     return error;  
  42.   
  43.  Recover_platform:  
  44.     if (suspend_ops->recover)  
  45.         suspend_ops->recover();  
  46.     goto Resume_devices;  
  47. }  


当外设进入休眠后,进入suspend_enter(),在suspend_enter()中suspend_ops->prepare()被调用,suspend_ops是板级的PM操作,依赖于具体的平台,在我samsung4412系统中,其注册在linux_source/arch/arm/plat-samsung/pm.c中,定义了suspend_ops->enter()函数。

[cpp] view plaincopy
  1. linux_source/arch/arm/plat-samsung/pm.c  
  2. static const struct platform_suspend_ops s3c_pm_ops = {  
  3.     .enter      = s3c_pm_enter,  
  4.     .prepare    = s3c_pm_prepare,  
  5.     .finish     = s3c_pm_finish,  
  6.     .valid      = suspend_valid_only_mem,  
  7. };  


接下来,首先关闭IRQ,关闭不用的CPU,休眠所有的系统设备和总线。最后调用 suspend_pos->enter() 来使CPU进入省电状态。这时候,整个休眠过程完成,代码的执行也就停在这里了。

[cpp] view plaincopy
  1. linux_source/kernel/power/suspend.c  
  2. /** 
  3.  *  suspend_enter - enter the desired system sleep state. 
  4.  *  @state:     state to enter 
  5.  * 
  6.  *  This function should be called after devices have been suspended. 
  7.  */  
  8. static int suspend_enter(suspend_state_t state)  
  9. {  
  10.     int error;  
  11.   
  12.     if (suspend_ops->prepare) {  
  13.         error = suspend_ops->prepare();  
  14.         if (error)  
  15.             goto Platform_finish;  
  16.     }  
  17.   
  18.     <span style="color:#3366ff;"><strong>error = dpm_suspend_noirq(PMSG_SUSPEND);</strong></span>  
  19.     if (error) {  
  20.         printk(KERN_ERR "PM: Some devices failed to power down\n");  
  21.         goto Platform_finish;  
  22.     }  
  23.   
  24.     if (suspend_ops->prepare_late) {  
  25.         error = suspend_ops->prepare_late();  
  26.         if (error)  
  27.             goto Platform_wake;  
  28.     }  
  29.   
  30.     if (suspend_test(TEST_PLATFORM))  
  31.         goto Platform_wake;  
  32.   
  33.     <span style="color:#3366ff;"><strong>error = disable_nonboot_cpus();</strong>  
  34. </span> if (error || suspend_test(TEST_CPUS))  
  35.         goto Enable_cpus;  
  36.   
  37.     arch_suspend_disable_irqs();  
  38.     BUG_ON(!irqs_disabled());  
  39.   
  40.     error = syscore_suspend();  
  41.     if (!error) {  
  42.         if (!(suspend_test(TEST_CORE) || pm_wakeup_pending())) {  
  43.             <strong><span style="color:#3366ff;">error = suspend_ops->enter(state);</span></strong>  
  44.             events_check_enabled = false;  
  45.         }  
  46.         <span style="color:#3366ff;"><strong>syscore_resume();</strong></span>  
  47.     }  
  48.   
  49.     arch_suspend_enable_irqs();  
  50.     BUG_ON(irqs_disabled());  
  51.   
  52.  Enable_cpus:  
  53.     enable_nonboot_cpus();  
  54.   
  55.  Platform_wake:  
  56.     if (suspend_ops->wake)  
  57.         suspend_ops->wake();  
  58.   
  59.     <span style="color:#3366ff;"><strong>dpm_resume_noirq(PMSG_RESUME);</strong>  
  60. </span>  
  61.  Platform_finish:  
  62.     if (suspend_ops->finish)  
  63.         <span style="color:#3366ff;"><strong>suspend_ops->finish();</strong></span>  
  64.   
  65.     return error;  
  66. }  


在suspend_pos->enter()所对应的函数中,代码最终停止在s3c_pm_arch_stop_clocks();处。

[cpp] view plaincopy
  1. linux_source/arch/arm/plat-samsung/pm.c  
  2. /* s3c_pm_enter  
  3.  * 
  4.  * central control for sleep/resume process 
  5. */  
  6. static int s3c_pm_enter(suspend_state_t state)  
  7. {  
  8.     .....  
  9.     /* save all necessary core registers not covered by the drivers */  
  10.     s3c_pm_save_gpios();  
  11.     s3c_pm_saved_gpios();  
  12.     s3c_pm_save_uarts();  
  13.     s3c_pm_save_core();  
  14.     .....  
  15.   
  16.     /* send the cpu to sleep... */  
  17.     <span style="color:#3366ff;"><strong>s3c_pm_arch_stop_clocks();</strong></span>  
  18.   
  19.     /* s3c_cpu_save will also act as our return point from when 
  20.      * we resume as it saves its own register state and restores it 
  21.      * during the resume.  */  
  22.     s3c_cpu_save(0, PLAT_PHYS_OFFSET - PAGE_OFFSET);  
  23.   
  24.     /* restore the cpu state using the kernel's cpu init code. */  
  25.     <span style="color:#3366ff;"><strong>cpu_init();</strong></span>  
  26.   
  27.     s3c_pm_restore_core();  
  28.     s3c_pm_restore_uarts();  
  29.     s3c_pm_restore_gpios();  
  30.     s3c_pm_restored_gpios();  
  31.     .....  
  32.   
  33.     return 0;  
  34. }  


Android 唤醒过程如下:
如果在休眠中系统被中断或者其他事件唤醒,接下来的代码就从suspend完成的地方开始执行,即pm.c中的s3c_pm_enter()中的cpu_init(),然后执行suspend_enter()的syscore_resume()函数,唤醒系统设备和总线,使能系统中断。然后回到suspend_devices_and_enter()函数中,dpm_resume_end(PMSG_RESUME)发出resume消息唤醒每个设备,使能终端。当suspend_devices_and_enter()执行完成后,系统外设已经唤醒,但进程依然是冻结的状态,返回到enter_state函数中,调用suspend_finish()函数。在suspend_finish()函数中,解冻进程和任务,使能用户空间helper进程,广播一个系统从suspend状态退出的notify,唤醒终端。

[cpp] view plaincopy
  1. linux_source/kernel/power/suspend.c  
  2. /** 
  3.  *  suspend_finish - Do final work before exiting suspend sequence. 
  4.  * 
  5.  *  Call platform code to clean up, restart processes, and free the 
  6.  *  console that we've allocated. This is not called for suspend-to-disk. 
  7.  */  
  8. static void suspend_finish(void)  
  9. {  
  10.     suspend_thaw_processes();  
  11.     usermodehelper_enable();  
  12.     <span style="color:#3366ff;"><strong>pm_notifier_call_chain(PM_POST_SUSPEND); //重要,唤醒系统和RIL等进程</strong>  
  13. </span> pm_restore_console();  
  14. }  

当所有的唤醒已经结束以后,用户进程都已经开始运行了,但没点亮屏幕,唤醒通常会是以下的几种原因: 
如果是来电,那么Modem会通过中断脚唤醒AP,rild是一个守护进程,在醒来后不断从modem usb数据端口polling数据,当发现是incoming call或者incoming sms事件后就通知WindowManager有来电响应,这样就会远程调用PowerManagerService来写”on”到 /sys/power/state 来调用late resume(),执行点亮屏幕等操作。
用户按键事件会送到WindowManager中,WindowManager会处理这些按键事件,按键分为几种情况,如果按键不是唤醒键,那么WindowManager会主动放弃wakeLock来使系统进入再次休眠;如果按键是唤醒键,那么WindowManger就会调用PowerManagerService中的接口来执行late Resume。  当”on”被写入到/sys/power/state之后,同early_suspend过程,request_suspend_state()被调用,只是执行的工作队列变为late_resume_work。在late_resume函数中,唤醒调用了early_suspend的设备。

0 0
原创粉丝点击