该系列文章总纲链接:专题分纲目录 Android Framework 电源子系统
本章关键点总结 & 说明:
本章节主要关注➕ 系统休眠 wakeLock 部分 即可。该章节 主要是 对wakelock机制中acquire和release的实现流程分析,其中native部分的一些实现是在PMS中进行说明的。
android系统的休眠唤醒主要是 使用了WakeLock锁,WakeLock是一种上锁机制。只要有应用拿着这个锁,CPU就无法进入休眠状态,一直处于工作状态。比如,手机屏幕在屏幕关闭的时候,有些应用依然可以唤醒屏幕提示用户消息,这里就是用到了wakelock锁机制,虽然手机屏幕关闭了,但是这些应用依然在运行着。当持有WakeLock锁时,系统就无法睡眠,同时WakeLock锁可以设置超时,超时后会自动解锁。
1 wakeLock锁使用简介
一个普通应用使用wakelock的方式如下所示:
WakeLock wakeLock = null;
//获取电源锁,保持该服务在屏幕熄灭时仍然获取CPU时,保持运行
private void acquireWakeLock()
{
if (null == wakeLock)
{
PowerManager pm = (PowerManager)this.getSystemService(Context.POWER_SERVICE);
wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK|PowerManager.ON_AFTER_RELEASE, "PostLocationService");
if (null != wakeLock)
{
wakeLock.acquire();
}
}
}
//释放设备电源锁
private void releaseWakeLock()
{
if (null != wakeLock)
{
wakeLock.release();
wakeLock = null;
}
}
首先是通过getSystemService获取pm代理,之后使用pm的newWakeLock方法创建一个新的wakelock锁对象,当执行wakelock的require方法时,就保持应用一直运行;当执行release方法时,就释放掉该锁。
2 获取WakeLock接口{require和release接口说明}
pm代理类的require和release接口实现如下:
//acquire 2个接口实现
public void acquire() {
synchronized (mToken) {
acquireLocked();
}
}
public void acquire(long timeout) {
synchronized (mToken) {
acquireLocked();
mHandler.postDelayed(mReleaser, timeout);
}
}
//release 2个接口实现
public void release() {
release(0);
}
public void release(int flags) {
synchronized (mToken) {
if (!mRefCounted || --mCount == 0) {
mHandler.removeCallbacks(mReleaser);
if (mHeld) {
try {
mService.releaseWakeLock(mToken, flags);
} catch (RemoteException e) {
}
mHeld = false;
}
}
//...
}
}
这里的acquire接口均调用了acquireLocked方法,实现如下:
private void acquireLocked() {
if (!mRefCounted || mCount++ == 0) {
mHandler.removeCallbacks(mReleaser);
try {
mService.acquireWakeLock(mToken, mFlags, mTag, mPackageName, mWorkSource,
mHistoryTag);
} catch (RemoteException e) {
}
mHeld = true;
}
}
综上,pm代理类的require和release接口最终调用了PMS的acquireWakeLock和releaseWakeLock方法;相关代码实现如下:
@Override // Binder call
public void acquireWakeLock(IBinder lock, int flags, String tag, String packageName,
WorkSource ws, String historyTag) {
//...
PowerManager.validateWakeLockParameters(flags, tag);
//...权限处理相关
try {
acquireWakeLockInternal(lock, flags, tag, packageName, ws, historyTag, uid, pid);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
@Override // Binder call
public void releaseWakeLock(IBinder lock, int flags) {
//...
final long ident = Binder.clearCallingIdentity();
try {
releaseWakeLockInternal(lock, flags);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
这里分别调用了PMS的acquireWakeLockInternal和releaseWakeLockInternal方法,这里开始分开解读
@1 acquireWakeLockInternal分析
代码实现如下:
private void acquireWakeLockInternal(IBinder lock, int flags, String tag, String packageName,
WorkSource ws, String historyTag, int uid, int pid) {
synchronized (mLock) {
WakeLock wakeLock;
//检查lock是否存在
int index = findWakeLockIndexLocked(lock);
boolean notifyAcquire;
if (index >= 0) {//lock已经存在
wakeLock = mWakeLocks.get(index);
if (!wakeLock.hasSameProperties(flags, tag, ws, uid, pid)) {
// Update existing wake lock. This shouldn't happen but is harmless.
notifyWakeLockChangingLocked(wakeLock, flags, tag, packageName,
uid, pid, ws, historyTag);
wakeLock.updateProperties(flags, tag, packageName, ws, historyTag, uid, pid);
}
notifyAcquire = false;
} else {//创建新的wakelock
wakeLock = new WakeLock(lock, flags, tag, packageName, ws, historyTag, uid, pid);
try {
lock.linkToDeath(wakeLock, 0);
} catch (RemoteException ex) {
throw new IllegalArgumentException("Wake lock is already dead.");
}
//将新的wakeLock加入到mWakeLocks中
//注意:该列表包含了系统中所有的wakeLock
mWakeLocks.add(wakeLock);
notifyAcquire = true;
}
applyWakeLockFlagsOnAcquireLocked(wakeLock, uid);
mDirty |= DIRTY_WAKE_LOCKS;
updatePowerStateLocked();
if (notifyAcquire) {
notifyWakeLockAcquiredLocked(wakeLock);
}
}
}
继续分析applyWakeLockFlagsOnAcquireLocked,代码实现如下:
private void applyWakeLockFlagsOnAcquireLocked(WakeLock wakeLock, int uid) {
if ((wakeLock.mFlags & PowerManager.ACQUIRE_CAUSES_WAKEUP) != 0
&& isScreenLock(wakeLock)) {
wakeUpNoUpdateLocked(SystemClock.uptimeMillis(), uid);
}
}
这里继续分析wakeUpNoUpdateLocked,代码实现如下:
private boolean wakeUpNoUpdateLocked(long eventTime, int uid) {
if (eventTime < mLastSleepTime || mWakefulness == WAKEFULNESS_AWAKE
|| !mBootCompleted || !mSystemReady) {
return false;
}
try {
//...
mLastWakeTime = eventTime;
/*更新成员变量
mLastUserActivityTimeNoChangeLights
mLastUserActivityTime
mDirty
*/
setWakefulnessLocked(WAKEFULNESS_AWAKE, 0);
//更新成员变量mLastUserActivityTime的值
userActivityNoUpdateLocked(
eventTime, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, uid);
} finally {
//...
}
return true;
}
@2 releaseWakeLockInternal分析
代码实现如下:
private void releaseWakeLockInternal(IBinder lock, int flags) {
synchronized (mLock) {
//检查lock是否存在
int index = findWakeLockIndexLocked(lock);
if (index < 0) {
return;
}
//通过索引获取对应的wakeLock
WakeLock wakeLock = mWakeLocks.get(index);
if ((flags & PowerManager.RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY) != 0) {
mRequestWaitForNegativeProximity = true;
}
wakeLock.mLock.unlinkToDeath(wakeLock, 0);
//将其从链表mWakeLocks中移除
removeWakeLockLocked(wakeLock, index);
}
}
这里继续分析removeWakeLockLocked,代码实现如下:
private void removeWakeLockLocked(WakeLock wakeLock, int index) {
mWakeLocks.remove(index);
notifyWakeLockReleasedLocked(wakeLock);
applyWakeLockFlagsOnReleaseLocked(wakeLock);
mDirty |= DIRTY_WAKE_LOCKS;
updatePowerStateLocked();
}
这里一共做了这样几件事情:
- 将传递进来的wakelock从链表mWakeLocks中移除并发出通知。
- 更新成员变量mLastUserActivityTime的值为当前时间,休眠时间到,系统会自动休眠。
- 调用关键方法updatePowerStateLocked()。
3 WakeLock native层实现
见上一节 createSuspendBlockerLocked分析 部分 SuspendBlockerImpl的acquire方法和release方法的实现。实际上在 PowerManagerService中 创建了两个wakeLock,分别是 PowerManagerService.WakeLocks 和 PowerManagerService.Display
特殊说明:
Android防止系统休眠的方式是通过向设备节点"/sys/power/wake_lock"写入数据
- 如果写的是PowerManagerService.WakeLocks,系统将不能休眠,但屏幕会关闭
- 如果写的是PowerManagerService.Display,系统将不能休眠,同时屏幕也不会关闭
如果系统要恢复休眠,则向"/sys/power/wake_unlock"写入同样的字符串就可以了。