Android休眠唤醒2

      http://blog.csdn.net/zhaoxiaoqiang10_/article/details/24408839

    标准linux休眠过程:

  • power management notifiers are executed with PM_SUSPEND_PREPARE 
  • tasks are frozen
  • target system sleep state is announced to the platform-handling code
  • devices are suspended 
  • platform-specific global suspend preparation methods are executed 
  • non-boot CPUs are taken off-line
  • interrupts are disabled on the remaining (main) CPU 
  • late suspend of devices is carried out (一般有一些BUS driver的动作进行)‏
  • platform-specific global methods are invoked to put the system to sleep 

  • 标准linux唤醒过程:

  • the main CPU is switched to the appropriate mode, if necessary
  • early resume of devices is carried out (一般有)
  • platform-specific global resume preparation methods are invoked
  • devices are woken up
  • tasks are thawed 
  • power management notifiers are executed with PM_POST_SUSPEND 
用户可以通过sys文件系统控制系统进入休眠一些BUS driver的动作进行)‏
  • interrupts are enabled on the main CPU 
  • non-boot CPUs are enabled :
  • 查看系统支持的休眠方式:
#cat /sys/power/state 
常见有 standby(suspend to RAM)、 mem(suspend to RAM)和 disk(suspend to disk),只是standby耗电更多,返回到正常工作状态的时间更短。
#echo mem > /sys/power/state 让系统进入休眠。
#echo on > /sys/power/state 使系统唤醒。

Android休眠与唤醒

           android在传统的linux内核电源管理设计的基础上,结合手机设计的实际需求而进化出的一套电源管理系统,其核心内容有:wakelock 、early_suspend与late_resume。
            wakelock在Android的电源管理系统中扮演一个核心的角色。 wakelock是一种锁的机制, 只要有人拿着这个锁,系统就无法进入休眠,可以被用户态程序和内核获得。这个 可以是有超时的或者是没有超时的, 超时的锁会在时间过去以后自动解锁。如果没有 了或者 超时了,内核就会启动休眠的那套机制来进入休眠。
             当系统启动完毕后,自己去加一把名为“main“的 ,而当系统睡眠时则会先去释放这把“main”锁,在android中,在 early_suspend的最后一步会去释放“ main”锁(wake_unlock: main)。释放完后则会去检查是否还有其他存在的锁,如果没有则直接进入睡眠过程。它的 缺点是,如果有某一应用获锁而不释放或者因一直在执行某种操作而没时间来释放的话,则会导致系统一直进入不了睡眠状态,功耗过大。
             early_suspend:先与linux内核的睡眠过程被调用。一般在手机系统的设计中对背光的操作等采用此类方法,因为背光需要的能耗过大。当然此操作与late_resume是配套使用的。一些在内核中要预先进行处理的事件可以先注册上early_suspend函数,当系统要进入睡眠之前会首先调用这些注册的函数。

本文中,linux kernel版本为 linux-3.10,android版本为 android 4.4,与android 休眠唤醒主要相关的文件主要有:
kernel/power/main.c
kernel/power/earlysuspend.c
kernel/power/wakelock_android.c 
kernel/power/userwakelock.c 
driver/base/power/main.c
arch/xxx/mach-xxx/pm.c或linux_source/arch/xxx/plat-xxx/pm.c

Android 休眠过程如下:

1 suspend state

       Suspend/Resume是Linux系统电源管理的一个重要功能, suspend可以在系统不使用的情况下进入低功耗活休眠状态下从而节省系统电源。Linux系统的suspend有四种状态,对于不同的体系结构或者电源管理接口来说,状态的含义不一定完全相同,但是不会有太大的差别。下面的是ACPI电源接口的含义及其对应的Sleep State。
On (on)                                                        S0 - Working
Standby (standby)                                       S1 - CPU and RAM are powered but not executed
Suspend to RAM (mem)                               S3 - RAM is powered and the running content is saved to RAM
Suspend to Disk,Hibernation (disk)           S4 - All contect is saved to Disk and power down

2 suspend用户空间接口

        Linux系统的电源管理Suspend框架跟Linux系统的驱动模型(Linux Driver Model) 是相关的,也是基于Linux的驱动模型来实现的。
        Linux的Suspend系统分 两部分,一部分是平台无关的 核心层
                                                           另一个是平台相关的 平台层。操作接口都在平台无关的核心层里了。
        根据Linux系统驱动模型,device结构描述了一个设备,device_driver是设备的驱动,而class、type和bus分别描述了设备所属的类别、类型和总线。而设备的电源管理也根据此模型分为class级的、type级的、bus级的和驱动级的。如果一个设备的class或者bus确切的知道如何管理一个设备的电源的时候,驱动级别的suspend/resume就可以为空了。这极大的提高了电源管理的高效性和灵活性。
Linxux系统的suspend核心代码位于kernel/power目录下,主要的文件是main.c 和 suspend.c。平台相关的代码一般位于平台(arch)的电源管理模块里。
kernel/power/main.c

power_attr(state);

宏展开,等价于:

  1. static struct kobj_attribute state_attr = {   
  2.     .attr   = {               
  3.         .name = “state”,      
  4.         .mode = 0644,             
  5.     },                    
  6.     .show   = state_show,             
  7.     .store  = state_store,        
  8. }  
创建细节同power_attr(wake_lock);
至此,在sysfs中的应用接口为/sys/power/state创建。

3 suspend流程

