Bootstrap

Android4.4电源管理——电源锁


//创建电源锁

PowerManagerService.java

    mWakeLockSuspendBlocker = createSuspendBlockerLocked("PowerManagerService.WakeLocks");

    mDisplaySuspendBlocker = createSuspendBlockerLocked("PowerManagerService.Display");


    private SuspendBlocker createSuspendBlockerLocked(String name) {
        SuspendBlocker suspendBlocker = new SuspendBlockerImpl(name);
        mSuspendBlockers.add(suspendBlocker);
        return suspendBlocker;
    }

//电源锁操作类的实现

    private final class SuspendBlockerImpl implements SuspendBlocker {
        private final String mName;
        private int mReferenceCount;

        public SuspendBlockerImpl(String name) {
            mName = name;
        }

        @Override
        public void acquire() {
            synchronized (this) {
                mReferenceCount += 1;
                if (mReferenceCount == 1) {
                    if (DEBUG_SPEW) {
                        Slog.d(TAG, "Acquiring suspend blocker \"" + mName + "\".");
                    }
                    nativeAcquireSuspendBlocker(mName);
                }
            }
        }

        @Override
        public void release() {
            synchronized (this) {
                mReferenceCount -= 1;
                if (mReferenceCount == 0) {
                    if (DEBUG_SPEW) {
                        Slog.d(TAG, "Releasing suspend blocker \"" + mName + "\".");
                    }
                    nativeReleaseSuspendBlocker(mName);
                } else if (mReferenceCount < 0) {
                    Log.wtf(TAG, "Suspend blocker \"" + mName
                            + "\" was released without being acquired!", new Throwable());
                    mReferenceCount = 0;
                }
            }
        }


    }

//JNI层函数实现电源锁的获取

com_android_server_power_PowerManagerService.cpp

static void nativeAcquireSuspendBlocker(JNIEnv *env, jclass clazz, jstring nameStr) {
    ScopedUtfChars name(env, nameStr);
    acquire_wake_lock(PARTIAL_WAKE_LOCK, name.c_str());
}


//将电源锁写入到相应的文件中,相当于获得了电源锁

power.c

int acquire_wake_lock(int lock, const char* id)
{
    initialize_fds();
    if (g_error) return g_error;

    int fd;

    if (lock == PARTIAL_WAKE_LOCK) {
        fd = g_fds[ACQUIRE_PARTIAL_WAKE_LOCK];
    }
    else {
        return EINVAL;
    }

    return write(fd, id, strlen(id));
}

//打开记录电源锁的文件

static inline void
initialize_fds(void)
{
    if (g_initialized == 0) {
        if(open_file_descriptors(NEW_PATHS) < 0)
            open_file_descriptors(OLD_PATHS);
        g_initialized = 1;
    }
}

//记录电源锁的文件路径

const char * const OLD_PATHS[] = {
    "/sys/android_power/acquire_partial_wake_lock",
    "/sys/android_power/release_wake_lock",
};

const char * const NEW_PATHS[] = {
    "/sys/power/wake_lock",
    "/sys/power/wake_unlock",
};

到现在为止,我们的代码流程已经走了一大半了,我们一开始介绍的android的上面几层Framework层、JNI层、HAL层都已经介绍了。下面就应该是和kernel层进行交互了。
但是在android/hardware/libhardware_legacy/power/power.c中的acquire_wake_lock()函数似乎没法和kernel层进行通信啊?最后的返回语句return write(fd, id, strlen(id))是一个系统调用,这里就实现了与kernel的交互。
kernel/power/main.c中的power_attr宏很多地方用到:

  1. #define power_attr(_name) \  
  2. static struct kobj_attribute _name##_attr = {   \  
  3.     .attr   = {             \  
  4.         .name = __stringify(_name), \  
  5.         .mode = 0644,           \  
  6.     },                  \  
  7.     .show   = _name##_show,         \  
  8.     .store  = _name##_store,        \  
  9. }  
  1. #ifdef CONFIG_USER_WAKELOCK  
  2. power_attr(wake_lock);  
  3. power_attr(wake_unlock);  
  4. #endif  
