zoukankan      html  css  js  c++  java
  • Android休眠唤醒机制

    有四种方式可以引起休眠

            ①在wake_unlock()中, 如果发现解锁以后没有任何其他的wake lock了, 就开始休眠

            ②在定时器到时间以后, 定时器的回调函数会查看是否有其他的wake lock, 如果没有, 就在这里让系统进入睡眠

            ③在wake_lock() 中, 对一个wake lock加锁以后, 会再次检查一下有没有锁,  刚加上锁,为什么要检查,有用吗?

            ④按power键,调用earlysuspend.使系统或应用程序释放锁.从而调用上述三个函数进入休眠

    1. earlysuspend、autosleep以及wakeup_count三种休眠机制的分析和比较

    1) android 面临的问题

    Opportunistic sleep: 当没有任务时,需要寻找时机,进入suspended

    2) 3类同步问题

    a. 内核:driver处理event的过程中,系统不能suspend

    b. 用户:用户进程处理的过程中系统不能suspend

    c. 内核与用户交互:

    休眠过程中,触发event, 需abort suspend流程;

    event 事件需用户态处理完毕后,才能suspend;

    2.常见的休眠唤醒机制有三种:earlysuspend、autosleep、wakeup_count。

    1. earlysuspend机制介绍:

      由上图可得,应用程序application层创建,申请,释放wake_lock锁,通过上层应用类PowerManagerService.java获得和释放wake_lock锁。

      对于进入休眠,有两种情况:

      1. 一种是power键灭屏关闭LCD、TP,或者后台有一些进程正在执行,如音乐播放器、文件传输之类,此时系统会先进入early_suspend状态,然后当这些正在执行的进程执行完成,PowerManagerService检查系统已经没有wake_lock锁时,系统进入深度休眠状态,Early_suspend与late_resume成对出现。
      2. 另一种是,系统直接检查到没有wake_lock锁时,直接进入深度睡眠状态。
    2. Autosleep

    3. Wakeup_count

    1. Android在Linux内核原有的睡眠唤醒模块基础上,主要增加了下面三个机制

      • Wake Lock 唤醒锁机制;

      • Early Suspend 预挂起机制;

      • Late Resume 迟唤醒机制;

      其基本原理:当启动一个应用程序的时候,它可以申请一个wake_lock唤醒锁,每当申请成功后都会在内核中注册一下(通知系统内核,现在已经有锁被申请,系统内核的wake_lock_store把它加入锁中),当应用程序在某种情况下释放wake_lock的时候,会注销之前所申请的wake_lock。特别要注意的是:只要是系统中有一个wake_lock的时候,系统此时都不能进行睡眠。但此时各个模块可以进行early_suspend。当系统中所有的wake_lock都被释放之后,系统就会进入真正的kernel的睡眠状态。在系统启动的时候会创建一个主唤醒锁main_wake_lock,该锁是内核初始化并持有的一个WAKE_LOCK_SUSPEND属性的非限时唤醒锁。因此,系统正常工作时,将始终因为该锁被内核持有而无法进入睡眠状态。也就是说在不添加新锁的情况下,只需将main_wake_lock 解锁,系统即可进入睡眠状态。

      从Android最上层(Java的应用程序),经过Java、C++和C语言写的Framework层、JNI层、HAL层最后到达android的最底层(Kernel层)。

      相关代码位置:

      Frameworks

      // 供给上层应用程序调用的接口

      frameworks/base/core/java/android/os/PowerManager.java

      // 具体实现PowerManager类中的接口

      frameworks/base/services/java/com/android/server/PowerManagerService.java

      // 被PowerManagerService类调用

      frameworks/base/core/java/android/os/ Power.java

      • JNI

      // 实现Power类中的JNI接口

      frameworks/base/core/jni/android_os_Power.cpp

      • HAL

      // 进行sysfs用户接口的操作

      hardware/libhardware_legacy/power/power.c

      • Kernel

      kernel/kernel/power/main.c

      kernel/kernel/power/earlysuspend.c

      kernel/kernel/power/suspend.c

      kernel/kernel/power/wakelock.c

      kernel/kernel/power/userwakelock.c

      在应用程序框架层中,PowerManager类是面向上层应用程序的接口类,提供了Wake Lock机制(同时也是睡眠唤醒子系统)的基本接口(唤醒锁的获取和释放)。上层应用程序通过调用这些接口,实现对系统电源状态的监控。

      • PowerManager类通过IBinder这种Android中特有的通信模式,与PowerManagerService 类进行通信。

      PowerManagerService 是PowerManager 类中定义的接口的具体实现,并进一步调用Power 类来与下一层进行通信。PowerManagerService 类是WakeLock 机制在应用程序框架层的核心,他们对应用程调用PowerManager类接口时所传递的参数进行初步的分析和对应的设置,并管理一个唤醒锁队列,然后配合其他模块(例如WatchDog、BatteryService、ShutdownThread 等)的状态信息,做出决策,调用Power类的对应接口,最终通过JNI 接口,调用到硬件抽象层中的函数,对sysfs 的用户接口进行操作,从而触发内核态实现的功能。

    2. 获得wake_lock唤醒锁

      比如在应用程序中,当获得wakelock唤醒锁的时候,它首先调用/android/frameworks/base/core/java/android/os/PowerManager类中的public void acquire()办法,而此方法通过Binder将调用PowerManagerService类中的public void acquireWakeLock。

      在用户态的调用流程如下:

      上述write实质上是文件sysfs: /sys/power/wake_lock,当write时,它将调用userwakelock.c::wake_lock_store()函数,其实现如下:

      1. 根据name在红黑树中查找user_wake_lock,若找到则直接返回;否则为它分配内存、调用wake_lock_init初始化、然后增加到红黑树中。

      2. 调用wake_lock或wake_lock_timeout,它将调用wake_lock_internal

      wake_lock_internal()函数流程:

      1) 判断锁的类型是否有效,即是否为WAKE_LOCK_SUSPEND或WAKE_LOCK_IDLE某一种 

      2) 如果定义了CONFIG_WAKELOCK_STAT, 则更新struct wake_lock里面的用于统计锁信息的成员变量 

      3) 将锁从inactive_locks链表上取下,加到active_wake_locks链表上。如果是超期锁则设置锁的flag|=WAKE_LOCK_AUTO_EXPIRE,否则取消WAKE_LOCK_AUTO_EXPIRE标志。如果锁是WAKE_LOCK_SUSPEND型的,则继续下面的步骤。 

      4) 对于WAKE_LOCK_SUSPEND型的锁如果它是超期锁,则调用has_wake_lock_locked函数检查所有处于活动状态的WAKE_LOCK_SUSPEND锁(即在active_wake_locks链表上的WAKE_LOCK_SUSPEND锁,或者说当前被加锁了的WAKE_LOCK_SUSPEND锁),是否有超期锁已经过期,如果有则把过期超期锁从active_wake_locks上删除,挂到inactive_locks上。同时它还检查链表上有没有非超期锁,如果有则直接返回-1,否则它最终返回的是所有超期锁过期时间的最大值 

      5) 如果has_wake_lock_locked函数返回的是-1(表示当前活动锁有非超时锁)或者0(表示所有活动锁都是超时锁,且全已经超时),则删除expire_timer,并排队一个suspend工作到suspend_work_queue工作队列,最终系统会suspend。suspend函数完成suspend系统的任务,它是suspend_work这个工作的处理函数,suspend_workk排队到suspend_work_queue工作队列中,最终系统会处理这个work,调用其handler即suspend函数。该函数首先sync文件系统,然后调用pm_suspend(request_suspend_state),接下来pm_suspend()就会调用 enter_state()来进入 linux的suspend流程。

    3. 系统进入休眠(suspend)

      当按了MID上的power键,经过一系统列的事务处理后,它会调用到PowerManager类中的goToSleep。在用户态的调用流程如下所示:

      最后一步write()写操作把"mem"写入/sys/power/state中。接下来,在kernel态,state_store函数将被调用。

      • Android特有的earlysuspend: request_suspend_state(state)

      • Linux标准的suspend: enter_state(state)

      在state_store()首先判断用户写入的是否是"disk"字符串,如果是则调用hibernate()函数命令系统进入hibernation状态。如果是其他字符串则调用request_suspend_state()(如果定义 CONFIG_EARLYSUSPEND)或者调用enter_state()(如果未定义CONFIG_EARLYSUSPEND)。 request_suspend_state()函数是android相对标准linux改动的地方,它实现在earlysuspend.c中。在标准linux内核中,用户通过 sysfs 写入"mem"和"standby"时,会直接调用enter_state()进入suspend模式,但在android中则会调用request_suspend_state()函数进入early suspend状态。

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

    len = p ? p - buf : n;

       

       

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

    }

    #else

    error = enter_state(state);

    #endif

    #endif

    Exit:

    return error ? error : n;

    }

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

    static DECLARE_WORK(early_suspend_work, early_suspend);

    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-d-d d:d:d. lu UTC) ",

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

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

    }

    requested_suspend_state = new_state;

    spin_unlock_irqrestore(&state_lock, irqflags);

    }

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

    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 ", state);

    mutex_unlock(&early_suspend_lock);

    goto abort;

    }

       

    if (debug_mask & DEBUG_SUSPEND)

    pr_info("early_suspend: call handlers ");

    list_for_each_entry(pos, &early_suspend_handlers, link) {

    if (pos->suspend != NULL)

    pos->suspend(pos);

    }

    mutex_unlock(&early_suspend_lock);

       

    if (debug_mask & DEBUG_SUSPEND)

    pr_info("early_suspend: sync ");

       

    sys_sync();

    abort:

    spin_lock_irqsave(&state_lock, irqflags);

    if (state == SUSPEND_REQUESTED_AND_SUSPENDED)

    wake_unlock(&main_wake_lock);

    spin_unlock_irqrestore(&state_lock, irqflags);

    }

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

    tatic DECLARE_WORK(suspend_work, suspend);

    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 ", 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 ", 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 ", lock->name);

    if (has_lock == 0)

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

    }

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

    static void suspend(struct work_struct *work)

    {

    int ret;

    int entry_event_num;

       

    if (has_wake_lock(WAKE_LOCK_SUSPEND)) {

    if (debug_mask & DEBUG_SUSPEND)

    pr_info("suspend: abort suspend ");

    return;

    }

       

    entry_event_num = current_event_num;

    sys_sync();

    if (debug_mask & DEBUG_SUSPEND)

    pr_info("suspend: enter suspend ");

    ret = pm_suspend(requested_suspend_state);

    if (debug_mask & DEBUG_EXIT_SUSPEND) {

    struct timespec ts;

    struct rtc_time tm;

    getnstimeofday(&ts);

    rtc_time_to_tm(ts.tv_sec, &tm);

    pr_info("suspend: exit suspend, ret = %d "

    "(%d-d-d d:d:d. lu UTC) ", ret,

    tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,

    tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec);

    }

    if (current_event_num == entry_event_num) {

    if (debug_mask & DEBUG_SUSPEND)

    pr_info("suspend: pm_suspend returned with no event ");

    wake_lock_timeout(&unknown_wakeup, HZ / 2);

    }

    }

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

    int pm_suspend(suspend_state_t state)

    {

    if (state > PM_SUSPEND_ON && state <= PM_SUSPEND_MAX)

    return enter_state(state);

    return -EINVAL;

    }

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

    static int enter_state(suspend_state_t state)

    {

    int error;

       

    if (!valid_state(state))

    return -ENODEV;

       

    if (!mutex_trylock(&pm_mutex))

    return -EBUSY;

       

    printk(KERN_INFO "PM: Syncing filesystems ... ");

    sys_sync();

    printk("done. ");

       

    pr_debug("PM: Preparing system for %s sleep ", pm_states[state]);

    error = suspend_prepare();

    if (error)

    goto Unlock;

       

    if (suspend_test(TEST_FREEZER))

    goto Finish;

       

    pr_debug("PM: Entering %s sleep ", pm_states[state]);

    error = suspend_devices_and_enter(state);

       

    Finish:

    pr_debug("PM: Finishing wakeup. ");

    suspend_finish();

    Unlock:

    mutex_unlock(&pm_mutex);

    return error;

    }

    外部设备在注册时,都会注册其自身的suspend函数,enter_state()函数通过回调这些设备的suspend使其进入suspend态

    1. 唤醒流程suspend流程相反
  • 相关阅读:
    获取控件的xy坐标
    你不知道的JavaScript--Item4 基本类型和基本包装类型(引用类型)
    你不知道的JavaScript--Item3 隐式强制转换
    ajax技术基础详解
    git回退到某个历史版本
    jQuery中 $.ajax()方法详解
    Eclipse Java注释模板设置详解
    MySQL中group_concat函数深入理解
    javascript知识详解之8张思维导图
    javascript 事件编程之事件(流,处理,对象,类型)
  • 原文地址:https://www.cnblogs.com/yejintianming00/p/8075073.html
Copyright © 2011-2022 走看看