最近研究如何让Android不休眠。听组里人说,机器在充电的时候不休眠。我试了一下,确实是,串口可以使用(CONFIG_PM_DEBUG并没有打开)。

这个时候,LCD显示屏是休眠了,触摸屏也休眠了,其他的比如重力传感器等就没有看了,但是标准的Linux系统并没有进入休眠。看了网上好多关于Android系统的休眠与唤醒

例子,感觉有些懵懵懂懂的。于是,还是看内核代码吧。

        Android在标准的Linux休眠与唤醒机制上又加了一层,就是early_suspend / late_resume。顾名思意,使用early_suspend()进行休眠的设备,它休眠的时刻早于其他设备,使用late_resume()唤醒的设备,它被唤醒的时刻要晚于其他设备。这对函数通常成对出现,当内核打开了CONFIG_EARLY_SUSPEND(Android默认打开)后,就可以使

用这组函数来代替驱动中标准的 suspend / resume接口。

        好了,讲到early_suspend和late_resume,似乎必须要扯到一种叫做wake_lock的锁定机制了。其实,单纯从某个设备的驱动程序上来讲,未必需要用到wake_lock机制,

比如我们的触摸屏驱动中使用了early_suspend,就没有使用wake_lock.

       目前,我了解到的,wake_lock的用途只有一个,那就是防止系统进入休眠(这里的休眠,指的是标准的Linux的休眠,不包含使用early_suspend()进行休眠的设备,

使用early_suspend()的设备,在系统还有wake_lock锁的时候,也是要休眠的)。

       好吧,现在是时候分析下Android/Linux的休眠与唤醒了,虽然好多先人 都已经讲了这些,而且讲的还不错,这里我还是要提一下。

root@android:/ # ls /sys/power/                                                
pm_async
state
wait_for_fb_sleep
wait_for_fb_wake
wake_lock
wake_unlock
wakeup_count

       这里,我只关注state,当state 的值变化时,内核会调用




1. static ssize_t state_store(struct kobject *kobj, struct
2. const char *buf, size_t
3. {  
4. #ifdef CONFIG_SUSPEND
5. #ifdef CONFIG_EARLYSUSPEND
6.     suspend_state_t state = PM_SUSPEND_ON;  
7. #else
8.     suspend_state_t state = PM_SUSPEND_STANDBY;  
9. #endif
10. const char * const
11. #endif
12. char
13. int
14. int
15.   
16. '\n', n);   
17.     len = p ? p - buf : n;  
18.   
19. /* First, check if we are requested to hibernate */
20. if (len == 4 && !strncmp(buf, "disk", len)) {  
21.         error = hibernate();  
22. goto
23.     }     
24.   
25. #ifdef CONFIG_SUSPEND
26. for
27. if
28. break;  
29.     }     
30. if
31. #ifdef CONFIG_EARLYSUSPEND
32. if
33.             error = 0;  
34. //这里,进入了Android的休眠与唤醒的处理函数
35.         }  
36. #else 
37.         error = enter_state(state);  
38. #endif 
39. #endif
40.   
41.  Exit:  
42. return
43. }  
44.   
45. power_attr(state);


static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,
               const char *buf, size_t n)
{
#ifdef CONFIG_SUSPEND
#ifdef CONFIG_EARLYSUSPEND
    suspend_state_t state = PM_SUSPEND_ON;
#else
    suspend_state_t state = PM_SUSPEND_STANDBY;
#endif
    const char * const *s; 
#endif
    char *p; 
    int len;
    int error = -EINVAL;

    p = memchr(buf, '\n', n); 
    len = p ? p - buf : n;

    /* First, check if we are requested to hibernate */
    if (len == 4 && !strncmp(buf, "disk", len)) {
        error = hibernate();
  goto Exit;
    }   

#ifdef CONFIG_SUSPEND
    for (s = &pm_states[state]; state < PM_SUSPEND_MAX; s++, state++) {
        if (*s && len == strlen(*s) && !strncmp(buf, *s, len))
            break;
    }   
    if (state < PM_SUSPEND_MAX && *s) 
#ifdef CONFIG_EARLYSUSPEND
        if (state == PM_SUSPEND_ON || valid_state(state)) {
            error = 0;
            request_suspend_state(state);//这里,进入了Android的休眠与唤醒的处理函数
        }
#else
        error = enter_state(state);
#endif
#endif

 Exit:
    return error ? error : n;
}

power_attr(state);



看看



1. request_suspend_state()都干了些什么事情


request_suspend_state()都干了些什么事情