default y
User-space wake lock api. Write "lockname" or "lockname timeout"
to /sys/power/wake_lock lock and if needed create a wake lock.
Write "lockname" to /sys/power/wake_unlock to unlock a user wake
lock.
  1. #ifdef CONFIG_PM_WAKELOCKS  
  2. power_attr(wake_lock);  
  3. power_attr(wake_unlock);  
  4. #endif   
default n
Allow user space to create, activate and deactivate wakeup source
objects with the help of a sysfs-based interface.
宏展开,等价于:
  1. static struct kobj_attribute wake_lock_attr = {   
  2.     .attr   = {               
  3.         .name = “wake_lock”,      
  4.         .mode = 0644,             
  5.     },                    
  6.     .show   = wake_lock_show,             
  7.     .store  = wake_lock_store,        
  8. }  
  1. static struct kobj_attribute wake_unlock_attr = {     
  2.     .attr   = {               
  3.         .name = “wake_unlock”,    
  4.         .mode = 0644,             
  5.     },                    
  6.     .show   = wake_unlock_show,           
  7.     .store  = wake_unlock_store,          
  8. }  
show和store函数的源码位于kernel/power/userwakelock.c。
  1. static struct attribute * g[] = {  
  2.     &state_attr.attr,  
  3. #ifdef CONFIG_PM_TRACE  
  4.     &pm_trace_attr.attr,  
  5.     &pm_trace_dev_match_attr.attr,  
  6. #endif  
  7. #ifdef CONFIG_PM_SLEEP  
  8.     &pm_async_attr.attr,  
  9.     &wakeup_count_attr.attr,  
  10. #ifdef CONFIG_USER_WAKELOCK  
  11.     &wake_lock_attr.attr,  
  12.     &wake_unlock_attr.attr,  
  13. #endif  
  14. #ifdef CONFIG_PM_AUTOSLEEP  
  15.     &autosleep_attr.attr,  
  16. #endif  
  17. #ifdef CONFIG_PM_WAKELOCKS  
  18.     &wake_lock_attr.attr,  
  19.     &wake_unlock_attr.attr,  
  20. #endif  
  21. #ifdef CONFIG_PM_DEBUG  
  22.     &pm_test_attr.attr,  
  23. #endif  
  24. #ifdef CONFIG_PM_SLEEP_DEBUG  
  25.     &pm_print_times_attr.attr,  
  26. #endif  
  27. #endif  
  28. #ifdef CONFIG_FREEZER  
  29.     &pm_freeze_timeout_attr.attr,  
  30. #endif  
  31.     NULL,  
  32. };  
  1. static struct attribute_group attr_group = {  
  2.     .attrs = g,  
  3. };  
pm_init()->
error = sysfs_create_group(power_kobj, &attr_group);
好了,我们该回到原来我们产生疑问的地方了这时我们还得关注其中的另一个函数acquire_wake_lock()->initialize_fds()。
  1. initialize_fds(void)  
  2. {  
  3.     // XXX: should be this:  
  4.     //pthread_once(&g_initialized, open_file_descriptors);  
  5.     // XXX: not this:  
  6.     if (g_initialized == 0) {  
  7.         if(open_file_descriptors(NEW_PATHS) < 0)  
  8.             open_file_descriptors(OLD_PATHS);  
  9.         g_initialized = 1;  
  10.     }  
  11. }  

其实这个函数中最核心的步骤就是open_file_descriptors(NEW_PATHS),顺序打开NEW_PATHS[ ]中的文件:

  1. static int  
  2. open_file_descriptors(const char * const paths[])  
  3. {  
  4.     int i;  
  5.     for (i=0; i<OUR_FD_COUNT; i++) {  
  6.         int fd = open(paths[i], O_RDWR);  
  7.         if (fd < 0) {  
  8.             fprintf(stderr, "fatal error opening \"%s\"\n", paths[i]);  
  9.             g_error = errno;  
  10.             return -1;  
  11.         }  
  12.         g_fds[i] = fd;  
  13.     }  
  14.   
  15.     g_error = 0;  
  16.     return 0;  
  17. }  
  1. const char * const NEW_PATHS[] = {  
  2.     "/sys/power/wake_lock",  
  3.     "/sys/power/wake_unlock",  
  4. };  