3.1 state_store()
当用户读写/sys/power/state时,state_store()函数会被调用。

  1. static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,  
  2.                const char *buf, size_t n)  
  3. {  
  4.     suspend_state_t state;  
  5.     int error;  
  6.   
  7.     error = pm_autosleep_lock();  
  8.     if (error)  
  9.         return error;  
  10.     if (pm_autosleep_state() > PM_SUSPEND_ON) {  
  11.         error = -EBUSY;  
  12.         goto out;  
  13.     }  
  14. /*decode suspend状态, 
  15. #define PM_SUSPEND_ON       ((__force suspend_state_t) 0) 
  16. #define PM_SUSPEND_FREEZE   ((__force suspend_state_t) 1) 
  17. #define PM_SUSPEND_STANDBY  ((__force suspend_state_t) 2) 
  18. #define PM_SUSPEND_MEM      ((__force suspend_state_t) 3) 
  19. #define PM_SUSPEND_MIN      PM_SUSPEND_FREEZE 
  20. #define PM_SUSPEND_MAX      ((__force suspend_state_t) 4) 
  21. */  
  22.     state = decode_state(buf, n);  
  23.     if (state < PM_SUSPEND_MAX)  
  24.     {  
  25. #ifdef CONFIG_EARLYSUSPEND  
  26. //android early_suspud由宏控制  
  27. //if 唤醒或者可支持的睡眠(mem)  
  28.         if (state == PM_SUSPEND_ON || valid_state(state)) {  
  29.             error = 0;  
  30.             request_suspend_state(state);  
  31.         }  
  32. #else  
  33. //linux标准的suspend流程  
  34.         error = pm_suspend(state);  
  35. #endif  
  36.     }  
  37.     else if (state == PM_SUSPEND_MAX)  
  38.         error = hibernate();  
  39.     else  
  40.         error = -EINVAL;   
  41.  out:  
  42.     pm_autosleep_unlock();  
  43.     return error ? error : n;  
  44. }  


  1. bool valid_state(suspend_state_t state)  
  2. {  
  3.     if (state == PM_SUSPEND_FREEZE) {  
  4. #ifdef CONFIG_PM_DEBUG  
  5.         if (pm_test_level != TEST_NONE &&  
  6.             pm_test_level != TEST_FREEZER &&  
  7.             pm_test_level != TEST_DEVICES &&  
  8.             pm_test_level != TEST_PLATFORM) {  
  9.             printk(KERN_WARNING "Unsupported pm_test mode for "  
  10.                     "freeze state, please choose "  
  11.                     "none/freezer/devices/platform.\n");  
  12.             return false;  
  13.         }  
  14. #endif  
  15.             return true;  
  16.     }  
  17.     /* 
  18.      * PM_SUSPEND_STANDBY and PM_SUSPEND_MEMORY states need lowlevel 
  19.      * support and need to be valid to the lowlevel 
  20.      * implementation, no valid callback implies that none are valid. 
  21.      */  
  22.     return suspend_ops && suspend_ops->valid && suspend_ops->valid(state);  
  23. }  

  1. static const struct platform_suspend_ops *suspend_ops;  
  2. void suspend_set_ops(const struct platform_suspend_ops *ops)  
  3. {  
  4.     lock_system_sleep();  
  5.     suspend_ops = ops;  
  6.     unlock_system_sleep();  
  7. }  

在板级相关的文件中设置:
/arch/arm/plat-samsung/pm.c

  1. static const struct platform_suspend_ops s3c_pm_ops = {  
  2.     .enter      = s3c_pm_enter,  
  3.     .prepare    = s3c_pm_prepare,  
  4.     .finish     = s3c_pm_finish,  
  5.     .valid      = suspend_valid_only_mem,  
  6. };  

  1. int suspend_valid_only_mem(suspend_state_t state)  
  2. {  
  3.     return state == PM_SUSPEND_MEM;  
  4. }  

只支持mem。

3.2 request_suspend_state()
on(唤醒)和mem(睡眠)。

  1. void request_suspend_state(suspend_state_t new_state)  
  2. {  
  3.     unsigned long irqflags;  
  4.     int old_sleep;  
  5.     spin_lock_irqsave(&state_lock, irqflags);  
  6. //static int state;全局变量  
  7.     old_sleep = state & SUSPEND_REQUESTED;  
  8.     if (debug_mask & DEBUG_USER_STATE) {  
  9.         struct timespec ts;  
  10.         struct rtc_time tm;  
  11.         getnstimeofday(&ts);  
  12.         rtc_time_to_tm(ts.tv_sec, &tm);  
  13.         pr_info("request_suspend_state: %s (%d->%d) at %lld "  
  14.             "(%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)\n",  
  15.             new_state != PM_SUSPEND_ON ? "sleep" : "wakeup",  
  16.             requested_suspend_state, new_state,  
  17.             ktime_to_ns(ktime_get()),  
  18.             tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,  
  19.             tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec);  
  20.     }  
  21.     printk("%s,%d,old_sleep=%d,new_state=%d\n",__func__,__LINE__,old_sleep,new_state);  
  22. /* 
  23. [ 1463.819671@0] request_suspend_state: sleep (0->3) at 1463745589000 (2015-02-15 00:05:26.810753000 UTC) 
  24. [ 1463.823352@0] request_suspend_state,169,old_sleep=0,new_state=3 
  25. state的取值: 
  26. enum { 
  27.     SUSPEND_REQUESTED = 0x1, 
  28.     SUSPENDED = 0x2, 
  29.     SUSPEND_REQUESTED_AND_SUSPENDED = SUSPEND_REQUESTED | SUSPENDED, 
  30. }; 
  31. */  
  32.     if (!old_sleep && new_state != PM_SUSPEND_ON) {  
  33. //suspend  
  34.         state |= SUSPEND_REQUESTED;  
  35.         queue_work(suspend_work_queue, &early_suspend_work);  
  36.     } else if (old_sleep && new_state == PM_SUSPEND_ON) {  
  37. //resum  
  38.         state &= ~SUSPEND_REQUESTED;  
  39.         wake_lock(&main_wake_lock);  
  40.         queue_work(suspend_work_queue, &late_resume_work);  
  41.     }  
  42.     requested_suspend_state = new_state;  
  43.     spin_unlock_irqrestore(&state_lock, irqflags);  
  44. }  