1. void
2. {  
3. long
4. int
5.   
6.     spin_lock_irqsave(&state_lock, irqflags);  
7.     old_sleep = state & SUSPEND_REQUESTED;  
8. if
9. struct
10. struct rtc_time tm;   
11.         getnstimeofday(&ts);  
12. tm);  
13. "request_suspend_state: %s (%d->%d) at %lld "
14. "(%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)\n",  
15. "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. if
22.         state |= SUSPEND_REQUESTED;  
23. //在休眠的时候,去遍历执行early_suspend_work这个队列
24. else if
25.         state &= ~SUSPEND_REQUESTED;  
26.         wake_lock(&main_wake_lock);  
27. //在唤醒的时候,去遍历执行late_resume_work这个队列
28.     }     
29.     requested_suspend_state = new_state;  
30.     spin_unlock_irqrestore(&state_lock, irqflags);  
31. }


void request_suspend_state(suspend_state_t new_state)
{
    unsigned long irqflags;
    int old_sleep;

    spin_lock_irqsave(&state_lock, irqflags);
    old_sleep = state & SUSPEND_REQUESTED;
    if (debug_mask & DEBUG_USER_STATE) {
        struct timespec ts; 
        struct rtc_time tm; 
        getnstimeofday(&ts);
        rtc_time_to_tm(ts.tv_sec, &tm);
        pr_info("request_suspend_state: %s (%d->%d) at %lld "
            "(%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)\n",
            new_state != PM_SUSPEND_ON ? "sleep" : "wakeup",
            requested_suspend_state, new_state,
            ktime_to_ns(ktime_get()),
            tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
            tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec);
    }   
    if (!old_sleep && new_state != PM_SUSPEND_ON) {
        state |= SUSPEND_REQUESTED;
        queue_work(suspend_work_queue, &early_suspend_work);//在休眠的时候,去遍历执行early_suspend_work这个队列
    } else if (old_sleep && new_state == PM_SUSPEND_ON) {
        state &= ~SUSPEND_REQUESTED;
        wake_lock(&main_wake_lock);
        queue_work(suspend_work_queue, &late_resume_work);//在唤醒的时候,去遍历执行late_resume_work这个队列
    }   
    requested_suspend_state = new_state;
    spin_unlock_irqrestore(&state_lock, irqflags);
}



        怎么样,是不是很简单,根据用户/系统所请求的状态,去做相应的动作(休眠/唤醒)

能用到的一些变量的声明在这里



1. static void early_suspend(struct
2. static void late_resume(struct
3. static
4. static


static void early_suspend(struct work_struct *work);
static void late_resume(struct work_struct *work);
static DECLARE_WORK(early_suspend_work, early_suspend);
static DECLARE_WORK(late_resume_work, late_resume);


         看名字也知道了,early_suspend这个函数指针来处理early_suspend_work这条队列,late_resume 这个函数指针来处理late_resume_work这条队列。

         虽然函数early_suspend()和late_resume()的实现都非常易懂,这里还是要贴出来,因为还有些东西要分析一下。




1. static void early_suspend(struct
2. {  
3. struct
4. long
5. int
6.   
7.     mutex_lock(&early_suspend_lock);  
8.     spin_lock_irqsave(&state_lock, irqflags);  
9. if
10.         state |= SUSPENDED;  
11. else
12.         abort = 1;  
13.     spin_unlock_irqrestore(&state_lock, irqflags);  
14.   
15. if
16. if
17. "early_suspend: abort, state %d\n", state);  
18.         mutex_unlock(&early_suspend_lock);  
19. goto
20.     }  
21.   
22. if
23. "early_suspend: call handlers\n");  
24. //这里就是关键了,遍历early_suspend_handler这条链表(在驱动中注册early_suspend的时候,都注册到这条链表上了)
25. if
26. if
27. "early_suspend: calling %pf\n", pos->suspend);  
28. //调用各个实现进行各设备的休眠
29.         }  
30.     }  
31.     mutex_unlock(&early_suspend_lock);  
32.   
33. if
34. "early_suspend: sync\n");  
35.   
36.     sys_sync();  
37. abort:  
38.     spin_lock_irqsave(&state_lock, irqflags);  
39. if
40. //这里很重要,别小看这个一个wake_unlock,起初我也以为这仅仅是一个释放main锁,其实里面有玄机呢。还记得wake_lock主要用来干嘛么,用来防止系统休眠,也就是说,只要系统中其他地方还拥有wake_lock锁(类型WAKE_LOCK_SUSPEND),系统就没法进入休眠,如果没有锁了,那就要接着走标准Linux的那一套休眠机制了
41.     spin_unlock_irqrestore(&state_lock, irqflags);  
42. }