总之经过着一系列的步骤后,最终我们将在 return write(fd, id, strlen(id));时调用android/kernel/kernel/power/userwakelock.c 中的 wake_lock_store()函数。

  1. ssize_t wake_lock_store(  
  2.     struct kobject *kobj, struct kobj_attribute *attr,  
  3.     const char *buf, size_t n)  
  4. {  
  5.     long timeout;  
  6.     struct user_wake_lock *l;  
  7.   
  8.     mutex_lock(&tree_lock);  
  9.     l = lookup_wake_lock_name(buf, 1, &timeout);  
  10.     if (IS_ERR(l)) {  
  11.         n = PTR_ERR(l);  
  12.         goto bad_name;  
  13.     }  
  14.   
  15.     if (debug_mask & DEBUG_ACCESS)  
  16.         pr_info("wake_lock_store: %s, timeout %ld\n", l->name, timeout);  
  17.   
  18.     if (timeout)  
  19.         wake_lock_timeout(&l->wake_lock, timeout);  
  20.     else  
  21.         wake_lock(&l->wake_lock);  
  22. bad_name:  
  23.     mutex_unlock(&tree_lock);  
  24.     return n;  
  25. }  
  1. struct rb_root user_wake_locks;  
  2. static struct user_wake_lock *lookup_wake_lock_name(  
  3.     const char *buf, int allocate, long *timeoutptr)  
  4. {  
  5.     struct rb_node **p = &user_wake_locks.rb_node;  
  6.     struct rb_node *parent = NULL;  
  7.     struct user_wake_lock *l;  
  8.     int diff;  
  9.     u64 timeout;  
  10.     int name_len;  
  11.     const char *arg;  
  12.   
  13.     /* Find length of lock name and start of optional timeout string */  
  14.     arg = buf;  
  15.     while (*arg && !isspace(*arg))  
  16.         arg++;  
  17. //lock name的长度  
  18.     name_len = arg - buf;  
  19.     if (!name_len)  
  20.         goto bad_arg;  
  21.     while (isspace(*arg))  
  22.         arg++;  
  23.   
  24.     /* Process timeout string */  
  25.     if (timeoutptr && *arg) {  
  26. //(char **)&arg存储的是解析string的结束字符  
  27.         timeout = simple_strtoull(arg, (char **)&arg, 0);  
  28.         while (isspace(*arg))  
  29.             arg++;  
  30. //如果解析string的结束字符不是’\0’  
  31.         if (*arg)  
  32.             goto bad_arg;  
  33.         /* convert timeout from nanoseconds to jiffies > 0 */  
  34.         timeout += (NSEC_PER_SEC / HZ) - 1;  
  35. //do_div(a,b)的返回值是余数,商保存到a中  
  36.         do_div(timeout, (NSEC_PER_SEC / HZ));  
  37.         if (timeout <= 0)  
  38.             timeout = 1;  
  39.         *timeoutptr = timeout;  
  40.     } else if (*arg)  
  41. //timeoutptr为NULL  
  42.         goto bad_arg;  
  43.     else if (timeoutptr)  
  44. //*arg为0,没有timeout  
  45.         *timeoutptr = 0;  
  46.   
  47.     /* Lookup wake lock in rbtree */  
  48. //对于一颗空的红黑树,略过while。wake lock按照name从小到大的顺序存储到user_wake_locks红黑树中  
  49.     while (*p) {  
  50.         parent = *p;  
  51.         l = rb_entry(parent, struct user_wake_lock, node);  
  52.         diff = strncmp(buf, l->name, name_len);  
  53. //如果buf是l->name的子串,那么l->name[name_len]就不会为0,但是buf[name_len]会为0  
  54.         if (!diff && l->name[name_len])  
  55.             diff = -1;  
  56.         if (debug_mask & DEBUG_ERROR)  
  57.             pr_info("lookup_wake_lock_name: compare %.*s %s %d\n",  
  58.                 name_len, buf, l->name, diff);  
  59.   
  60.         if (diff < 0)  
  61.             p = &(*p)->rb_left;  
  62.         else if (diff > 0)  
  63.             p = &(*p)->rb_right;  
  64.         else  
  65.             return l;  
  66.     }  
  67.   
  68.     /* Allocate and add new wakelock to rbtree */  
  69. //allocate为0,表示不需要分配新的wakelock,只在rbtree上查找,找不到就出错了  
  70.     if (!allocate) {  
  71.         if (debug_mask & DEBUG_ERROR)  
  72.             pr_info("lookup_wake_lock_name: %.*s not found\n",  
  73.                 name_len, buf);  
  74.         return ERR_PTR(-EINVAL);  
  75.     }  
  76.     l = kzalloc(sizeof(*l) + name_len + 1, GFP_KERNEL);  
  77.     if (l == NULL) {  
  78.         if (debug_mask & DEBUG_FAILURE)  
  79.             pr_err("lookup_wake_lock_name: failed to allocate "  
  80.                 "memory for %.*s\n", name_len, buf);  
  81.         return ERR_PTR(-ENOMEM);  
  82.     }  
  83.     memcpy(l->name, buf, name_len);  
  84.     if (debug_mask & DEBUG_NEW)  
  85.         pr_info("lookup_wake_lock_name: new wake lock %s\n", l->name);  
  86.     wake_lock_init(&l->wake_lock, WAKE_LOCK_SUSPEND, l->name);  
  87. //插入结点,并染成红色  
  88.     rb_link_node(&l->node, parent, p);  
  89.     rb_insert_color(&l->node, &user_wake_locks);  
  90.     return l;  
  91.   
  92. bad_arg:  
  93.     if (debug_mask & DEBUG_ERROR)  
  94.         pr_info("lookup_wake_lock_name: wake lock, %.*s, bad arg, %s\n",  
  95.             name_len, buf, arg);  
  96.     return ERR_PTR(-EINVAL);  
  97. }  