static DECLARE_WORK(early_suspend_work, early_suspend);//工作项
static DECLARE_WORK(late_resume_work, late_resume);
/kernel/power/wakelock_android.c
struct workqueue_struct *suspend_work_queue;//工作队列
wakelocks_init()->
suspend_work_queue = create_singlethread_workqueue("suspend");

3.3 early_suspend()
kernel/power/earlysuspend.c

  1. static void early_suspend(struct work_struct *work)  
  2. {  
  3.     struct early_suspend *pos;  
  4.     unsigned long irqflags;  
  5.     int abort = 0;  
  6.   
  7.     mutex_lock(&early_suspend_lock);  
  8.     spin_lock_irqsave(&state_lock, irqflags);  
  9. //是否还是suspend状态,不是abort  
  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. //按照level顺序执行early_suspend_handlers上的early suspend  
  26.     list_for_each_entry(pos, &early_suspend_handlers, link) {  
  27.         if (pos->suspend != NULL)  
  28.         {  
  29.             printk("%pf\n",pos->suspend);  
  30.             pos->suspend(pos);  
  31.         }  
  32.     }  
  33.     mutex_unlock(&early_suspend_lock);  
  34.   
  35.     if (debug_mask & DEBUG_SUSPEND)  
  36.         pr_info("early_suspend: sync\n");  
  37. //同步文件系统  
  38.     sys_sync();  
  39. abort:  
  40.     spin_lock_irqsave(&state_lock, irqflags);  
  41.     if (state == SUSPEND_REQUESTED_AND_SUSPENDED)  
  42. //当系统中所有的wake_lock都被释放之后,系统就会进入真正的kernel的睡眠状态  
  43.         wake_unlock(&main_wake_lock);  
  44.     spin_unlock_irqrestore(&state_lock, irqflags);  
  45. }  

3.4 wake_unlock()
  1. void wake_unlock(struct wake_lock *lock)  
  2. {  
  3.     int type;  
  4.     unsigned long irqflags;  
  5.     spin_lock_irqsave(&list_lock, irqflags);  
  6.     type = lock->flags & WAKE_LOCK_TYPE_MASK;  
  7. #ifdef CONFIG_WAKELOCK_STAT  
  8.     wake_unlock_stat_locked(lock, 0);  
  9. #endif  
  10.     if (debug_mask & DEBUG_WAKE_LOCK)  
  11.         pr_info("wake_unlock: %s\n", lock->name);  
  12.     lock->flags &= ~(WAKE_LOCK_ACTIVE | WAKE_LOCK_AUTO_EXPIRE);  
  13.     list_del(&lock->link);  
  14.     list_add(&lock->link, &inactive_locks);  
  15.     if (type == WAKE_LOCK_SUSPEND) {  
  16.         long has_lock = has_wake_lock_locked(type);  
  17.         if (has_lock > 0) {  
  18.             if (debug_mask & DEBUG_EXPIRE)  
  19.                 pr_info("wake_unlock: %s, start expire timer, "  
  20.                     "%ld\n", lock->name, has_lock);  
  21. //如果active_wake_locks[0]上flags为WAKE_LOCK_AUTO_EXPIRE的lock中expires没有到期  
  22.             mod_timer(&expire_timer, jiffies + has_lock);  
  23.         } else {  
  24. //wake_lock()时,也会走一部分这样的流程,也会mod_timer(&expire_timer, jiffies + expire_in)  
  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. //active_wake_locks[0]上flags为WAKE_LOCK_AUTO_EXPIRE的所有lock的expires已经到期,会将suspend_work加入工作队列  
  30.             if (has_lock == 0)  
  31.                 queue_work(suspend_work_queue, &suspend_work);  
  32. //has_lock==-1,说明active_wake_locks[0]上有flags不为WAKE_LOCK_AUTO_EXPIRE的lock,而且还没有unlock  
  33.         }  
  34.         if (lock == &main_wake_lock) {  
  35.             if (debug_mask & DEBUG_SUSPEND)  
  36.                 print_active_locks(WAKE_LOCK_SUSPEND);  
  37. #ifdef CONFIG_WAKELOCK_STAT  
  38.             update_sleep_wait_stats_locked(0);  
  39. #endif  
  40.         }  
  41.     }  
  42.     spin_unlock_irqrestore(&list_lock, irqflags);  
  43. }  

  1. static DEFINE_TIMER(expire_timer, expire_wake_locks, 0, 0);  

  1. static void expire_wake_locks(unsigned long data)  
  2. {  
  3.     long has_lock;  
  4.     unsigned long irqflags;  
  5.     if (debug_mask & DEBUG_EXPIRE)  
  6.         pr_info("expire_wake_locks: start\n");  
  7.     spin_lock_irqsave(&list_lock, irqflags);  
  8.     if (debug_mask & DEBUG_SUSPEND)  
  9.         print_active_locks(WAKE_LOCK_SUSPEND);  
  10.     has_lock = has_wake_lock_locked(WAKE_LOCK_SUSPEND);  
  11.     if (debug_mask & DEBUG_EXPIRE)  
  12.         pr_info("expire_wake_locks: done, has_lock %ld\n", has_lock);  
  13.     if (has_lock == 0)  
  14.         queue_work(suspend_work_queue, &suspend_work);  
  15.     spin_unlock_irqrestore(&list_lock, irqflags);  
  16. }  

