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

2019-07-14 00:36发布


//创建电源锁 [cpp] view plaincopy在CODE上查看代码片派生到我的代码片 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;
    } //电源锁操作类的实现 [cpp] view plaincopy在CODE上查看代码片派生到我的代码片

    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层函数实现电源锁的获取 [cpp] view plaincopy在CODE上查看代码片派生到我的代码片 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 [cpp] view plaincopy在CODE上查看代码片派生到我的代码片 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));
} //打开记录电源锁的文件 [cpp] view plaincopy在CODE上查看代码片派生到我的代码片
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;
    }
}
//记录电源锁的文件路径 [cpp] view plaincopy在CODE上查看代码片派生到我的代码片

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宏很多地方用到:
[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  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. }  
[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  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.
[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  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.
宏展开,等价于:
[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  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. }  
[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  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。
[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  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. };  
[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  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()。 [cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  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[ ]中的文件: [cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. static int  
  2. open_file_descriptors(const char * const paths[])  
  3. {  
  4.     int i;  
  5.     for (i=0; i
  6.         int fd = open(paths[i], O_RDWR);  
  7.         if (fd < 0) {  
  8.             fprintf(stderr, "fatal error opening "%s" ", 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. }  
[cpp] view plaincopy
  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()函数。
[cpp] view plaincopy
  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 ", 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. }  
[cpp] view plaincopy
  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的结束字符不是’