wake_lock_store()执行的基本流程为:首先调用lookup_wake_lock_name()来获得指定的唤醒锁,若延迟参数timeout为零的话,就调用 wake_lock()否则就调用wake_lock_timeout(),但不管调用哪个最后都会调用到android/kernel/kernel/power/wakelock.c中的函数static void wake_lock_internal()。

  1. static void wake_lock_internal(  
  2.     struct wake_lock *lock, long timeout, int has_timeout)  
  3. {  
  4.  int type;  
  5.    unsigned long irqflags;  
  6.  long expire_in;  
  7.   
  8.  spin_lock_irqsave(&list_lock, irqflags);  
  9.     type = lock->flags & WAKE_LOCK_TYPE_MASK;  
  10. //检查type是否合法  
  11.     BUG_ON(type >= WAKE_LOCK_TYPE_COUNT);  
  12. //检查是否初始化过  
  13.   BUG_ON(!(lock->flags & WAKE_LOCK_INITIALIZED));  
  14. #ifdef CONFIG_WAKELOCK_STAT  
  15.    if (type == WAKE_LOCK_SUSPEND && wait_for_wakeup) {  
  16.      if (debug_mask & DEBUG_WAKEUP)  
  17.           pr_info("wakeup wake lock: %s\n", lock->name);  
  18.        wait_for_wakeup = 0;  
  19.         lock->stat.wakeup_count++;  
  20.    }  
  21.    if ((lock->flags & WAKE_LOCK_AUTO_EXPIRE) &&  
  22.      (long)(lock->expires - jiffies) <= 0) {  
  23.        wake_unlock_stat_locked(lock, 0);  
  24.        lock->stat.last_time = ktime_get();  
  25.   }  
  26. #endif  
  27.  if (!(lock->flags & WAKE_LOCK_ACTIVE)) {  
  28.      lock->flags |= WAKE_LOCK_ACTIVE;  
  29. #ifdef CONFIG_WAKELOCK_STAT  
  30.       lock->stat.last_time = ktime_get();  
  31. #endif  
  32.     }  
  33. //从inactive_locks上删除  
  34.    list_del(&lock->link);  
  35.    if (has_timeout) {  
  36.       if (debug_mask & DEBUG_WAKE_LOCK)  
  37.            pr_info("wake_lock: %s, type %d, timeout %ld.%03lu\n",  
  38.               lock->name, type, timeout / HZ,  
  39.               (timeout % HZ) * MSEC_PER_SEC / HZ);  
  40.         lock->expires = jiffies + timeout;  
  41.        lock->flags |= WAKE_LOCK_AUTO_EXPIRE;  
  42.         list_add_tail(&lock->link, &active_wake_locks[type]);  
  43.     } else {  
  44.         if (debug_mask & DEBUG_WAKE_LOCK)  
  45.            pr_info("wake_lock: %s, type %d\n", lock->name, type);  
  46.        lock->expires = LONG_MAX;  
  47.         lock->flags &= ~WAKE_LOCK_AUTO_EXPIRE;  
  48.        list_add(&lock->link, &active_wake_locks[type]);  
  49.  }  
  50.    if (type == WAKE_LOCK_SUSPEND) {  
  51.         current_event_num++;  
  52. #ifdef CONFIG_WAKELOCK_STAT  
  53.      if (lock == &main_wake_lock)  
  54.             update_sleep_wait_stats_locked(1);  
  55.       else if (!wake_lock_active(&main_wake_lock))  
  56.             update_sleep_wait_stats_locked(0);  
  57. #endif  
  58.         if (has_timeout)  
  59.             expire_in = has_wake_lock_locked(type);  
  60.      else  
  61.             expire_in = -1;  
  62.      if (expire_in > 0) {  
  63.          if (debug_mask & DEBUG_EXPIRE)  
  64.               pr_info("wake_lock: %s, start expire timer, "  
  65.                    "%ld\n", lock->name, expire_in);  
  66.          mod_timer(&expire_timer, jiffies + expire_in);  
  67.       } else {  
  68.             if (del_timer(&expire_timer))  
  69.                if (debug_mask & DEBUG_EXPIRE)  
  70.                   pr_info("wake_lock: %s, stop expire timer\n",  
  71.                        lock->name);  
  72.          if (expire_in == 0)  
  73.              queue_work(suspend_work_queue, &suspend_work);  
  74.       }  
  75.    }  
  76.    spin_unlock_irqrestore(&list_lock, irqflags);  


//电源锁的使用

    /**
     * Updates the suspend blocker that keeps the CPU alive.
     *
     * This function must have no other side-effects.
     */
    private void updateSuspendBlockerLocked() {
        final boolean needWakeLockSuspendBlocker = ((mWakeLockSummary & WAKE_LOCK_CPU) != 0);
        final boolean needDisplaySuspendBlocker = needDisplaySuspendBlocker();

        // First acquire suspend blockers if needed.
        if (needWakeLockSuspendBlocker && !mHoldingWakeLockSuspendBlocker) {
            mWakeLockSuspendBlocker.acquire();
            mHoldingWakeLockSuspendBlocker = true;
        }
        if (needDisplaySuspendBlocker && !mHoldingDisplaySuspendBlocker) {
            mDisplaySuspendBlocker.acquire();
            mHoldingDisplaySuspendBlocker = true;
        }

        // Then release suspend blockers if needed.
        if (!needWakeLockSuspendBlocker && mHoldingWakeLockSuspendBlocker) {
            mWakeLockSuspendBlocker.release();
            mHoldingWakeLockSuspendBlocker = false;
        }
        if (!needDisplaySuspendBlocker && mHoldingDisplaySuspendBlocker) {
            mDisplaySuspendBlocker.release();
            mHoldingDisplaySuspendBlocker = false;
        }
    }



//判断是否处于亮屏或者正在变化阶段

    private boolean needDisplaySuspendBlocker() {

        //正处于变化阶段
        if (!mDisplayReady) {
            return true;
        }
        if (mDisplayPowerRequest.screenState != DisplayPowerRequest.SCREEN_STATE_OFF) {

            //有疑问?
            // If we asked for the screen to be on but it is off due to the proximity
            // sensor then we may suspend but only if the configuration allows it.
            // On some hardware it may not be safe to suspend because the proximity
            // sensor may not be correctly configured as a wake-up source.
            if (!mDisplayPowerRequest.useProximitySensor || !mProximityPositive
                    || !mSuspendWhenScreenOffDueToProximityConfig) {
                return true;
            }
        }
        return false;
    }

;