expire_timer的到期函数, queue_work(suspend_work_queue, &suspend_work);     static DECLARE_WORK(suspend_work, suspend);
wakelock有加锁和解锁2种操作,加锁有2种,一是永久加锁( wake_lock),必须手动的解锁;另一种超时锁( wake_lock_timeout),这种锁在过去指定时间后,会自动解锁。
对于 wake_lock(),timeout = has_timeout = 0;直接加锁后,然后退出;而对于wake_lock_timeout(),在经过timeout时间后,才加锁。再判断当前持有wakelock时,启动另一个定时器,在expire_timer的回调函数中再次判断是否持有wakelock。
在wakelock中,有2个地方可以让系统从early_suspend进入suspend状态。分别是:
  • 在wake_unlock中,解锁之后,若没有其他的wakelock,则进入suspend。
  • 在超时锁的定时器超时后,定时器的回调函数,会判断有没有其他的wakelock,若没有,则进入suspend。
3.5 suspend()
  1. static void suspend(struct work_struct *work)  
  2. {  
  3.     int ret;  
  4.     int entry_event_num;  
  5.     struct timespec ts_entry, ts_exit;  
  6. //如果有不是自动到期的lock还没有unlock或者自动到期的lock还没有到期  
  7.     if (has_wake_lock(WAKE_LOCK_SUSPEND)) {  
  8.         if (debug_mask & DEBUG_SUSPEND)  
  9.             pr_info("suspend: abort suspend\n");  
  10.         return;  
  11.     }  
  12.   
  13.     entry_event_num = current_event_num;  
  14.     if (debug_mask & DEBUG_SUSPEND)  
  15.         pr_info("suspend: sys_sync...");  
  16.     sys_sync();  
  17.     if (debug_mask & DEBUG_SUSPEND)  
  18.         pr_info("done.\n");  
  19.     if (debug_mask & DEBUG_SUSPEND)  
  20.         pr_info("suspend: enter suspend\n");  
  21.     getnstimeofday(&ts_entry);  
  22.     ret = pm_suspend(requested_suspend_state);  
  23.     getnstimeofday(&ts_exit);  
  24.   
  25.     if (debug_mask & DEBUG_EXIT_SUSPEND) {  
  26.         struct rtc_time tm;  
  27.         rtc_time_to_tm(ts_exit.tv_sec, &tm);  
  28.         pr_info("suspend: exit suspend, ret = %d "  
  29.             "(%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)\n", ret,  
  30.             tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,  
  31.             tm.tm_hour, tm.tm_min, tm.tm_sec, ts_exit.tv_nsec);  
  32.     }  
  33.   
  34.     if (ts_exit.tv_sec - ts_entry.tv_sec <= 1) {  
  35.         ++suspend_short_count;  
  36.   
  37.         if (suspend_short_count == SUSPEND_BACKOFF_THRESHOLD) {  
  38.             suspend_backoff();  
  39.             suspend_short_count = 0;  
  40.         }  
  41.     } else {  
  42.         suspend_short_count = 0;  
  43.     }  
  44.   
  45.     if (current_event_num == entry_event_num) {  
  46.         if (debug_mask & DEBUG_SUSPEND)  
  47.             pr_info("suspend: pm_suspend returned with no event\n");  
  48.           
  49.     }  
  50.     wake_lock_timeout(&unknown_wakeup,2* HZ);  
  51. }  

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这两个队列的先后顺序了。


3.6 pm_suspend()
  1. int pm_suspend(suspend_state_t state)  
  2. {  
  3.     int error;  
  4.   
  5.     if (state <= PM_SUSPEND_ON || state >= PM_SUSPEND_MAX)  
  6.         return -EINVAL;  
  7.   
  8.     pm_suspend_marker("entry");  
  9.     error = enter_state(state);  
  10.     if (error) {  
  11.         suspend_stats.fail++;  
  12.         dpm_save_failed_errno(error);  
  13.     } else {  
  14.         suspend_stats.success++;  
  15.     }  
  16.     pm_suspend_marker("exit");  
  17.     return error;  
  18. }  

  1. static int enter_state(suspend_state_t state)  
  2. {  
  3.     int error;  
  4.   
  5.     if (!valid_state(state))  
  6.         return -ENODEV;  
  7.   
  8.     if (!mutex_trylock(&pm_mutex))  
  9.         return -EBUSY;  
  10.   
  11.     if (state == PM_SUSPEND_FREEZE)  
  12.         freeze_begin();  
  13.   
  14.     printk(KERN_INFO "PM: Syncing filesystems ... ");  
  15.     sys_sync();  
  16.     printk("done.\n");  
  17.   
  18.     pr_debug("PM: Preparing system for %s sleep\n", pm_states[state]);  
  19.     error = suspend_prepare(state);  
  20.     if (error)  
  21.         goto Unlock;  
  22.   
  23.     if (suspend_test(TEST_FREEZER))  
  24.         goto Finish;  
  25.   
  26.     pr_debug("PM: Entering %s sleep\n", pm_states[state]);  
  27.     pm_restrict_gfp_mask();  
  28.     error = suspend_devices_and_enter(state);  
  29.     pm_restore_gfp_mask();  
  30.   
  31.  Finish:  
  32.     pr_debug("PM: Finishing wakeup.\n");  
  33.     suspend_finish();  
  34.  Unlock:  
  35.     mutex_unlock(&pm_mutex);  
  36.     return error;  
  37. }  

uspend()调用了pm_suspend(),通过判断当前的状态,选择enter_state(),在enter_state()中,经过了suspend_prepare(),suspend_test()和suspend_device_and_enter(),在suspend_device_and_enter()中调用了device_suspend()来保存状态和结束系统的设备,到了dpm_suspend()中结束所有的device

