1.定义
PowerManagerService(以下简称PMS)是Android系统电源管理的核心服务,它在Framework层建立起一个策略控制方案,向下决策HAL以及kernel层来控制设备待机状态,控制显示屏,背光灯,距离传感器,光线传感器等硬件设备的状态。向上提供给应用程序相应的操作接口来保持系统处于唤醒状态,比如音乐播放时持续保持系统唤醒,应用通知来临唤醒手机屏幕等场景。它的启动方式和AlarmManagerService大同小异,只不过PMS是在SystemServer中的引导服务中启动,AMS是在SystemServer中的其他服务中启动。启动时序图如下:
2.PowerManager
PowerManager是PowerManagerService的代理类,它对外提供了操作PMS的接口函数,真正的处理工作则是在PMS中。获取PowerManager的实例方式和AlarmManager一样,时序图也类似,这里不做过多讲解。在PowerManager中只有部分方法对上层应用开放,相关部分接口如下:
(1)isScreenOn():获取屏幕是否亮起;
(2)reboot(xx):用于重启设备,但是需要REBOOT权限;
(3)isPowerSaveMode():获取系统是否处于省电模式;
(4)isDeviceIdleMode():系统是否处于idle状态;
(5)newWakeLock(xx):生成新的wakelock实例;
(6)wakeUp(xx):用于强制唤醒系统;@hide
(7)shutdown(xx):关机;@hide
(8)userActivity(xx):用于通知PowerMangerService有用户活动发生了,并重新计算自动灭屏时间同时如果系统没有进入睡眠则点亮屏幕,比如用户点击了屏幕等;@hide
(9)goToSleep(xx):强制使系统进入到睡眠状态;当用户按了power键则会调用该方法;@hide
(10)boostScreenBrightness(xx):将屏幕亮度调到最大值;@hide
(11) setPowerSaveMode;设置系统省电模式是否开启;@hide;
(12)and so on;
在PowerManager中所有的方法实现最后都是通过Binder的方式调用到PowerManagerService中的函数进行实现的。所以后面对PowerManagerService的实现进行讲解,在讲解PMS之前先来了解一下wakelock机制。
3.WakeLock机制
Wakelock是一种锁的机制,当用户通过PowerManager获取到该锁之后那么系统就不能进入到休眠状态,直到该锁被释放为止。
3.1 生成wakeLock实例
在Android中通过PowerManager对系统电源状态进行管理。而在实际开发过程中,我们使用PowerManager主要是为了通过它获取一个WakeLock锁,用于控制当前设备的一些耗电操作。WakeLock是PowerManager中的内部类,我们需要通过PowerManager中的newWakeLock(int levelAndFlags,String tag)方法生成实例,代码如下:
public WakeLock newWakeLock(int levelAndFlags, String tag) {
//判断用户传入的levelAndFlags以及tag是否合法
validateWakeLockParameters(levelAndFlags, tag);
return new WakeLock(levelAndFlags, tag, mContext.getOpPackageName());
}
复制代码
3.2 levelAndFlags值讲解
(1)PARTIAL_WAKE_LOCK:使CPU高速运行,屏幕和键盘光关闭;
(2)SCREEN_DIM_WAKE_LOCK:确保屏幕亮起,但是允许它是最低亮度;已经被废弃;
(3)SCREEN_BRIGHT_WAKE_LOCK:保证屏幕亮起,并且是最大亮度;已经被废弃;
(4)FULL_WAKE_LOCK:保证屏幕和键盘背光是以最大亮度亮起;已经被废弃;
(5)PROXIMITY_SCREEN_OFF_WAKE_LOCK:用于和接近传感器配合使用,来实现电话类应用中当手机贴近耳朵的时候将屏幕熄灭,而离开的时候又使屏幕亮起;
(6)DOZE_WAKE_LOCK:系统级别的flag,在DreamManager中被使用;
(7)DRAW_WAKE_LOCK:系统级别的flag,在WindowManager中被使用。
3.3 WakeLock的使用
(1)即使持有多次wakelock锁也只需要一次释放;
(2)持有多少次wakelock锁就需要释放多少次;
(3)设置wakelock超时时间,超时之后自动释放,可以手动释放;
持有wakelock锁代码如下:
private void acquireLocked() {
//用于统计调用当前wakelock多少次
mInternalCount++;
mExternalCount++;
//mRefCounted表示是否通过计数的方式使用wakelock,默认为true:
//true:那么acquire了多少次就需要release多少次;实际情况就是在第一次调用的
//时候才会真正去获取wakelock锁,最后一次释放的时候才会真正释放wakelock锁
//false:那么即使调用了多次也只需要释放一次
if (!mRefCounted || mInternalCount == 1) {
mHandler.removeCallbacks(mReleaser);
Trace.asyncTraceBegin(Trace.TRACE_TAG_POWER, mTraceName, 0);
try {
//调用到PowerManagerService中
mService.acquireWakeLock(mToken, mFlags, mTag, mPackageName, mWorkSource,
mHistoryTag);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
mHeld = true;
}
}
复制代码
释放wakelock锁代码如下:
public void release(int flags) {
synchronized (mToken) {
//将调用次数减1
if (mInternalCount > 0) {
mInternalCount--;
}
//RELEASE_FLAG_TIMEOUT表示是通过设置超时时间的方式持有wakelock锁的
if ((flags & RELEASE_FLAG_TIMEOUT) == 0) {
mExternalCount--;
}
if (!mRefCounted || mInternalCount == 0) {
mHandler.removeCallbacks(mReleaser);
if (mHeld) {
Trace.asyncTraceEnd(Trace.TRACE_TAG_POWER, mTraceName, 0);
try {
mService.releaseWakeLock(mToken, flags);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
mHeld = false;
}
}
//如果是持有多少次wakelock锁就需要释放多少次wakelock锁
//那么释放wakelock之前必须先持有wakelock锁
if (mRefCounted && mExternalCount < 0) {
throw new RuntimeException("WakeLock under-locked " + mTag);
}
}
}
复制代码
4.PMS中各个方法讲解
4.1 wakeup
该方法用于强制唤醒系统,通过PowerManager调用到PMS中的wakeUp(xx)方法中,首先检查用户是否添加了DEVICE_POWER权限并获取应用的uid,最后调用wakeUpNoUpdateLocked(xx)函数和updatePowerStateLocked()函数,部分代码如下所示:
mDirty:用于标识哪个状态改变了或者需要被重新计算
private boolean wakeUpNoUpdateLocked(long eventTime, String reason, int reasonUid,String opPackageName,
int opUid) {
//判断唤醒的时间是否小于上一次睡眠时间或者系统处于睡眠时间或者系统还没有完全启动或者系统还没有ready
//则不进行唤醒
if (eventTime < mLastSleepTime || mWakefulness == WAKEFULNESS_AWAKE
|| !mBootCompleted || !mSystemReady) {
return false;
}
Trace.traceBegin(Trace.TRACE_TAG_POWER, "wakeUp");
try {
.......
//更新上一次唤醒时间
mLastWakeTime = eventTime;
//调用链:mNotifier.onWakeUp(xx)-->BatteryStatsService.noteWakeUp(xx)-->
//BatteryStatsImpl.noteWakeUpLocke(xx)-->BatteryStatsImpl.addHistoryEventLocked(xx)
mNotifier.onWakeUp(reason, reasonUid, opPackageName, opUid);
userActivityNoUpdateLocked(eventTime, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, reasonUid);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
return true;
}
复制代码
4.2 userActivity
用于通知PowerManagerService有用户活动发生,并重新计算自动灭屏时间以及在系统没有进入睡眠的时候重新点亮屏幕;比如用户点击屏幕或者按键等操作都会触发到该函数中。当从PowerManager中通过Binder的方式调用到PowerManagerService中首先会进行权限的检测,然后调用到userActivityNoUpdateLocked和updatePowerStateLocked方法中,部分代码如下:
//更新用户活动上一次触发时间以及mDirty标签等
private boolean userActivityNoUpdateLocked(long eventTime, int event, int flags, int uid) {
//如果当前触发时间小于上一次睡眠时间或者小于上一次唤醒时间(时间不合法)等则直接返回false
if (eventTime < mLastSleepTime || eventTime < mLastWakeTime
|| !mBootCompleted || !mSystemReady) {
return false;
}
Trace.traceBegin(Trace.TRACE_TAG_POWER, "userActivity");
try {
//如果触发时间大于上一次唤醒屏幕时间,更新上一次唤醒屏幕时间
if (eventTime > mLastInteractivePowerHintTime) {
powerHintInternal(PowerHint.INTERACTION, 0);
mLastInteractivePowerHintTime = eventTime;
}
mNotifier.onUserActivity(event, uid);
if (mUserInactiveOverrideFromWindowManager) {
mUserInactiveOverrideFromWindowManager = false;
mOverriddenTimeout = -1;
}
//如果系统处于睡眠或者doze状态那么直接返回false
if (mWakefulness == WAKEFULNESS_ASLEEP
|| mWakefulness == WAKEFULNESS_DOZING
|| (flags & PowerManager.USER_ACTIVITY_FLAG_INDIRECT) != 0) {
return false;
}
//如果有应用Activity在前台,则更新该应用前台时间
maybeUpdateForegroundProfileLastActivityLocked(eventTime);
//如果设置了屏幕已经变暗但是延长屏幕当前亮度的时间flag值
if ((flags & PowerManager.USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS) != 0) {
//如果当前触发时间大于上一次延长屏幕当前亮度触发时间以及上一次让屏幕更亮的触发时间
if (eventTime > mLastUserActivityTimeNoChangeLights
&& eventTime > mLastUserActivityTime) {
mLastUserActivityTimeNoChangeLights = eventTime;
//给PMS中的标签添加有用户活动发生标签
mDirty |= DIRTY_USER_ACTIVITY;
//如果是按钮被点击或者被释放的用户活动
if (event == PowerManager.USER_ACTIVITY_EVENT_BUTTON) {
mDirty |= DIRTY_QUIESCENT;
}
return true;
}
} else {
//更新上一次用户活动触发时间
if (eventTime > mLastUserActivityTime) {
mLastUserActivityTime = eventTime;
mDirty |= DIRTY_USER_ACTIVITY;
if (event == PowerManager.USER_ACTIVITY_EVENT_BUTTON) {
mDirty |= DIRTY_QUIESCENT;
}
return true;
}
}
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
return false;
}
复制代码
4.3 goToSleep
强制系统进入到休眠状态,并覆盖掉所有正在执行的wakelock,在用户按了power键之后会被触发。在PowerManager中通过Bidner的方式调用到PMS中,首先进行权限检测,然后调用到goToSleepInternal(xx)方法中,最后调用到goToSleepNoUpdateLocked和updatePowerStateLocked方法,部分代码如下:
private boolean goToSleepNoUpdateLocked(long eventTime, int reason, int flags, int uid) {
//如果触发时间小于上一次唤醒时间或者系统处于睡眠或者doze状态,或者系统没有完全启动或者系统没有准备完全
//直接返回false
if (eventTime < mLastWakeTime || mWakefulness == WAKEFULNESS_ASLEEP|| mWakefulness == WAKEFULNESS_DOZING
|| !mBootCompleted || !mSystemReady) {
return false;
}
Trace.traceBegin(Trace.TRACE_TAG_POWER, "goToSleep");
try {
//更新上一次进入睡眠时间
mLastSleepTime = eventTime;
//可以开启屏保
mSandmanSummoned = true;
//将当前设置为doze状态
setWakefulnessLocked(WAKEFULNESS_DOZING, reason);
//用于记录在系统进入到睡眠状态的时候有多少wakelock会被清除掉
int numWakeLocksCleared = 0;
final int numWakeLocks = mWakeLocks.size();
for (int i = 0; i < numWakeLocks; i++) {
final WakeLock wakeLock = mWakeLocks.get(i);
switch (wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) {
case PowerManager.FULL_WAKE_LOCK:
case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
case PowerManager.SCREEN_DIM_WAKE_LOCK:
numWakeLocksCleared += 1;
break;
}
}
EventLogTags.writePowerSleepRequested(numWakeLocksCleared);
// 将系统设置为睡眠状态
if ((flags & PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE) != 0) {
reallyGoToSleepNoUpdateLocked(eventTime, uid);
}
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
return true;
}
复制代码
4.4 acquireWakeLockInternal
PowerManager通过Binder的方式调用到PMS的acquireWakeLock(xx)方法之后,首先进行权限检测,然后获取到调用Binder的uid和Pid,并传递到acquireWakeLockInternal(xx)方法中;最后再调用到updatePowerStateLocked()方法,更新电源状态。部分代码如下所示:
private void acquireWakeLockInternal(IBinder lock, int flags, String tag, String packageName,
WorkSource ws, String historyTag, int uid, int pid) {
synchronized (mLock) {
WakeLock wakeLock;
//从存储wakelock的列表中查找是否存在当前设置的wakelock
int index = findWakeLockIndexLocked(lock);
boolean notifyAcquire;
if (index >= 0) {
wakeLock = mWakeLocks.get(index);
//判断设置的wakelock与列表中存储的wakelock属性是否发生了变化
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;
//创建一个新的wakelock并添加到wakelocks列表中去
} else {
..................
mWakeLocks.add(wakeLock);
setWakeLockDisabledStateLocked(wakeLock);
notifyAcquire = true;
}
applyWakeLockFlagsOnAcquireLocked(wakeLock, uid);
mDirty |= DIRTY_WAKE_LOCKS;
updatePowerStateLocked();
if (notifyAcquire) {
// This needs to be done last so we are sure we have acquired the
// kernel wake lock. Otherwise we have a race where the system may
// go to sleep between the time we start the accounting in battery
// stats and when we actually get around to telling the kernel to
// stay awake.
//发送wakelock已经执行通知
notifyWakeLockAcquiredLocked(wakeLock);
}
}
}
private void applyWakeLockFlagsOnAcquireLocked(WakeLock wakeLock, int uid) {
//如果当前wakelock能够唤醒屏幕,且当前wakelock锁设置的flag也能够唤醒屏幕
if ((wakeLock.mFlags & PowerManager.ACQUIRE_CAUSES_WAKEUP) != 0
&& isScreenLock(wakeLock)) {
String opPackageName;
int opUid;
//更新包名
if (wakeLock.mWorkSource != null && wakeLock.mWorkSource.getName(0) != null) {
opPackageName = wakeLock.mWorkSource.getName(0);
opUid = wakeLock.mWorkSource.get(0);
} else {
opPackageName = wakeLock.mPackageName;
opUid = wakeLock.mWorkSource != null ? wakeLock.mWorkSource.get(0)
: wakeLock.mOwnerUid;
}
//更新上一次发生时间
wakeUpNoUpdateLocked(SystemClock.uptimeMillis(), wakeLock.mTag, opUid,
opPackageName, opUid);
}
private boolean wakeUpNoUpdateLocked(long eventTime, String reason, int reasonUid,
String opPackageName, int opUid) {
//如果系统开机时间小于上一次睡眠时间或者当前系统处于唤醒状态或者系统没有启动完全则直接返回false
if (eventTime < mLastSleepTime || mWakefulness == WAKEFULNESS_AWAKE
|| !mBootCompleted || !mSystemReady) {
return false;
}
Trace.asyncTraceBegin(Trace.TRACE_TAG_POWER, TRACE_SCREEN_ON, 0);
Trace.traceBegin(Trace.TRACE_TAG_POWER, "wakeUp");
..............
//更新上一次唤醒时间
mLastWakeTime = eventTime;
mNotifier.onWakeUp(reason, reasonUid, opPackageName, opUid);
//更新用户活动时间
userActivityNoUpdateLocked(
eventTime, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, reasonUid);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
return true;
}
复制代码
4.5 updatePowerStateLocked
该方法根据各个方法所设置的mDirty值来重新计算系统电源状态。部分代码如下所示:
private void updatePowerStateLocked() {
//如果系统还没有准备好或者没有任何改变则直接返回;
if (!mSystemReady || mDirty == 0) {
return;
}
Trace.traceBegin(Trace.TRACE_TAG_POWER, "updatePowerState");
try {
//用于更新充电以及电池状态,充电方式,剩余电量,是否是低电量,并记录充电状态是否改变以及是否在
//插拔电之后亮屏等
updateIsPoweredLocked(mDirty);
//用于更新mStayOn变量,如果为true则表示屏幕长亮
//如果设置中设置了可保持长亮,如果手机正在充电则会将mStayOn设置为true
updateStayOnLocked(mDirty);
//更新屏幕亮度超时时间,如果当前时间小于离上一次将亮度调整到最大到下一次亮度调整到最大的时间延迟
//则在最小时间延迟之后才将亮度调整到最大
updateScreenBrightnessBoostLocked(mDirty);
final long now = SystemClock.uptimeMillis();
int dirtyPhase2 = 0;
//循环是因为wakelock和user activity的计算会受到Wakefulness的影响
for (;;) {
int dirtyPhase1 = mDirty;
dirtyPhase2 |= dirtyPhase1;
mDirty = 0;
//将对应uid的wakelock的flag值更新到mProfilePowerState列表中对应item的mWakeLockSummary上
//并根据系统状态去除不必要的wakelock的flag值
updateWakeLockSummaryLocked(dirtyPhase1);
//根据系统最后一次调用userActivity(xx)方法的时间计算现在是否可以将屏幕状态
//mUserActivitySummary设置成亮屏或者暗屏或者屏保,当系统处于深度睡眠的时候则会忽略掉用户活动
updateUserActivitySummaryLocked(now, dirtyPhase1);
//用于更新系统状态,并且用于决定系统是否进入到屏保状态。
//返回true表示系统状态发生了变化(进入了屏保或者休眠状态),
//那么需要重新计算user Activity以及wakelock的flag值
if (!updateWakefulnessLocked(dirtyPhase1)) {
break;
}
}
updateProfilesLocked(now);
//更新设备屏幕显示,在该方法中会最终计算出屏幕亮度、是否自动调节亮度等值
final boolean displayBecameReady = updateDisplayPowerStateLocked(dirtyPhase2);
//更新屏保
updateDreamLocked(dirtyPhase2, displayBecameReady);
//系统状态更新完成
finishWakefulnessChangeIfNeededLocked();
//可能需要释放最后一个维持cpu唤醒或者屏幕亮灭的suspend锁,所以需要确保所有的任务都已经完成
//更新suspend锁使屏幕处于唤醒状态
updateSuspendBlockerLocked();
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
}
private void updateScreenBrightnessBoostLocked(int dirty) {
//如果可以将屏幕亮度调节到了最大
if ((dirty & DIRTY_SCREEN_BRIGHTNESS_BOOST) != 0) {
if (mScreenBrightnessBoostInProgress) {
final long now = SystemClock.uptimeMillis();
mHandler.removeMessages(MSG_SCREEN_BRIGHTNESS_BOOST_TIMEOUT);
//如果上一次调节屏幕亮度到最大的时间晚于上一次系统睡眠时间
if (mLastScreenBrightnessBoostTime > mLastSleepTime) {
//调节亮度到最大的下一次时间延迟 = 上一次调节亮度到最大 + 5s
final long boostTimeout = mLastScreenBrightnessBoostTime +
SCREEN_BRIGHTNESS_BOOST_TIMEOUT;
//如果调节亮度到最大的最小时间延迟大于当前时间,则在boostTimeOut时间通过handler重新触发
//才允许将亮度调整到最大
if (boostTimeout > now) {
Message msg = mHandler.obtainMessage(MSG_SCREEN_BRIGHTNESS_BOOST_TIMEOUT);
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, boostTimeout);
return;
}
}
//将是否正在调节亮度到最大置为false
mScreenBrightnessBoostInProgress = false;
mNotifier.onScreenBrightnessBoostChanged();
//触发用户活动
userActivityNoUpdateLocked(now,
PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID);
}
}
}
private void updateWakeLockSummaryLocked(int dirty) {
//如果wakelock和WAKEFULNESS改变了则继续执行
if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_WAKEFULNESS)) != 0) {
mWakeLockSummary = 0;
final int numProfiles = mProfilePowerState.size();
//mProfilePowerState:用于存储用户设置的屏幕灭屏时间
for (int i = 0; i < numProfiles; i++) {
mProfilePowerState.valueAt(i).mWakeLockSummary = 0;
}
final int numWakeLocks = mWakeLocks.size();
for (int i = 0; i < numWakeLocks; i++) {
final WakeLock wakeLock = mWakeLocks.get(i);
//根据wakelock的flag值来确定系统的状态(cpu运行、屏幕变量或者变暗等)
final int wakeLockFlags = getWakeLockSummaryFlags(wakeLock);
//将wakelock的flag值更新到mWakeLockSummary中
mWakeLockSummary |= wakeLockFlags;
for (int j = 0; j < numProfiles; j++) {
final ProfilePowerState profile = mProfilePowerState.valueAt(j);
//将对应uid的wakelock的flag值更新到mProfilePowerState中item对应uid的mWakeLockSummary中
if (wakeLockAffectsUser(wakeLock, profile.mUserId)) {
profile.mWakeLockSummary |= wakeLockFlags;
}
}
}
//如果系统不处于doze状态则从mWakeLockSummary中移除doze和dream标签
if (mWakefulness != WAKEFULNESS_DOZING) {
mWakeLockSummary &= ~(WAKE_LOCK_DOZE | WAKE_LOCK_DRAW);
}
//如果系统处于睡眠状态或者有wakelock有doze标签则系统不允许亮屏
if (mWakefulness == WAKEFULNESS_ASLEEP
|| (mWakeLockSummary & WAKE_LOCK_DOZE) != 0) {
//从mWakeLockSummary中去掉
mWakeLockSummary &= ~(WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_SCREEN_DIM
| WAKE_LOCK_BUTTON_BRIGHT);
}
//根据系统状态重新调整mWakeLockSummary值(去除不必要的wakelockflag值)
mWakeLockSummary = adjustWakeLockSummaryLocked(mWakeLockSummary);
for (int i = 0; i < numProfiles; i++) {
final ProfilePowerState profile = mProfilePowerState.valueAt(i);
profile.mWakeLockSummary = adjustWakeLockSummaryLocked(profile.mWakeLockSummary);
}
}
}
private void updateUserActivitySummaryLocked(long now, int dirty) {
//如果有用户活动发生
if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY
| DIRTY_WAKEFULNESS | DIRTY_SETTINGS)) != 0) {
mHandler.removeMessages(MSG_USER_ACTIVITY_TIMEOUT);
long nextTimeout = 0;
//系统出唤醒或者dream或者doze状态
if (mWakefulness == WAKEFULNESS_AWAKE
|| mWakefulness == WAKEFULNESS_DREAMING
|| mWakefulness == WAKEFULNESS_DOZING) {
//获取系统进入休眠时间,该时间大于等于屏幕最小灭屏时间
final long sleepTimeout = getSleepTimeoutLocked();
//获取屏幕灭屏时间
final long screenOffTimeout = getScreenOffTimeoutLocked(sleepTimeout);
//获取屏幕处于亮度很暗持续时间
final long screenDimDuration = getScreenDimDurationLocked(screenOffTimeout);
//通过windowmanager的用户交互
final boolean userInactiveOverride = mUserInactiveOverrideFromWindowManager;
//系统下次休眠时间
final long nextProfileTimeout = getNextProfileTimeoutLocked(now);
mUserActivitySummary = 0;
if (mLastUserActivityTime >= mLastWakeTime) {
//系统下次睡眠时间 = 上一次用户活动时间 + 灭屏时间 - 屏幕处于暗屏持续时间
nextTimeout = mLastUserActivityTime
+ screenOffTimeout - screenDimDuration;
//如果当前时间小于下一次系统睡眠时间,说明此时是亮屏状态
if (now < nextTimeout) {
mUserActivitySummary = USER_ACTIVITY_SCREEN_BRIGHT;
} else {
//下一次灭屏时间 = 上一次用户活动时间 + 灭屏时间
nextTimeout = mLastUserActivityTime + screenOffTimeout;
//如果当前时间小于下一次灭屏时间,那么系统此时处于暗屏状态
if (now < nextTimeout) {
mUserActivitySummary = USER_ACTIVITY_SCREEN_DIM;
}
}
}
//如果上一次用户活动时间 > 上一次唤醒时间
if (mUserActivitySummary == 0&& mLastUserActivityTimeNoChangeLights >= mLastWakeTime) {
//下一次灭屏时间 = 上一次用户活动时间 + 灭屏时间
nextTimeout = mLastUserActivityTimeNoChangeLights + screenOffTimeout;
//如果当前时间 < 下一次灭屏时间
if (now < nextTimeout) {
//根据mDisplayPowerRequest.policy设置屏幕状态
if (mDisplayPowerRequest.policy == DisplayPowerRequest.POLICY_BRIGHT
|| mDisplayPowerRequest.policy == DisplayPowerRequest.POLICY_VR) {
mUserActivitySummary = USER_ACTIVITY_SCREEN_BRIGHT;
} else if (mDisplayPowerRequest.policy == DisplayPowerRequest.POLICY_DIM) {
mUserActivitySummary = USER_ACTIVITY_SCREEN_DIM;
}
}
}
if (mUserActivitySummary == 0) {
//如果系统进入休眠时间 >= 0
if (sleepTimeout >= 0) {
//获取上一次用户活动时间两种flag的最大值
final long anyUserActivity = Math.max(mLastUserActivityTime,
mLastUserActivityTimeNoChangeLights);
//如果上一次用户活动时间 >= 上一次唤醒时间
if (anyUserActivity >= mLastWakeTime) {
//下一次休眠时间 = 上一次用户活动时间 + 系统进入休眠时间
nextTimeout = anyUserActivity + sleepTimeout;
//如果当前时间 < 下一次休眠时间则将屏幕状态置为屏保状态
if (now < nextTimeout) {
mUserActivitySummary = USER_ACTIVITY_SCREEN_DREAM;
}
}
} else {
mUserActivitySummary = USER_ACTIVITY_SCREEN_DREAM;
nextTimeout = -1;
}
}
if (mUserActivitySummary != USER_ACTIVITY_SCREEN_DREAM && userInactiveOverride) {
if ((mUserActivitySummary &
(USER_ACTIVITY_SCREEN_BRIGHT | USER_ACTIVITY_SCREEN_DIM)) != 0) {
//系统因为最近的用户活动保持为唤醒状态
if (nextTimeout >= now && mOverriddenTimeout == -1) {
// Save when the next timeout would have occurred
mOverriddenTimeout = nextTimeout;
}
}
mUserActivitySummary = USER_ACTIVITY_SCREEN_DREAM;
nextTimeout = -1;
}
//计算下一次灭屏时间
if (nextProfileTimeout > 0) {
nextTimeout = Math.min(nextTimeout, nextProfileTimeout);
}
//在nextTimeout时间之后发送message给handler进行处理,再次触发updatePowerStateLocked()进行刷新
if (mUserActivitySummary != 0 && nextTimeout >= 0) {
scheduleUserInactivityTimeout(nextTimeout);
}
} else {
mUserActivitySummary = 0;
}
}
}
//该方法会根据当前的wakelocks以及user Activity判断设备进入到屏保状态
private boolean updateWakefulnessLocked(int dirty) {
boolean changed = false;
//如果系统中有状态变化
if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY | DIRTY_BOOT_COMPLETED
| DIRTY_WAKEFULNESS | DIRTY_STAY_ON | DIRTY_PROXIMITY_POSITIVE
| DIRTY_DOCK_STATE)) != 0) {
//如果系统是唤醒状态且系统需要马上进入到睡眠状态
if (mWakefulness == WAKEFULNESS_AWAKE && isItBedTimeYetLocked()) {
final long time = SystemClock.uptimeMillis();
//返回true表示手机会自动进入屏保
if (shouldNapAtBedTimeLocked()) {
changed = napNoUpdateLocked(time, Process.SYSTEM_UID);
} else {
//系统进入了深度睡眠
changed = goToSleepNoUpdateLocked(time,
PowerManager.GO_TO_SLEEP_REASON_TIMEOUT, 0, Process.SYSTEM_UID);
}
}
}
return changed;
}
复制代码
4.6 PowerManagerInternal中定义了四种WakeFulness值用于标识系统当前的状态:
(1)WAKEFULNESS_ASLEEP:表示系统当前处于休眠状态,只能被wakeup()唤醒;
(2)WAKEFULNESS_AWAKE:表示系统目前处于正常运行状态;
(3)WAKEFULNESS_DREAMING:表示系统当前处于屏保状态;
(4)WAKEFULNESS_DOZING:表示系统处于doze状态。
5 总结
从上面的分析来看,对于PowerManagerService中的数据处理流程可以归结为如下的步骤:
(1)用户通过调用PowerManager进行数据处理;
(2)PowerManager通过Binder的方式调用到PMS中;
(3)PMS中的方法首先进行权限检测并获取到调用Binder应用的uid以及pid;
(4)判断时间是否合法;
(5)更新上一次相关时间;
(6)调用到updatePowerStateLocked()方法中,最后通过方法updateSuspendBlockerLocked()调用到底层更新suspen锁以保持cpu唤醒。
至此,PMS中比较重要的代码算是记录完了,当然里面还有很多细节部分需要不断的完善阅读,这样才能不断的将PMS的核心理解的更加透彻。