Android在标准Linux基础上对休眠唤醒的实现


一、新增特性介绍

实际上,Android仍然是利用了标准linux的休眠唤醒系统,只不过添加了一些使用上的新特性,early suspend、late resume、wake lock。

Early suspend - 这个机制定义了在suspend的早期,关闭显示屏的时候,一些和显示屏相关的设备,比如背光、重力感应器和触摸屏等设备都应该被关掉,但是此时系统可能还有持有wake lock的任务在运行,如音乐播放,电话,或者扫描sd卡上的文件等,这个时候整个系统还不能进入真正睡眠,直到所有的wake lock都没释放。在嵌入式设备中,悲观是一个很大的电源消耗,所有android加入了这种机制。

Late resume - 这个机制定义了在resume的后期,也就是唤醒源已经将处理器唤醒,标准linux的唤醒流程已经走完了,在android上层系统识别出这个物理上的唤醒源是上层定义的,那么上层将会发出late resume的命令给下层,这个时候将会调用相关设备注册的late resume回调函数。

Wake lock - wakelock在android的电源管理系统中扮演一个核心的角色,wakelock是一种锁的机制, 只要有task拿着这个锁, 系统就无法进入休眠, 可以被用户态进程和内核线程获得。这个锁可以是有超时的或者是没有超时的, 超时的锁会在时间过去以后自动解锁。如果没有锁了或者超时了, 内核就会启动标准linux的那套休眠机制机制来进入休眠。

二、kernel层源码解析 - early suspend 和 late resume实现

相关源码:

kernel/kernel/power/main.c

kernel/kernel/power/earlysuspend.c

kernel/kernel/power/wakelock.c

kernel/kernel/power/userwakelock.c

kernel/kernel/power/suspend.c

之前标准的linux的sysfs的接口只需要一个state就够了,现在至少需要3个接口文件:state、wake_lock、wake_unlock。现在为了配合android为休眠唤醒添加的几种新特性,可以填入文件state的模式又多了一种:on, 标准android系统中只支持state的on和mem模式,其余的暂不支持。wake_lock和wake_unlock接口对应的读写函数在文件userwakelock.c中,对wakelock.c中的create wakelock或者release wakelock进行了封装,供用户空间来使用。