3.6.1 suspend_prepare()

  1. static int suspend_prepare(suspend_state_t state)  
  2. {  
  3.     int error;  
  4. //平台相关  
  5.     if (need_suspend_ops(state) && (!suspend_ops || !suspend_ops->enter))  
  6.         return -EPERM;  
  7.   
  8.     pm_prepare_console();  
  9.   
  10.     error = pm_notifier_call_chain(PM_SUSPEND_PREPARE);  
  11.     if (error)  
  12.         goto Finish;  
  13. //冻结进程  
  14.     error = suspend_freeze_processes();  
  15.     if (!error)  
  16.         return 0;  
  17.   
  18.     suspend_stats.failed_freeze++;  
  19.     dpm_save_failed_step(SUSPEND_FREEZE);  
  20.  Finish:  
  21.     pm_notifier_call_chain(PM_POST_SUSPEND);  
  22.     pm_restore_console();  
  23.     return error;  
  24. }  


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()
  1. int suspend_devices_and_enter(suspend_state_t state)  
  2. {  
  3.     int error;  
  4.     bool wakeup = false;  
  5.   
  6.     if (need_suspend_ops(state) && !suspend_ops)  
  7.         return -ENOSYS;  
  8.   
  9.     trace_machine_suspend(state);  
  10. //没定义begin()略过  
  11.     if (need_suspend_ops(state) && suspend_ops->begin) {  
  12.         error = suspend_ops->begin(state);  
  13.         if (error)  
  14.             goto Close;  
  15.     }  
  16.     suspend_console();  
  17.     ftrace_stop();  
  18.     suspend_test_start();  
  19.     error = dpm_suspend_start(PMSG_SUSPEND);  
  20.     if (error) {  
  21.         printk(KERN_ERR "PM: Some devices failed to suspend\n");  
  22.         goto Recover_platform;  
  23.     }  
  24.     suspend_test_finish("suspend devices");  
  25.     if (suspend_test(TEST_DEVICES))  
  26.         goto Recover_platform;  
  27.   
  28.     do {  
  29.         error = suspend_enter(state, &wakeup);  
  30.     } while (!error && !wakeup && need_suspend_ops(state)  
  31.         && suspend_ops->suspend_again && suspend_ops->suspend_again());  
  32.   
  33.  Resume_devices:  
  34.     suspend_test_start();  
  35.     dpm_resume_end(PMSG_RESUME);  
  36.     suspend_test_finish("resume devices");  
  37.     ftrace_start();  
  38.     resume_console();  
  39.  Close:  
  40.     if (need_suspend_ops(state) && suspend_ops->end)  
  41.         suspend_ops->end();  
  42.     trace_machine_suspend(PWR_EVENT_EXIT);  
  43.     return error;  
  44.   
  45.  Recover_platform:  
  46.     if (need_suspend_ops(state) && suspend_ops->recover)  
  47.         suspend_ops->recover();  
  48.     goto Resume_devices;  
  49. }  

  1. int suspend_devices_and_enter(suspend_state_t state)  
  2. {  
  3.     int error;  
  4.     bool wakeup = false;  
  5.   
  6.     if (need_suspend_ops(state) && !suspend_ops)  
  7.         return -ENOSYS;  
  8.   
  9.     trace_machine_suspend(state);  
  10.     if (need_suspend_ops(state) && suspend_ops->begin) {  
  11.         error = suspend_ops->begin(state);  
  12.         if (error)  
  13.             goto Close;  
  14.     }  
  15.     suspend_console();  
  16.     ftrace_stop();  
  17.     suspend_test_start();  
  18. //device suspend  
  19.     error = dpm_suspend_start(PMSG_SUSPEND);  
  20.     if (error) {  
  21.         printk(KERN_ERR "PM: Some devices failed to suspend\n");  
  22.         goto Recover_platform;  
  23.     }  
  24.     suspend_test_finish("suspend devices");  
  25.     if (suspend_test(TEST_DEVICES))  
  26.         goto Recover_platform;  
  27. //停在这里  
  28.     do {  
  29.         error = suspend_enter(state, &wakeup);  
  30.     } while (!error && !wakeup && need_suspend_ops(state)  
  31.         && suspend_ops->suspend_again && suspend_ops->suspend_again());  
  32.   
  33.  Resume_devices:  
  34.     suspend_test_start();  
  35.     dpm_resume_end(PMSG_RESUME);  
  36.     suspend_test_finish("resume devices");  
  37.     ftrace_start();  
  38.     resume_console();  
  39.  Close:  
  40.     if (need_suspend_ops(state) && suspend_ops->end)  
  41.         suspend_ops->end();  
  42.     trace_machine_suspend(PWR_EVENT_EXIT);  
  43.     return error;  
  44.   
  45.  Recover_platform:  
  46.     if (need_suspend_ops(state) && suspend_ops->recover)  
  47.         suspend_ops->recover();  
  48.     goto Resume_devices;  
  49. }  
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()
  1. int dpm_suspend_start(pm_message_t state)  
  2. {  
  3.     int error;  
  4.     error = dpm_prepare(state);  
  5.     if (error) {  
  6.         suspend_stats.failed_prepare++;  
  7.         dpm_save_failed_step(SUSPEND_PREPARE);  
  8.     } else  
  9.         error = dpm_suspend(state);  
  10.     return error;  
  11. }  

  1. int dpm_prepare(pm_message_t state)  
  2. {  
  3.     int error = 0;  
  4.   
  5.     might_sleep();  
  6.   
  7.     mutex_lock(&dpm_list_mtx);  
  8.     while (!list_empty(&dpm_list)) {  
  9.         struct device *dev = to_device(dpm_list.next);  
  10.   
  11.         get_device(dev);  
  12.         mutex_unlock(&dpm_list_mtx);  
  13.   
  14. //这里会调用 dev->XXXX->prepare(),callback()的选择顺序同dpm_suspend()  
  15.         error = device_prepare(dev, state);  
  16.   
  17.         mutex_lock(&dpm_list_mtx);  
  18.         if (error) {  
  19.             if (error == -EAGAIN) {  
  20.                 put_device(dev);  
  21.                 error = 0;  
  22.                 continue;  
  23.             }  
  24.             printk(KERN_INFO "PM: Device %s not prepared "  
  25.                 "for power transition: code %d\n",  
  26.                 dev_name(dev), error);  
  27.             put_device(dev);  
  28.             break;  
  29.         }  
  30.         dev->power.is_prepared = true;  
  31. //dpm_list转移到dpm_prepared_list,添加到结尾,两个list顺序一致  
  32.         if (!list_empty(&dev->power.entry))  
  33.             list_move_tail(&dev->power.entry, &dpm_prepared_list);  
  34.         put_device(dev);  
  35.     }  
  36.     mutex_unlock(&dpm_list_mtx);  
  37.     return error;  
  38. }  

  1. int dpm_suspend(pm_message_t state)  
  2. {  
  3.     ktime_t starttime = ktime_get();  
  4.     int error = 0;  
  5.   
  6.     might_sleep();  
  7.   
  8.     mutex_lock(&dpm_list_mtx);  
  9.     pm_transition = state;  
  10.     async_error = 0;  
  11.     while (!list_empty(&dpm_prepared_list)) {  
  12.         struct device *dev = to_device(dpm_prepared_list.prev);  
  13.   
  14.         get_device(dev);  
  15.         mutex_unlock(&dpm_list_mtx);  
  16. //device suspend  
  17.         error = device_suspend(dev);  
  18.   
  19.         mutex_lock(&dpm_list_mtx);  
  20.         if (error) {  
  21.             pm_dev_err(dev, state, "", error);  
  22.             dpm_save_failed_dev(dev_name(dev));  
  23.             put_device(dev);  
  24.             break;  
  25.         }  
  26.         if (!list_empty(&dev->power.entry))  
  27. //dpm_prepared_list转移到dpm_suspended_list,添加到list头,两个list顺序相反  
  28.             list_move(&dev->power.entry, &dpm_suspended_list);  
  29.         put_device(dev);  
  30.         if (async_error)  
  31.             break;  
  32.     }  
  33.     mutex_unlock(&dpm_list_mtx);  
  34.     async_synchronize_full();  
  35.     if (!error)  
  36.         error = async_error;  
  37.     if (error) {  
  38.         suspend_stats.failed_suspend++;  
  39.         dpm_save_failed_step(SUSPEND_SUSPEND);  
  40.     } else  
  41.         dpm_show_time(starttime, state, NULL);  
  42.     return error;  
  43. }  
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

