Android休眠唤醒机制简介(二)
Android休眠唤醒机制简介(二)
******************************************************************
作者:sean
日期:2012-11-29
修改历史:2014-1
******************************************************************
接上一节,结合code来分析一下:
具体流程
下面我将分别以两条路线(第一:获得wakelock唤醒锁。第二:系统进入睡眠。)来分别说明各自的流程,让读者对android睡眠唤醒机制有更深入的理解!第一部分:获得wakelock唤醒锁
比如在应用程序中,当获得wakelock唤醒锁的时候,它首先是调用frameworks/base/core/java/android/os/PowerManager.java类中的public void acquire()方法,而该方法通过android特有的通讯机制,会接着调用到PowerManagerService类中的public void acquireWakeLock。
public void acquire() { synchronized (mToken) { acquireLocked(); } }
private void acquireLocked() { if (!mRefCounted || mCount++ == 0) { // Do this even if the wake lock is already thought to be held (mHeld == true) // because non-reference counted wake locks are not always properly released. // For example, the keyguard's wake lock might be forcibly released by the // power manager without the keyguard knowing. A subsequent call to acquire // should immediately acquire the wake lock once again despite never having // been explicitly released by the keyguard. mHandler.removeCallbacks(mReleaser); try { mService.acquireWakeLock(mToken, mFlags, mTag, mPackageName, mWorkSource); } catch (RemoteException e) { } mHeld = true; } }
@Override // Binder call public void acquireWakeLock(IBinder lock, int flags, String tag, String packageName, WorkSource ws) { if (lock == null) { throw new IllegalArgumentException("lock must not be null"); } if (packageName == null) { throw new IllegalArgumentException("packageName must not be null"); } PowerManager.validateWakeLockParameters(flags, tag); mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null); if (ws != null && ws.size() != 0) { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.UPDATE_DEVICE_STATS, null); } else { ws = null; } final int uid = Binder.getCallingUid(); final int pid = Binder.getCallingPid(); final long ident = Binder.clearCallingIdentity(); try { acquireWakeLockInternal(lock, flags, tag, packageName, ws, uid, pid); } finally { Binder.restoreCallingIdentity(ident); } }
acquireWakeLockInternal()->updatePowerStateLocked()->updateSuspendBlockerLocked()->
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; } }acquire()是什么函数?需要看一下frameworks/base/services/java/com/android/server/PowerManagerService.java类的构造过程。
public PowerManagerService() { synchronized (mLock) { mWakeLockSuspendBlocker = createSuspendBlockerLocked("PowerManagerService.WakeLocks"); mDisplaySuspendBlocker = createSuspendBlockerLocked("PowerManagerService.Display"); mDisplaySuspendBlocker.acquire(); mHoldingDisplaySuspendBlocker = true; mScreenOnBlocker = new ScreenOnBlockerImpl(); mDisplayBlanker = new DisplayBlankerImpl(); mWakefulness = WAKEFULNESS_AWAKE; } nativeInit(); nativeSetPowerState(true, true); }
private SuspendBlocker createSuspendBlockerLocked(String name) { SuspendBlocker suspendBlocker = new SuspendBlockerImpl(name); mSuspendBlockers.add(suspendBlocker); return suspendBlocker; }
于是frameworks/base/services/java/com/android/server/PowerManagerService.java类的SuspendBlockerImpl类中的acquire(),便是我们要找的acquire()。
@Override public void acquire() { synchronized (this) { mReferenceCount += 1; if (mReferenceCount == 1) { if (DEBUG_SPEW) { Slog.d(TAG, "Acquiring suspend blocker \"" + mName + "\"."); } nativeAcquireSuspendBlocker(mName); } } }而该方法调用了com_android_server_power_PowerManagerService.cpp中的nativeAcquireSuspendBlocker。
static JNINativeMethod gPowerManagerServiceMethods[] = { /* name, signature, funcPtr */ { "nativeInit", "()V", (void*) nativeInit }, { "nativeSetPowerState", "(ZZ)V", (void*) nativeSetPowerState }, { "nativeAcquireSuspendBlocker", "(Ljava/lang/String;)V", (void*) nativeAcquireSuspendBlocker }, { "nativeReleaseSuspendBlocker", "(Ljava/lang/String;)V", (void*) nativeReleaseSuspendBlocker }, { "nativeSetInteractive", "(Z)V", (void*) nativeSetInteractive }, { "nativeSetAutoSuspend", "(Z)V", (void*) nativeSetAutoSuspend },};
static void nativeAcquireSuspendBlocker(JNIEnv *env, jclass clazz, jstring nameStr) { ScopedUtfChars name(env, nameStr); acquire_wake_lock(PARTIAL_WAKE_LOCK, name.c_str());}函数 acquire_wake_lock()的实现在 power.c中,其定义如下:
intacquire_wake_lock(int lock, const char* id){ initialize_fds();// ALOGI("acquire_wake_lock lock=%d id='%s'\n", lock, id); 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));}到现在为止,我们的代码流程已经走了一大半了,我们一开始介绍的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宏很多地方用到:
#define power_attr(_name) \static struct kobj_attribute _name##_attr = {\.attr= {\.name = __stringify(_name),\.mode = 0644,\},\.show= _name##_show,\.store= _name##_store,\}
#ifdef CONFIG_USER_WAKELOCKpower_attr(wake_lock);power_attr(wake_unlock);#endifdefault 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.
#ifdef CONFIG_PM_WAKELOCKSpower_attr(wake_lock);power_attr(wake_unlock);#endifdefault n
Allow user space to create, activate and deactivate wakeup source
objects with the help of a sysfs-based interface.
宏展开,等价于:
static struct kobj_attribute wake_lock_attr = {.attr= {.name = “wake_lock”,.mode = 0644,},.show= wake_lock_show,.store= wake_lock_store,}
static struct kobj_attribute wake_unlock_attr = {.attr= {.name = “wake_unlock”,.mode = 0644,},.show= wake_unlock_show,.store= wake_unlock_store,}show和store函数的源码位于kernel/power/userwakelock.c。
static struct attribute * g[] = {&state_attr.attr,#ifdef CONFIG_PM_TRACE&pm_trace_attr.attr,&pm_trace_dev_match_attr.attr,#endif#ifdef CONFIG_PM_SLEEP&pm_async_attr.attr,&wakeup_count_attr.attr,#ifdef CONFIG_USER_WAKELOCK&wake_lock_attr.attr,&wake_unlock_attr.attr,#endif#ifdef CONFIG_PM_AUTOSLEEP&autosleep_attr.attr,#endif#ifdef CONFIG_PM_WAKELOCKS&wake_lock_attr.attr,&wake_unlock_attr.attr,#endif#ifdef CONFIG_PM_DEBUG&pm_test_attr.attr,#endif#ifdef CONFIG_PM_SLEEP_DEBUG&pm_print_times_attr.attr,#endif#endif#ifdef CONFIG_FREEZER&pm_freeze_timeout_attr.attr,#endifNULL,};
static struct attribute_group attr_group = {.attrs = g,};pm_init()->
error = sysfs_create_group(power_kobj, &attr_group);
好了,我们该回到原来我们产生疑问的地方了这时我们还得关注其中的另一个函数acquire_wake_lock()->initialize_fds()。
initialize_fds(void){ // XXX: should be this: //pthread_once(&g_initialized, open_file_descriptors); // XXX: not this: if (g_initialized == 0) { if(open_file_descriptors(NEW_PATHS) < 0) open_file_descriptors(OLD_PATHS); g_initialized = 1; }}
其实这个函数中最核心的步骤就是open_file_descriptors(NEW_PATHS),顺序打开NEW_PATHS[ ]中的文件:
static intopen_file_descriptors(const char * const paths[]){ int i; for (i=0; i<OUR_FD_COUNT; i++) { int fd = open(paths[i], O_RDWR); if (fd < 0) { fprintf(stderr, "fatal error opening \"%s\"\n", paths[i]); g_error = errno; return -1; } g_fds[i] = fd; } g_error = 0; return 0;}
const char * const NEW_PATHS[] = { "/sys/power/wake_lock", "/sys/power/wake_unlock",};
总之经过着一系列的步骤后,最终我们将在 return write(fd, id, strlen(id));时调用android/kernel/kernel/power/userwakelock.c 中的 wake_lock_store()函数。
ssize_t wake_lock_store( struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t n){ long timeout; struct user_wake_lock *l; mutex_lock(&tree_lock); l = lookup_wake_lock_name(buf, 1, &timeout); if (IS_ERR(l)) { n = PTR_ERR(l); goto bad_name; } if (debug_mask & DEBUG_ACCESS) pr_info("wake_lock_store: %s, timeout %ld\n", l->name, timeout); if (timeout) wake_lock_timeout(&l->wake_lock, timeout); else wake_lock(&l->wake_lock);bad_name: mutex_unlock(&tree_lock); return n;}
struct rb_root user_wake_locks;static struct user_wake_lock *lookup_wake_lock_name( const char *buf, int allocate, long *timeoutptr){ struct rb_node **p = &user_wake_locks.rb_node; struct rb_node *parent = NULL; struct user_wake_lock *l; int diff; u64 timeout; int name_len; const char *arg; /* Find length of lock name and start of optional timeout string */ arg = buf; while (*arg && !isspace(*arg)) arg++;//lock name的长度 name_len = arg - buf; if (!name_len) goto bad_arg; while (isspace(*arg)) arg++; /* Process timeout string */ if (timeoutptr && *arg) {//(char **)&arg存储的是解析string的结束字符 timeout = simple_strtoull(arg, (char **)&arg, 0); while (isspace(*arg)) arg++;//如果解析string的结束字符不是’\0’ if (*arg) goto bad_arg; /* convert timeout from nanoseconds to jiffies > 0 */ timeout += (NSEC_PER_SEC / HZ) - 1;//do_div(a,b)的返回值是余数,商保存到a中 do_div(timeout, (NSEC_PER_SEC / HZ)); if (timeout <= 0) timeout = 1; *timeoutptr = timeout; } else if (*arg)//timeoutptr为NULL goto bad_arg; else if (timeoutptr)//*arg为0,没有timeout *timeoutptr = 0; /* Lookup wake lock in rbtree *///对于一颗空的红黑树,略过while。wake lock按照name从小到大的顺序存储到user_wake_locks红黑树中 while (*p) { parent = *p; l = rb_entry(parent, struct user_wake_lock, node); diff = strncmp(buf, l->name, name_len);//如果buf是l->name的子串,那么l->name[name_len]就不会为0,但是diff会为0 if (!diff && l->name[name_len]) diff = -1; if (debug_mask & DEBUG_ERROR) pr_info("lookup_wake_lock_name: compare %.*s %s %d\n", name_len, buf, l->name, diff); if (diff < 0) p = &(*p)->rb_left; else if (diff > 0) p = &(*p)->rb_right; else return l; } /* Allocate and add new wakelock to rbtree *///allocate为0,表示不需要分配新的wakelock,只在rbtree上查找,找不到就出错了 if (!allocate) { if (debug_mask & DEBUG_ERROR) pr_info("lookup_wake_lock_name: %.*s not found\n", name_len, buf); return ERR_PTR(-EINVAL); } l = kzalloc(sizeof(*l) + name_len + 1, GFP_KERNEL); if (l == NULL) { if (debug_mask & DEBUG_FAILURE) pr_err("lookup_wake_lock_name: failed to allocate " "memory for %.*s\n", name_len, buf); return ERR_PTR(-ENOMEM); } memcpy(l->name, buf, name_len); if (debug_mask & DEBUG_NEW) pr_info("lookup_wake_lock_name: new wake lock %s\n", l->name); wake_lock_init(&l->wake_lock, WAKE_LOCK_SUSPEND, l->name);//插入结点,并染成红色 rb_link_node(&l->node, parent, p); rb_insert_color(&l->node, &user_wake_locks); return l;bad_arg: if (debug_mask & DEBUG_ERROR) pr_info("lookup_wake_lock_name: wake lock, %.*s, bad arg, %s\n", name_len, buf, arg); return ERR_PTR(-EINVAL);}
wake_lock_store()执行的基本流程为:首先调用lookup_wake_lock_name()来获得指定的唤醒锁,若延迟参数timeout为零的话,就调用 wake_lock()否则就调用wake_lock_timeout(),但不管调用哪个最后都会调用到android/kernel/kernel/power/wakelock.c中的函数static void wake_lock_internal()。
static void wake_lock_internal( struct wake_lock *lock, long timeout, int has_timeout){ int type; unsigned long irqflags; long expire_in; spin_lock_irqsave(&list_lock, irqflags); type = lock->flags & WAKE_LOCK_TYPE_MASK;//检查type是否合法 BUG_ON(type >= WAKE_LOCK_TYPE_COUNT);//检查是否初始化过 BUG_ON(!(lock->flags & WAKE_LOCK_INITIALIZED));#ifdef CONFIG_WAKELOCK_STAT if (type == WAKE_LOCK_SUSPEND && wait_for_wakeup) { if (debug_mask & DEBUG_WAKEUP) pr_info("wakeup wake lock: %s\n", lock->name); wait_for_wakeup = 0; lock->stat.wakeup_count++; } if ((lock->flags & WAKE_LOCK_AUTO_EXPIRE) && (long)(lock->expires - jiffies) <= 0) { wake_unlock_stat_locked(lock, 0); lock->stat.last_time = ktime_get(); }#endif if (!(lock->flags & WAKE_LOCK_ACTIVE)) { lock->flags |= WAKE_LOCK_ACTIVE;#ifdef CONFIG_WAKELOCK_STAT lock->stat.last_time = ktime_get();#endif }//从inactive_locks上删除 list_del(&lock->link); if (has_timeout) { if (debug_mask & DEBUG_WAKE_LOCK) pr_info("wake_lock: %s, type %d, timeout %ld.%03lu\n", lock->name, type, timeout / HZ, (timeout % HZ) * MSEC_PER_SEC / HZ); lock->expires = jiffies + timeout; lock->flags |= WAKE_LOCK_AUTO_EXPIRE; list_add_tail(&lock->link, &active_wake_locks[type]); } else { if (debug_mask & DEBUG_WAKE_LOCK) pr_info("wake_lock: %s, type %d\n", lock->name, type); lock->expires = LONG_MAX; lock->flags &= ~WAKE_LOCK_AUTO_EXPIRE; list_add(&lock->link, &active_wake_locks[type]); } if (type == WAKE_LOCK_SUSPEND) { current_event_num++;#ifdef CONFIG_WAKELOCK_STAT if (lock == &main_wake_lock) update_sleep_wait_stats_locked(1); else if (!wake_lock_active(&main_wake_lock)) update_sleep_wait_stats_locked(0);#endif if (has_timeout) expire_in = has_wake_lock_locked(type); else expire_in = -1; if (expire_in > 0) { if (debug_mask & DEBUG_EXPIRE) pr_info("wake_lock: %s, start expire timer, " "%ld\n", lock->name, expire_in); mod_timer(&expire_timer, jiffies + expire_in); } else { if (del_timer(&expire_timer)) if (debug_mask & DEBUG_EXPIRE) pr_info("wake_lock: %s, stop expire timer\n", lock->name); if (expire_in == 0) queue_work(suspend_work_queue, &suspend_work); } } spin_unlock_irqrestore(&list_lock, irqflags);}
第二部分:系统进入睡眠
假如现在我们按了PAD上的power睡眠键,经过一些列的事件处理后,它会调用到PowerManager类中的public void goToSleep(long time) { try { mService.goToSleep(time, GO_TO_SLEEP_REASON_USER); } catch (RemoteException e) { } }而该函数会调用到PowerManagerService类中的public void goToSleep()方法;
@Override // Binder call public void goToSleep(long eventTime, int reason) { if (eventTime > SystemClock.uptimeMillis()) { throw new IllegalArgumentException("event time must not be in the future"); } mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null); final long ident = Binder.clearCallingIdentity(); try { goToSleepInternal(eventTime, reason); } finally { Binder.restoreCallingIdentity(ident); } }
private void goToSleepInternal(long eventTime, int reason) { synchronized (mLock) { if (goToSleepNoUpdateLocked(eventTime, reason)) { updatePowerStateLocked(); } } }goToSleepNoUpdateLocked是goToSleep功能的计算者,来决定是否要休眠,而updatePowerStateLocked函数算是功能的执行者,而且这个执行者同时负责执行了很多其他的功能。其实goToSleepNoUpdateLocked并没有真正地让device进行sleep,仅仅只是把PowerManagerService中一些必要的属性进行了赋值,等会在分析updatePowerStateLocked的时候,再给出解释。在PowerManagerService的代码中,有很多的方法的名字中都含有xxxNoUpdateLocked这样的后缀,我觉得这样做大概是因为,都类似于goToSleepNoUpdateLocked方法,并没有真正地执行方法名字所描述的功能,仅仅是更新了一些必要的属性。 所以在Android系统中可以把多个power state属性的多个变化放在一起共同执行的,而真正的功能执行者就是updatePowerStateLocked。
private void updatePowerStateLocked() { if (!mSystemReady || mDirty == 0) {//如果系统没有准备好,或者power state没有发生任何变化,这个方法可以不用执行的 return; } if(!SystemProperties.getBoolean("ro.platform.has.mbxuimode", false)) { if (isHdmiPlugged()) { return; } } // Phase 0: Basic state updates. updateIsPoweredLocked(mDirty); updateStayOnLocked(mDirty); // Phase 1: Update wakefulness. // Loop because the wake lock and user activity computations are influenced // by changes in wakefulness. final long now = SystemClock.uptimeMillis(); int dirtyPhase2 = 0; for (;;) { int dirtyPhase1 = mDirty; dirtyPhase2 |= dirtyPhase1; mDirty = 0; updateWakeLockSummaryLocked(dirtyPhase1); updateUserActivitySummaryLocked(now, dirtyPhase1); if (!updateWakefulnessLocked(dirtyPhase1)) { break; } } // Phase 2: Update dreams and display power state. updateDreamLocked(dirtyPhase2); updateDisplayPowerStateLocked(dirtyPhase2); // Phase 3: Send notifications, if needed. if (mDisplayReady) { sendPendingNotificationsLocked(); } // Phase 4: Update suspend blocker. // Because we might release the last suspend blocker here, we need to make sure // we finished everything else first! updateSuspendBlockerLocked(); }对sys/power/state进行读写操作的时候,(linux/kernel/power/main.c)中的state_store()函数会被调用,在该函数中会分成两个分支:
Android特有的earlysuspend: request_suspend_state(state)
Linux标准的suspend: enter_state(state)
更多相关文章
- android调用系统程序
- Android学习札记17:ImageView中的setImageBitmap()方法
- android输入法全屏问题
- android 去掉listview之间的黑线
- Android(安卓)Webview播放HTML5 video的一个思路
- Java中的instanceof关键字在Android中的用法
- Android(安卓)java.lang.IllegalArgumentException: pointerInde
- Android:解决列表滚动时背景色变黑的方法
- 2014.04.21 ——— android 魅族SmartBar判断