static void early_suspend(struct work_struct *work)
{
    struct early_suspend *pos;
    unsigned long irqflags;
    int abort = 0;

    mutex_lock(&early_suspend_lock);
    spin_lock_irqsave(&state_lock, irqflags);
    if (state == SUSPEND_REQUESTED)
        state |= SUSPENDED;
    else
        abort = 1;
    spin_unlock_irqrestore(&state_lock, irqflags);

    if (abort) {
        if (debug_mask & DEBUG_SUSPEND)
            pr_info("early_suspend: abort, state %d\n", state);
        mutex_unlock(&early_suspend_lock);
        goto abort;
    }

    if (debug_mask & DEBUG_SUSPEND)
        pr_info("early_suspend: call handlers\n");
    list_for_each_entry(pos, &early_suspend_handlers, link) {//这里就是关键了,遍历early_suspend_handler这条链表(在驱动中注册early_suspend的时候,都注册到这条链表上了)
        if (pos->suspend != NULL) {
            if (debug_mask & DEBUG_VERBOSE)
                pr_info("early_suspend: calling %pf\n", pos->suspend);
            pos->suspend(pos);//调用各个实现进行各设备的休眠
        }
    }
    mutex_unlock(&early_suspend_lock);

    if (debug_mask & DEBUG_SUSPEND)
        pr_info("early_suspend: sync\n");

    sys_sync();
abort:
    spin_lock_irqsave(&state_lock, irqflags);
    if (state == SUSPEND_REQUESTED_AND_SUSPENDED)
        wake_unlock(&main_wake_lock);//这里很重要,别小看这个一个wake_unlock,起初我也以为这仅仅是一个释放main锁,其实里面有玄机呢。还记得wake_lock主要用来干嘛么,用来防止系统休眠,也就是说,只要系统中其他地方还拥有wake_lock锁(类型WAKE_LOCK_SUSPEND),系统就没法进入休眠,如果没有锁了,那就要接着走标准Linux的那一套休眠机制了
    spin_unlock_irqrestore(&state_lock, irqflags);
}




void wake_unlock(struct wake_lock *lock)  
{  
    int type;  
    unsigned long irqflags;  
    spin_lock_irqsave(&list_lock, irqflags);  
    type = lock->flags & WAKE_LOCK_TYPE_MASK;  
#ifdef CONFIG_WAKELOCK_STAT   
    wake_unlock_stat_locked(lock, 0);   
#endif   
    if (debug_mask & DEBUG_WAKE_LOCK)  
        pr_info("wake_unlock: %s\n", lock->name);  
    lock->flags &= ~(WAKE_LOCK_ACTIVE | WAKE_LOCK_AUTO_EXPIRE);  
    list_del(&lock->link);  
    list_add(&lock->link, &inactive_locks);  
    if (type == WAKE_LOCK_SUSPEND) {//类型,驱动中一般只有这一种类型   
        long has_lock = has_wake_lock_locked(type);  
        if (has_lock > 0) {  
            if (debug_mask & DEBUG_EXPIRE)  
                pr_info("wake_unlock: %s, start expire timer, "  
                    "%ld\n", lock->name, has_lock);  
            mod_timer(&expire_timer, jiffies + has_lock);  
        } else {  
            if (del_timer(&expire_timer))  
                if (debug_mask & DEBUG_EXPIRE)  
                    pr_info("wake_unlock: %s, stop expire "  
                        "timer\n", lock->name);  
            if (has_lock == 0)//如果没有锁了,要进入标准Linux的休眠机制了,咱们接着往下跟   
                queue_work(suspend_work_queue, &suspend_work);  
        }     
        if (lock == &main_wake_lock) {  
            if (debug_mask & DEBUG_SUSPEND)  
                print_active_locks(WAKE_LOCK_SUSPEND);  
#ifdef CONFIG_WAKELOCK_STAT   
            update_sleep_wait_stats_locked(0);  
#endif   
        }     
    }     
    spin_unlock_irqrestore(&list_lock, irqflags);  
}  
EXPORT_SYMBOL(wake_unlock);  