例如:[ 271.825139@0] 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);

  1. static struct device_type input_dev_type = {  
  2.     .groups     = input_dev_attr_groups,  
  3.     .release    = input_dev_release,  
  4.     .uevent     = input_dev_uevent,  
  5. #ifdef CONFIG_PM  
  6.     .pm     = &input_dev_pm_ops,  
  7. #endif  
  8. };  

  1. static const struct dev_pm_ops input_dev_pm_ops = {  
  2.     .suspend    = input_dev_suspend,  
  3.     .resume     = input_dev_resume,  
  4.     .poweroff   = input_dev_suspend,  
  5.     .restore    = input_dev_resume,  
  6. };  

  1. static int input_dev_suspend(struct device *dev)  
  2. {  
  3.     struct input_dev *input_dev = to_input_dev(dev);  
  4.   
  5.     mutex_lock(&input_dev->mutex);  
  6.   
  7.     if (input_dev->users)  
  8.         input_dev_toggle(input_dev, false);  
  9.   
  10.     mutex_unlock(&input_dev->mutex);  
  11.   
  12.     return 0;  
  13. }  


再例如:[ 271.829858@0] suspend 1-0040+ @ 865, parent: i2c-1

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));

  1. static struct device_type i2c_client_type = {  
  2.     .groups     = i2c_dev_attr_groups,  
  3.     .uevent     = i2c_device_uevent,  
  4.     .release    = i2c_client_dev_release,  
  5. };  

没有定义dev_pm_ops,继续找i2c_bus_type。
  1. struct bus_type i2c_bus_type = {  
  2.     .name       = "i2c",  
  3.     .match      = i2c_device_match,  
  4.     .probe      = i2c_device_probe,  
  5.     .remove     = i2c_device_remove,  
  6.     .shutdown   = i2c_device_shutdown,  
  7.     .pm     = &i2c_device_pm_ops,  
  8. };  

  1. static const struct dev_pm_ops i2c_device_pm_ops = {  
  2.     .suspend = i2c_device_pm_suspend,  
  3.     .resume = i2c_device_pm_resume,  
  4.     .freeze = i2c_device_pm_freeze,  
  5.     .thaw = i2c_device_pm_thaw,  
  6.     .poweroff = i2c_device_pm_poweroff,  
  7.     .restore = i2c_device_pm_restore,  
  8.     SET_RUNTIME_PM_OPS(  
  9.         pm_generic_runtime_suspend,  
  10.         pm_generic_runtime_resume,  
  11.         pm_generic_runtime_idle  
  12.     )  
  13. };  

  1. static int i2c_device_pm_suspend(struct device *dev)  
  2. {  
  3.     const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;  
  4. //如果device对应的driver定义了pm,pm->suspend存在,调用pm->suspend(dev)  
  5.     if (pm)  
  6.         return pm_generic_suspend(dev);  
  7. //如果没有定义pm,如果driver->suspend存在,调用driver->suspend(client, mesg)  
  8.     else  
  9.         return i2c_legacy_suspend(dev, PMSG_SUSPEND);  
  10. }  