如果上层用户执行:echo xxx(on or mem) > sys/power/state的话,将会调用到如下函数:

  1. static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,  
  2.   
  3. const char *buf, size_t n)  
  4.   
  5. {  
  6.   
  7. #ifdef CONFIG_SUSPEND // set   
  8.   
  9. #ifdef CONFIG_EARLYSUSPEND    //set   
  10.   
  11.        suspend_state_t state = PM_SUSPEND_ON;   // for early suspend and late resume   
  12.   
  13. #else   
  14.   
  15.        suspend_state_t state = PM_SUSPEND_STANDBY;  
  16.   
  17. #endif   
  18.   
  19.        const char * const *s;  
  20.   
  21. #endif   
  22.   
  23.        char *p;  
  24.   
  25.        int len;  
  26.   
  27.        int error = -EINVAL;  
  28.   
  29.    
  30.   
  31.        p = memchr(buf, '/n', n);  
  32.   
  33.        len = p ? p - buf : n;  
  34.   
  35.    
  36.   
  37.        /* First, check if we are requested to hibernate */  
  38.   
  39.        if (len == 4 && !strncmp(buf, "disk", len)) {  
  40.   
  41.               error = hibernate();  // 检查是否要求进入disk省电模式,暂时不支持   
  42.   
  43.   goto Exit;  
  44.   
  45.        }  
  46.   
  47.    
  48.   
  49. #ifdef CONFIG_SUSPEND        // def   
  50.   
  51.        for (s = &pm_states[state]; state < PM_SUSPEND_MAX; s++, state++) {  
  52.   
  53.               if (*s && len == strlen(*s) && !strncmp(buf, *s, len))  
  54.   
  55.                      break;  
  56.   
  57.        }  
  58.   
  59.        if (state < PM_SUSPEND_MAX && *s)  
  60.   
  61. #ifdef CONFIG_EARLYSUSPEND   
  62.   
  63.               if (state == PM_SUSPEND_ON || valid_state(state)) {  
  64.   
  65. // 需要经过平台pm.c文件定义的模式支持检查函数,mtk只支持mem,同时如果是android发送出来的late resume命令(on),这里也会放行,往下执行   
  66.   
  67.                      error = 0;  
  68.   
  69.                      request_suspend_state(state);     // android休眠唤醒的路线   
  70.   
  71.               }  
  72.   
  73. #else   
  74.   
  75.               error = enter_state(state);// 标准linux休眠唤醒的路线   
  76.   
  77. #endif   
  78.   
  79. #endif   
  80.   
  81.    
  82.   
  83.  Exit:  
  84.   
  85.        return error ? error : n;  
  86.   
  87. }  
  88.   
  89.    
  90.   
  91. @ kernel/kernel/power/earlysuspend.c  
  92.   
  93. enum {  
  94.   
  95.        DEBUG_USER_STATE = 1U << 0,  
  96.   
  97.        DEBUG_SUSPEND = 1U << 2,  
  98.   
  99. };  
  100.   
  101. int Earlysuspend_debug_mask = DEBUG_USER_STATE;  
  102.   
  103. module_param_named(Earlysuspend_debug_mask, Earlysuspend_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);  
  104.   
  105.    
  106.   
  107. static DEFINE_MUTEX(early_suspend_lock);  
  108.   
  109. static LIST_HEAD(early_suspend_handlers);  
  110.   
  111. static void early_sys_sync(struct work_struct *work);  
  112.   
  113. static void early_suspend(struct work_struct *work);  
  114.   
  115. static void late_resume(struct work_struct *work);  
  116.   
  117. static DECLARE_WORK(early_sys_sync_work, early_sys_sync);  
  118.   
  119. static DECLARE_WORK(early_suspend_work, early_suspend);  
  120.   
  121. static DECLARE_WORK(late_resume_work, late_resume);  
  122.   
  123. static DEFINE_SPINLOCK(state_lock);  
  124.   
  125. enum {  
  126.   
  127.        SUSPEND_REQUESTED = 0x1,  
  128.   
  129.        SUSPENDED = 0x2,  
  130.   
  131.        SUSPEND_REQUESTED_AND_SUSPENDED = SUSPEND_REQUESTED | SUSPENDED,  
  132.   
  133. };  
  134.   
  135. static int state;             // 初始化为0   
  136.   
  137.    
  138.   
  139. static DECLARE_COMPLETION(fb_drv_ready);  
  140.   
  141.    
  142.   
  143. void request_suspend_state(suspend_state_t new_state)  
  144.   
  145. {  
  146.   
  147.        unsigned long irqflags;  
  148.   
  149.        int old_sleep;  
  150.   
  151.    
  152.   
  153.        spin_lock_irqsave(&state_lock, irqflags);  
  154.   
  155.        old_sleep = state & SUSPEND_REQUESTED; // state = 1 or 3   
  156.   
  157. // state的值会在0->1->3->2->0循环变化,后面分析代码都可以看出这些值代表系统目前处于什么阶段,简单得说就是:正常->准备进early suspend->开始early suspend并且对名为mian的wakelock解锁,如果此时没有其余wakelock处于lock状态,那么系统就走linux的休眠唤醒路线让整个系统真正休眠,直到唤醒源发生,然后将处理器和linux层唤醒。之后android层判断本次底层醒来是由于我所定义的唤醒源引起的吗?如果不是,android将不予理会,过段时间没有wakelock锁,系统会再次走linux的休眠路线进入休眠。如果是,那么android上层就会写一个on的指令到state接口中,同样是会调用到函数request_suspend_state() -> 准备执行late resume -> 开始执行late resume,之后整个系统就这样被唤醒了。   
  158.   
  159.        if (Earlysuspend_debug_mask & DEBUG_USER_STATE) {  
  160.   
  161.               struct timespec ts;        // 打印出debug信息   
  162.   
  163.               struct rtc_time tm;  
  164.   
  165.               getnstimeofday(&ts);  
  166.   
  167.               rtc_time_to_tm(ts.tv_sec, &tm);  
  168.   
  169.               pr_info("[request_suspend_state]: %s (%d->%d) at %lld "  
  170.   
  171.                      "(%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)/n",  
  172.   
  173.                      new_state != PM_SUSPEND_ON ? "sleep" : "wakeup",  
  174.   
  175.                      requested_suspend_state, new_state,  
  176.   
  177.                      ktime_to_ns(ktime_get()),  
  178.   
  179.                      tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,  
  180.   
  181.                      tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec);  
  182.   
  183.        }  
  184.   
  185. // eg: [request_suspend_state]: sleep (0->3) at 97985478409 (2010-01-03 09:52:59.637902305 UTC), 这里对时间的获取和处理,在其他地方可以参考   
  186.   
  187.        // ready to enter earlysuspend   
  188.   
  189.        if (!old_sleep && new_state != PM_SUSPEND_ON) { // SUSEpnd会进入这里   
  190.   
  191.               state |= SUSPEND_REQUESTED;    // state = 1   
  192.   
  193.               pr_info("[request_suspend_state]:  
  194.   
  195. sys_sync_work_queue early_sys_sync_work/n");  
  196.   
  197.               queue_work(sys_sync_work_queue, &early_sys_sync_work);  
  198.   
  199.               pr_info("[request_suspend_state]: suspend_work_queue early_suspend_work/n");  
  200.   
  201.               queue_work(suspend_work_queue, &early_suspend_work);  
  202.   
  203. // 在wakelocks_init()函数(wakelock.c)中会创建这两个工作队列和工作者线程来专门负责处理sys_sync和early suspend的工作。关于工作队列的详情参考我工作队列的文章   
  204.   
  205.        }  
  206.   
  207.        // ready to enter lateresume   
  208.   
  209.        else if (old_sleep && new_state == PM_SUSPEND_ON) {  
  210.   
  211.               state &= ~SUSPEND_REQUESTED; // state = 2   
  212.   
  213.               wake_lock(&main_wake_lock);         // 对main wakelock上锁   
  214.   
  215.               pr_info("[request_suspend_state]: suspend_work_queue late_resume_work/n" );  
  216.   
  217.               if (queue_work(suspend_work_queue, &late_resume_work)) {  
  218.   
  219. // 提交late resume的工作项   
  220.   
  221.             //   
  222.   
  223.             //  In order to synchronize the backlight turn on timing,   
  224.   
  225.             //  block the thread and wait for fb driver late_resume()   
  226.   
  227.                   //  callback function is completed   
  228.   
  229.                   //   
  230.   
  231.             wait_for_completion(&fb_drv_ready);       
  232.   
  233. // 等待完成量fb_drv_ready,他会在late resume结束之后完成   
  234.   
  235.         }  
  236.   
  237.        }  
  238.   
  239.        requested_suspend_state = new_state;       
  240.   
  241. // 存储本次休眠或者是唤醒的状态,供下次休眠或者唤醒使用   
  242.   
  243.        spin_unlock_irqrestore(&state_lock, irqflags);  
  244.   
  245. }  

在系统suspend的时候提交的两个工作项会陆续被执行到,那么下面就来看一下执行early suspend的关键函数。

  1. static void early_sys_sync(struct work_struct *work)  
  2.   
  3. {  
  4.   
  5.        wake_lock(&sys_sync_wake_lock);  
  6.   
  7.        printk("[sys_sync work] start/n");  
  8.   
  9.        sys_sync();    // 同步文件系统   
  10.   
  11.        printk("[sys_sync wrok] done/n");  
  12.   
  13.        wake_unlock(&sys_sync_wake_lock);  
  14.   
  15. }  
  16.   
  17.    
  18.   
  19. static void early_suspend(struct work_struct *work)  
  20.   
  21. {  
  22.   
  23.        struct early_suspend *pos;  
  24.   
  25.        unsigned long irqflags;  
  26.   
  27.        int abort = 0;  
  28.   
  29.    
  30.   
  31.        mutex_lock(&early_suspend_lock);  
  32.   
  33.        spin_lock_irqsave(&state_lock, irqflags);  
  34.   
  35.        if (state == SUSPEND_REQUESTED)  
  36.   
  37.               state |= SUSPENDED; // state = 3   
  38.   
  39.        else  
  40.   
  41.               abort = 1;  
  42.   
  43.        spin_unlock_irqrestore(&state_lock, irqflags);  
  44.   
  45.    
  46.   
  47.        if (abort) {     // suspend 中止退出   
  48.   
  49.               if (Earlysuspend_debug_mask & DEBUG_SUSPEND)  
  50.   
  51.                      pr_info("[early_suspend]: abort, state %d/n", state);  
  52.   
  53.               mutex_unlock(&early_suspend_lock);  
  54.   
  55.               goto abort;  
  56.   
  57.        }  
  58.   
  59.    
  60.   
  61.        if (Earlysuspend_debug_mask & DEBUG_SUSPEND)  
  62.   
  63.               pr_info("[early_suspend]: call handlers/n");  
  64.   
  65.        list_for_each_entry(pos, &early_suspend_handlers, link) {  
  66.   
  67.               if (pos->suspend != NULL)  
  68.   
  69.                      pos->suspend(pos);  
  70.   
  71.        }  
  72.   
  73. // 函数register_early_suspend()会将每一个early suspend项以优先级大小注册到链表early_suspend_handlers中,这里就是一次取出,然后执行对应的early suspend回调函数   
  74.   
  75.        mutex_unlock(&early_suspend_lock);  
  76.   
  77.    
  78.   
  79.        // Remove sys_sync from early_suspend,   
  80.   
  81.        // and use work queue to complete sys_sync   
  82.   
  83.    
  84.   
  85. abort:  
  86.   
  87.        spin_lock_irqsave(&state_lock, irqflags);  
  88.   
  89.        if (state == SUSPEND_REQUESTED_AND_SUSPENDED)  
  90.   
  91.        {  
  92.   
  93.               pr_info("[early_suspend]: wake_unlock(main)/n");  
  94.   
  95.               wake_unlock(&main_wake_lock);  
  96.   
  97. // main wakelock 解锁。看到这里,好像系统执行了early suspend之后就没有往下执行标准linux的suspend流程了,其实不是,android的做法是,不是你执行完了early suspend  的回调就可以马上走标准linux的suspend流程,而是会检查还有没有wakelock被持有,如果所有wakelock全是解锁状态,那么就会执行标准linux的suspend步骤。   
  98.   
  99. }  
  100.   
  101.        spin_unlock_irqrestore(&state_lock, irqflags);  
  102.   
  103. }  
  104.   
  105.    
  106.   
  107. static void late_resume(struct work_struct *work)  
  108.   
  109. {  
  110.   
  111.        struct early_suspend *pos;  
  112.   
  113.        unsigned long irqflags;  
  114.   
  115.        int abort = 0;  
  116.   
  117.     int completed = 0;  
  118.   
  119.    
  120.   
  121.        mutex_lock(&early_suspend_lock);  
  122.   
  123.        spin_lock_irqsave(&state_lock, irqflags);  
  124.   
  125.    
  126.   
  127.     // return back from suspend   
  128.   
  129.        if (state == SUSPENDED)  
  130.   
  131.               state &= ~SUSPENDED;    // state = 0   
  132.   
  133.        else  
  134.   
  135.               abort = 1;  
  136.   
  137.        spin_unlock_irqrestore(&state_lock, irqflags);  
  138.   
  139.    
  140.   
  141.        if (abort) {  
  142.   
  143.               if (Earlysuspend_debug_mask & DEBUG_SUSPEND)  
  144.   
  145.                      pr_info("[late_resume]: abort, state %d/n", state);  
  146.   
  147.               goto abort;  
  148.   
  149.        }  
  150.   
  151.        if (Earlysuspend_debug_mask & DEBUG_SUSPEND)  
  152.   
  153.               pr_info("[late_resume]: call handlers/n");  
  154.   
  155.        list_for_each_entry_reverse(pos, &early_suspend_handlers, link)  
  156.   
  157.     {  
  158.   
  159.         if (!completed && pos->level < EARLY_SUSPEND_LEVEL_DISABLE_FB) {  
  160.   
  161.             complete(&fb_drv_ready);  
  162.   
  163.             completed = 1;  
  164.   
  165.         }  
  166.   
  167.               if (pos->resume != NULL)  
  168.   
  169.                      pos->resume(pos);  
  170.   
  171.     }  
  172.   
  173. // 以和early suspend的逆序执行链表early_suspend_handlers上的late resume回调函数   
  174.   
  175. if (Earlysuspend_debug_mask & DEBUG_SUSPEND)  
  176.   
  177.               pr_info("[late_resume]: done/n");  
  178.   
  179. abort:  
  180.   
  181.     if (!completed)  
  182.   
  183.         complete(&fb_drv_ready);   // 设置完成量ok   
  184.   
  185.      mutex_unlock(&early_suspend_lock);  
  186.   
  187. }  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 下一页

相关内容