Android 待机功能流程分析
Android智能手机或机顶盒子为了进入省电模式、所以就需要有待机功能。
PowerManager.java 类提供了如下的电源管理功能:
public void goToSleep(long time) 强迫设备进入睡眠状态
public void reboot(String reason) 重启设备
提供了内部类: public final class WakeLock
public void acquire(long timeout)申请待机锁
public void release(int flags) 释放待机锁
我这里讲的主要是:
利用Linux内核原有的睡眠唤醒模块上基础上,在Android系统上主要增加了下面三个机制:
• 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 解锁,系统即可进入睡眠状态。
先看一下整体流程层次结构图:
下面按照层次结构从java层分析:
frameworks/base/core/java/android/os/PowerManager.java
@public final class WakeLock 内部类
获取待机锁:
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, mWorkSource); } catch (RemoteException e) { } mHeld = true; } }
以上代码很清楚,判定标志mRefCounted 为false 或mCount 值为0即可进入获取待机锁、并将mCount加1
此时调用mService.acquireWakeLock(mToken, mFlags, mTag, mWorkSource);
mService 就是PowerManagerService 类
frameworks/base/services/java/com/android/server/PowerManagerService.java
@acquireWakeLock ->acquireWakeLockInternal ->updatePowerStateLocked
重要的操作都在这里做的,五个步骤
private void updatePowerStateLocked() { if (!mSystemReady || mDirty == 0) { 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(); }
最后一个方法updateSuspendBlockerLocked() 将会调用native方法
@mWakeLockSuspendBlocker.acquire(); ->nativeAcquireSuspendBlocker
private static native void nativeAcquireSuspendBlocker(String name);
此时将进入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()); }
实现相当简单、不解释了。
hardware/libhardware_legacy/power/power.c
int acquire_wake_lock(int lock, const char* id) { initialize_fds(); // 打开句柄 open("/sys/power/wake_lock") 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)); // 写入命令 }
此时将进入内核代码分析是如何做的。
kernel/power/main.c - PM subsystem core functionality.
static ssize_t wake_lock_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t n) { int error = pm_wake_lock(buf); return error ? error : n; }
kernel/power/wakelock.c
int pm_wake_lock(const char *buf) { const char *str = buf; struct wakelock *wl; u64 timeout_ns = 0; size_t len; int ret = 0; while (*str && !isspace(*str)) str++; len = str - buf; if (!len) return -EINVAL; if (*str && *str != '\n') { /* Find out if there's a valid timeout string appended. */ ret = kstrtou64(skip_spaces(str), 10, &timeout_ns); if (ret) return -EINVAL; } mutex_lock(&wakelocks_lock); wl = wakelock_lookup_add(buf, len, true); if (IS_ERR(wl)) { ret = PTR_ERR(wl); goto out; } if (timeout_ns) { u64 timeout_ms = timeout_ns + NSEC_PER_MSEC - 1; do_div(timeout_ms, NSEC_PER_MSEC); __pm_wakeup_event(&wl->ws, timeout_ms); } else { __pm_stay_awake(&wl->ws); } wakelocks_lru_most_recent(wl); out: mutex_unlock(&wakelocks_lock); return ret; }
这块没有细看、有兴趣的朋友可以看看。本质就是利用红黑树查看锁的情况,最后该函数首先sync文件系统,然后调用pm_suspend(request_suspend_state),接下来pm_suspend()就会调用 enter_state()来进入 linux的suspend流程。
机顶盒的资源也可以实现待机函数、这样子即可快速进入待机模式。
释放待机锁的流程与获取待机锁差不多就不多说了。
最后说明一下:
WakeLock 类型以及说明:
PARTIAL_WAKE_LOCK:保持CPU 运转,屏幕和键盘灯有可能是关闭的。
SCREEN_DIM_WAKE_LOCK:保持CPU 运转,允许保持屏幕显示但有可能是灰的,允许关闭键盘灯
SCREEN_BRIGHT_WAKE_LOCK:保持CPU 运转,允许保持屏幕高亮显示,允许关闭键盘灯
FULL_WAKE_LOCK:保持CPU 运转,保持屏幕高亮显示,键盘灯也保持亮度
ACQUIRE_CAUSES_WAKEUP:强制使屏幕亮起,这种锁主要针对一些必须通知用户的操作.
ON_AFTER_RELEASE:当锁被释放时,保持屏幕亮起一段时间
最后 AndroidManifest.xml 声明权限:
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.DEVICE_POWER"/>
应用程序中如果要在待机前保存数据状态的话,要保证此过程中不会进入待机。可以在 onResume() 或者 onStart() 中申请 wakelock 锁,即调用acquireWakeLock()方法。
在 onPause() 或者 onDistroy() 中处理应用待机后再释放掉 wakelock 锁,此时调用releaseWakeLock()方法
最后一点需要注意下:
另外WakeLock的设置是 Activiy 级别的,不是针对整个Application应用的。所以application下有多个activity一定需要注意下!
更多相关文章
- android调用系统通讯录,并返回联系人号码和称呼
- 做自己的Android ROM,屏蔽对framework中的系统APK的签名检查
- Android系统启动流程 -- android
- Android 通过Volley 模拟登录教务系统 出错,出错原因:系统正忙
- Android_照相机Camera_调用系统照…
- 尝试在安卓系统中获得USSD响应
- android手机联网时会有什么系统广播发出呢??
- [置顶] Android系统的样式style
- Android实现一键复制粘贴,兼容低版本系统(api 11以下)