Android休眠唤醒机制简介(二)
本文转载自:http://blog.csdn.net/zhaoxiaoqiang10_/article/details/24408911
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;
- }
- }
- 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());
- }
- int
- acquire_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/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_WAKELOCK
- power_attr(wake_lock);
- power_attr(wake_unlock);
- #endif
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_WAKELOCKS
- power_attr(wake_lock);
- power_attr(wake_unlock);
- #endif
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,
- }
- 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,
- #endif
- NULL,
- };
- static struct attribute_group attr_group = {
- .attrs = g,
- };
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 int
- open_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,但是buf[name_len]会为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) {
- }
- }
- @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();
- }
- }
- }
- 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();
- }
Android特有的earlysuspend: request_suspend_state(state)
Linux标准的suspend: enter_state(state)
- 顶
- 0
- 踩