如果driver->pm定义了,就不会执行driver->suspend了。
再例如:[ 271.963564@0] suspend adc_key.10+ @ 865, parent: platform
platform_device_add()->
pdev->dev.bus = &platform_bus_type;
没有定义pdev->dev.type。

  1. struct bus_type platform_bus_type = {  
  2.     .name       = "platform",  
  3.     .dev_attrs  = platform_dev_attrs,  
  4.     .match      = platform_match,  
  5.     .uevent     = platform_uevent,  
  6.     .pm     = &platform_dev_pm_ops,  
  7. };  

  1. static const struct dev_pm_ops platform_dev_pm_ops = {  
  2.     .runtime_suspend = pm_generic_runtime_suspend,  
  3.     .runtime_resume = pm_generic_runtime_resume,  
  4.     .runtime_idle = pm_generic_runtime_idle,  
  5.     USE_PLATFORM_PM_SLEEP_OPS  
  6. };  


  1. #define USE_PLATFORM_PM_SLEEP_OPS \  
  2.     .suspend = platform_pm_suspend, \  
  3.     .resume = platform_pm_resume, \  
  4.     .freeze = platform_pm_freeze, \  
  5.     .thaw = platform_pm_thaw, \  
  6.     .poweroff = platform_pm_poweroff, \  
  7.     .restore = platform_pm_restore,  

  1. int platform_pm_suspend(struct device *dev)  
  2. {  
  3.     struct device_driver *drv = dev->driver;  
  4.     int ret = 0;  
  5.   
  6.     if (!drv)  
  7.         return 0;  
  8.   
  9.     if (drv->pm) {  
  10.         if (drv->pm->suspend)  
  11.             ret = drv->pm->suspend(dev);  
  12.     } else {  
  13.         ret = platform_legacy_suspend(dev, PMSG_SUSPEND);  
  14.     }  
  15.   
  16.     return ret;  
  17. }  
同样,如果driver->pm定义了,就不会执行driver->suspend了。
3.6.2.2 suspend_enter()
  1. static int suspend_enter(suspend_state_t state, bool *wakeup)  
  2. {  
  3.     int error;  
  4. //平台相关  
  5.     if (need_suspend_ops(state) && suspend_ops->prepare) {  
  6.         error = suspend_ops->prepare();  
  7.         if (error)  
  8.             goto Platform_finish;  
  9.     }  
  10. // Execute "late" and "noirq" device suspend callbacks.  
  11.     error = dpm_suspend_end(PMSG_SUSPEND);  
  12.     if (error) {  
  13.         printk(KERN_ERR "PM: Some devices failed to power down\n");  
  14.         goto Platform_finish;  
  15.     }  
  16.   
  17.     if (need_suspend_ops(state) && suspend_ops->prepare_late) {  
  18.         error = suspend_ops->prepare_late();  
  19.         if (error)  
  20.             goto Platform_wake;  
  21.     }  
  22.   
  23.     if (suspend_test(TEST_PLATFORM))  
  24.         goto Platform_wake;  
  25.   
  26.     /* 
  27.      * PM_SUSPEND_FREEZE equals 
  28.      * frozen processes + suspended devices + idle processors. 
  29.      * Thus we should invoke freeze_enter() soon after 
  30.      * all the devices are suspended. 
  31.      */  
  32.     if (state == PM_SUSPEND_FREEZE) {  
  33.         freeze_enter();  
  34.         goto Platform_wake;  
  35.     }  
  36.   
  37.     error = disable_nonboot_cpus();  
  38.     if (error || suspend_test(TEST_CPUS))  
  39.         goto Enable_cpus;  
  40. //关中断  
  41.     arch_suspend_disable_irqs();  
  42.     BUG_ON(!irqs_disabled());  
  43.   
  44.     error = syscore_suspend();  
  45.     if (!error) {  
  46.         *wakeup = pm_wakeup_pending();  
  47.         if (!(suspend_test(TEST_CORE) || *wakeup)) {  
  48. // enter(state)使CPU进入省电状态,整个休眠过程完成,代码停止  
  49.             error = suspend_ops->enter(state);  
  50.             events_check_enabled = false;  
  51.         }  
  52.         syscore_resume();  
  53.     }  
  54.   
  55.     arch_suspend_enable_irqs();  
  56.     BUG_ON(irqs_disabled());  
  57.   
  58.  Enable_cpus:  
  59.     enable_nonboot_cpus();  
  60.   
  61.  Platform_wake:  
  62.     if (need_suspend_ops(state) && suspend_ops->wake)  
  63.         suspend_ops->wake();  
  64.   
  65.     dpm_resume_start(PMSG_RESUME);  
  66.   
  67.  Platform_finish:  
  68.     if (need_suspend_ops(state) && suspend_ops->finish)  
  69.         suspend_ops->finish();  
  70.   
  71.     return error;  
  72. }  
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()

  1. void dpm_resume_end(pm_message_t state)  
  2. {  
  3.     dpm_resume(state);  
  4.     dpm_complete(state);  
  5. }  
3.7.1 dpm_resume()
  1. void dpm_resume(pm_message_t state)  
  2. {  
  3.     struct device *dev;  
  4.     ktime_t starttime = ktime_get();  
  5.   
  6.     might_sleep();  
  7.   
  8.     mutex_lock(&dpm_list_mtx);  
  9.     pm_transition = state;  
  10.     async_error = 0;  
  11. //异步resum  
  12.     list_for_each_entry(dev, &dpm_suspended_list, power.entry) {  
  13.         INIT_COMPLETION(dev->power.completion);  
  14.         if (is_async(dev)) {  
  15.             get_device(dev);  
  16.             async_schedule(async_resume, dev);  
  17.         }  
  18.     }  
  19. //resum的list和suspend是相反的  
  20.     while (!list_empty(&dpm_suspended_list)) {  
  21.         dev = to_device(dpm_suspended_list.next);  
  22.         get_device(dev);  
  23.         if (!is_async(dev)) {  
  24.             int error;  
  25.   
  26.             mutex_unlock(&dpm_list_mtx);  
  27. //callback选择顺序同suspend  
  28.             error = device_resume(dev, state, false);  
  29.             if (error) {  
  30.                 suspend_stats.failed_resume++;  
  31.                 dpm_save_failed_step(SUSPEND_RESUME);  
  32.                 dpm_save_failed_dev(dev_name(dev));  
  33.                 pm_dev_err(dev, state, "", error);  
  34.             }  
  35.   
  36.             mutex_lock(&dpm_list_mtx);  
  37.         }  
  38.         if (!list_empty(&dev->power.entry))  
  39.             list_move_tail(&dev->power.entry, &dpm_prepared_list);  
  40.         put_device(dev);  
  41.     }  
  42.     mutex_unlock(&dpm_list_mtx);  
  43.     async_synchronize_full();  
  44.     dpm_show_time(starttime, state, NULL);  
  45. }  