void wake_unlock(struct wake_lock *lock)
{
    int type;
    unsigned long irqflags;
    spin_lock_irqsave(&list_lock, irqflags);
    type = lock->flags & WAKE_LOCK_TYPE_MASK;
#ifdef CONFIG_WAKELOCK_STAT
    wake_unlock_stat_locked(lock, 0); 
#endif
    if (debug_mask & DEBUG_WAKE_LOCK)
        pr_info("wake_unlock: %s\n", lock->name);
    lock->flags &= ~(WAKE_LOCK_ACTIVE | WAKE_LOCK_AUTO_EXPIRE);
    list_del(&lock->link);
    list_add(&lock->link, &inactive_locks);
    if (type == WAKE_LOCK_SUSPEND) {//类型,驱动中一般只有这一种类型
        long has_lock = has_wake_lock_locked(type);
        if (has_lock > 0) {
            if (debug_mask & DEBUG_EXPIRE)
                pr_info("wake_unlock: %s, start expire timer, "
                    "%ld\n", lock->name, has_lock);
            mod_timer(&expire_timer, jiffies + has_lock);
        } else {
            if (del_timer(&expire_timer))
                if (debug_mask & DEBUG_EXPIRE)
                    pr_info("wake_unlock: %s, stop expire "
                        "timer\n", lock->name);
            if (has_lock == 0)//如果没有锁了,要进入标准Linux的休眠机制了,咱们接着往下跟
                queue_work(suspend_work_queue, &suspend_work);
        }   
        if (lock == &main_wake_lock) {
            if (debug_mask & DEBUG_SUSPEND)
                print_active_locks(WAKE_LOCK_SUSPEND);
#ifdef CONFIG_WAKELOCK_STAT
            update_sleep_wait_stats_locked(0);
#endif
        }   
    }   
    spin_unlock_irqrestore(&list_lock, irqflags);
}
EXPORT_SYMBOL(wake_unlock);



这里就是进入标准Linux的休眠的地方了



1. static void suspend(struct
2. {  
3. int
4. int
5. struct
6.   
7. if
8. if
9. "suspend: abort suspend\n");  
10. return;  
11.     }  
12.   
13.     entry_event_num = current_event_num;  
14.     sys_sync();  
15. if
16. "suspend: enter suspend\n");  
17.     getnstimeofday(&ts_entry);  
18. //这里是关键点
19.     getnstimeofday(&ts_exit);  
20.   
21. if
22. struct rtc_time tm;  
23. tm);  
24. "suspend: exit suspend, ret = %d "
25. "(%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)\n", ret,  
26. tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,  
27. tm.tm_hour, tm.tm_min, tm.tm_sec, ts_exit.tv_nsec);  
28.     }  
29.   
30. if
31.         ++suspend_short_count;  
32.   
33. if
34.             suspend_backoff();  
35.             suspend_short_count = 0;  
36.         }  
37. else
38.         suspend_short_count = 0;  
39.     }  
40.   
41. if
42. if
43. "suspend: pm_suspend returned with no event\n");  
44.         wake_lock_timeout(&unknown_wakeup, HZ / 2);  
45.     }  
46. }  
47. static


static void suspend(struct work_struct *work)
{
    int ret;
    int entry_event_num;
    struct timespec ts_entry, ts_exit;

    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;
    sys_sync();
    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, HZ / 2);
    }
}
static DECLARE_WORK(suspend_work, suspend);






1. int
2. {  
3. if
4. return enter_state(state);//正如你所料,开始走Linux那套休眠的流程了
5. return
6. }  
7. EXPORT_SYMBOL(pm_suspend);


int pm_suspend(suspend_state_t state)
{
    if (state > PM_SUSPEND_ON && state < PM_SUSPEND_MAX)
        return enter_state(state);//正如你所料,开始走Linux那套休眠的流程了
    return -EINVAL;
}
EXPORT_SYMBOL(pm_suspend);



       唤醒相关的代码就不贴 了,跟休眠类似的。

下面讲下驱动中如何使用wake_lock和early_suspend,总的来说,还是挺简单的

比如在设备probe的时候做如下操作

struct early_suspend    early_suspend;
early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; //等级,等级大小和suspend顺序一致,和resume顺序相反
 early_suspend.suspend = xxx_early_suspend;//指定函数指针,需自己实现
 early_suspend.resume = xxx_late_resume;register_early_suspend(&early_suspend);//注册进核心,也就是加入刚才early_suspend_handlers那个链表
 struct wake_lock    chrg_lock;
 wake_lock_init(&chrg_lock, WAKE_LOCK_SUSPEND, "xxx_wake_lock");//初始化类型为WAKE_LOCK_SUSPEND的wake_lock锁#ifdef CONFIG_HAS_EARLYSUSPEND
 static void xxx_early_suspend(struct early_suspend *h)
 {
        ....
         wake_lock(&chrg_lock);
       ....
 }


 static void xxx_late_resume(struct early_suspend *h)
 {
      .....
         wake_unlock(&chrg_lock);
      ....
 }
 #endif