无论是同步resum,还是异步resum都会调用device_resume();
3.7.2 dpm_complete()
  1. void dpm_complete(pm_message_t state)  
  2. {  
  3.     struct list_head list;  
  4.   
  5.     might_sleep();  
  6.   
  7.     INIT_LIST_HEAD(&list);  
  8.     mutex_lock(&dpm_list_mtx);  
  9. //包括新增加的device   
  10.     while (!list_empty(&dpm_prepared_list)) {  
  11.         struct device *dev = to_device(dpm_prepared_list.prev);  
  12.   
  13.         get_device(dev);  
  14.         dev->power.is_prepared = false;  
  15.         list_move(&dev->power.entry, &list);  
  16.         mutex_unlock(&dpm_list_mtx);  
  17. //执行callbacks  
  18.         device_complete(dev, state);  
  19.   
  20.         mutex_lock(&dpm_list_mtx);  
  21.         put_device(dev);  
  22.     }  
  23.     list_splice(&list, &dpm_list);  
  24.     mutex_unlock(&dpm_list_mtx);  
  25. }  

睡眠唤醒过程中的一些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()

  1. static void suspend_finish(void)  
  2. {  
  3.     suspend_thaw_processes();  
  4.     pm_notifier_call_chain(PM_POST_SUSPEND);  
  5.     pm_restore_console();  
  6. }  

suspend_finish()函数中,解冻进程和任务,使能用户空间helper进程,广播一个系统从suspend状态退出的notify,唤醒终端。
当所有的唤醒已经结束以后,用户进程都已经开始运行了,但没点亮屏幕,唤醒通常会是以下的几种原因:
如果是来电,那么Modem会通过发送命令给rild来让rild通知WindowManager有来电响应,这样就会远程调用PowerManagerService来写”on”到 /sys/power/state 来调用late resume(),执行点亮屏幕等操作。
用户按键事件会送到 WindowManager 中, WindowManager 会处理这些按键事件,按键分为几种情况,如果按键不是唤醒键,那么 WindowManager 会主动放弃wakeLock来使系统进入再次休眠;如果按键是唤醒键,那么 WindowManger 就会调用 PowerManagerService 中的接口来执行late resume。
3.9 late_resume()

  1. static void late_resume(struct work_struct *work)  
  2. {  
  3.     struct early_suspend *pos;  
  4.     unsigned long irqflags;  
  5.     int abort = 0;  
  6.   
  7.     mutex_lock(&early_suspend_lock);  
  8.     spin_lock_irqsave(&state_lock, irqflags);  
  9.     if (state == SUSPENDED)  
  10.         state &= ~SUSPENDED;  
  11.     else  
  12.         abort = 1;  
  13.     spin_unlock_irqrestore(&state_lock, irqflags);  
  14.   
  15.     if (abort) {  
  16.         if (debug_mask & DEBUG_SUSPEND)  
  17.             pr_info("late_resume: abort, state %d\n", state);  
  18.         goto abort;  
  19.     }  
  20.     if (debug_mask & DEBUG_SUSPEND)  
  21.         pr_info("late_resume: call handlers\n");  
  22. //late_resum的顺序和early_suspend相反  
  23.     list_for_each_entry_reverse(pos, &early_suspend_handlers, link)  
  24.         if (pos->resume != NULL)  
  25.         {  
  26.             printk("%pf\n",pos->resume);  
  27.             pos->resume(pos);  
  28.         }  
  29.     if (debug_mask & DEBUG_SUSPEND)  
  30.         pr_info("late_resume: done\n");  
  31. abort:  
  32.     mutex_unlock(&early_suspend_lock);  
  33. }  

        当”on”被写入到 /sys/power/state 之后,同early_suspend过程类似, request_suspend_state() 被调用,只是执行的工作队列变为 late_resume_work 。在 late_resume 函数中,唤醒调用了 early_suspend 的设备。

3.10 register_early_suspend()

  1. void register_early_suspend(struct early_suspend *handler)  
  2. {  
  3.     struct list_head *pos;  
  4.   
  5.     mutex_lock(&early_suspend_lock);  
  6.     list_for_each(pos, &early_suspend_handlers) {  
  7.         struct early_suspend *e;  
  8.         e = list_entry(pos, struct early_suspend, link);  
  9.         if (e->level > handler->level)  
  10.             break;  
  11.     }  
  12.     list_add_tail(&handler->link, pos);  
  13. //如果此时进入了suspend阶段,early_suspend已经执行过了,这里需要执行  
  14.     if ((state & SUSPENDED) && handler->suspend)  
  15.         handler->suspend(handler);  
  16.     mutex_unlock(&early_suspend_lock);  
  17. }  

early_suspend.level取值如下
  1. enum {  
  2.     EARLY_SUSPEND_LEVEL_BLANK_SCREEN = 50,  
  3.     EARLY_SUSPEND_LEVEL_STOP_DRAWING = 100,  
  4.     EARLY_SUSPEND_LEVEL_DISABLE_FB = 150,  
  5. };  

Suspend handlers are called in low to high level order, resume handlers are
called in the opposite order. 
suspend的顺序,根据level,从低到高;resum相反;如果要早睡晚醒,把level改小;如果要晚睡早醒;把level改大。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值