一.灭屏简述
先来讲灭屏,灭屏的方式一般有如下几种:
1.用户按Power键灭屏;
2.手机自动放置一段时间后超时灭屏;
3.Sensor灭屏。
灭屏的原因在PowerManager类中的sleepReasonToString方法有列出常见的:
/**
* @hide
*/
public static String sleepReasonToString(int sleepReason) {
switch (sleepReason) {
case GO_TO_SLEEP_REASON_APPLICATION: return "application";
case GO_TO_SLEEP_REASON_DEVICE_ADMIN: return "device_admin";
case GO_TO_SLEEP_REASON_TIMEOUT: return "timeout";
case GO_TO_SLEEP_REASON_LID_SWITCH: return "lid_switch";
case GO_TO_SLEEP_REASON_POWER_BUTTON: return "power_button";
case GO_TO_SLEEP_REASON_HDMI: return "hdmi";
case GO_TO_SLEEP_REASON_SLEEP_BUTTON: return "sleep_button";
case GO_TO_SLEEP_REASON_ACCESSIBILITY: return "accessibility";
case GO_TO_SLEEP_REASON_FORCE_SUSPEND: return "force_suspend";
default: return Integer.toString(sleepReason);
}
}
当触发灭屏的时候,其实是调用的PowerManager中的goToSleep方法。
这个方法共有两个:一个是只传参发出睡眠请求的时间time;另一是传三个参数:睡眠请求的时间time、灭屏原因reason、WakeLock的flag:
public void goToSleep(long time) {
goToSleep(time, GO_TO_SLEEP_REASON_APPLICATION, 0);
}
@UnsupportedAppUsage
public void goToSleep(long time, int reason, int flags) {
try {
mService.goToSleep(time, reason, flags);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
最终调用到PowerManagerSevice的goToSleep方法上:
@Override // Binder call
public void goToSleep(long eventTime, int reason, int flags) {
if (eventTime > SystemClock.uptimeMillis()) {
throw new IllegalArgumentException("event time must not be in the future");
}
// 检查DEVICE_POWER权限
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.DEVICE_POWER, null);
// 线程id
final int uid = Binder.getCallingUid();
final long ident = Binder.clearCallingIdentity();
try {
goToSleepInternal(eventTime, reason, flags, uid);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
接着看goToSleepInternal的实现:
private void goToSleepInternal(long eventTime, int reason, int flags, int uid) {
// 加上锁
synchronized (mLock) {
// 判断goToSleepNoUpdateLocked的返回值
if (goToSleepNoUpdateLocked(eventTime, reason, flags, uid)) {
// 更新Powerstate
updatePowerStateLocked();
}
}
}
先看goToSleepNoUpdateLocked:
@SuppressWarnings("deprecation")
private boolean goToSleepNoUpdateLocked(long eventTime, int reason, int flags, int uid) {
if (DEBUG_SPEW) {
Slog.d(TAG, "goToSleepNoUpdateLocked: eventTime=" + eventTime
+ ", reason=" + reason + ", flags=" + flags + ", uid=" + uid);
}
if (eventTime < mLastWakeTime
|| mWakefulness == WAKEFULNESS_ASLEEP
|| mWakefulness == WAKEFULNESS_DOZING
|| !mBootCompleted || !mSystemReady) {
return false;
}
Trace.traceBegin(Trace.TRACE_TAG_POWER, "goToSleep");
try {
// 获取灭屏的原因
reason = Math.min(PowerManager.GO_TO_SLEEP_REASON_MAX,
Math.max(reason, PowerManager.GO_TO_SLEEP_REASON_MIN));
Slog.i(TAG, "Going to sleep due to " + PowerManager.sleepReasonToString(reason)
+ " (uid " + uid + ")...");
mLastSleepTime = eventTime;
mLastSleepReason = reason;
mSandmanSummoned = true;
// 通知设备更改唤醒状态
setWakefulnessLocked(WAKEFULNESS_DOZING, reason, eventTime);
// Report the number of wake locks that will be cleared by going to sleep.
// 报告将通过睡眠清除的唤醒锁的数量
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);
// Skip dozing if requested.
// 跳过dozing状态
if ((flags & PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE) != 0) {
// 调用reallyGoToSleepNoUpdateLocked函数
reallyGoToSleepNoUpdateLocked(eventTime, uid);
}
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
return true;
}
最后来看PowerManagerService的核心方法updatePowerStateLocked方法,关键的地方Google都有注释说明了,来看源码实现:
private void updatePowerStateLocked() {
if (!mSystemReady || mDirty == 0) {
return;
}
if (!Thread.holdsLock(mLock)) {
Slog.wtf(TAG, "Power manager lock was not held when calling updatePowerStateLocked");
}
Trace.traceBegin(Trace.TRACE_TAG_POWER, "updatePowerState");
try {
// Phase 0: Basic state updates.
// 阶段0:基础状态的更新
// 更新mIsPowered的值,ture表示设备插入电源
updateIsPoweredLocked(mDirty);
// 更新mStayOn的值,true表示设备应保持打开状态
updateStayOnLocked(mDirty);
// 更新屏幕亮度
updateScreenBrightnessBoostLocked(mDirty);
// Phase 1: Update wakefulness.
// Loop because the wake lock and user activity computations are influenced
// by changes in wakefulness.
// 阶段1:更新唤醒状态
final long now = SystemClock.uptimeMillis();
int dirtyPhase2 = 0;
// 死循环
for (;;) {
int dirtyPhase1 = mDirty;
dirtyPhase2 |= dirtyPhase1;
mDirty = 0;
// 更新mWakeLockSummary的值以汇总所有活动唤醒锁的状态
updateWakeLockSummaryLocked(dirtyPhase1);
// 更新mUserActivitySummary的值以汇总请求的用户
updateUserActivitySummaryLocked(now, dirtyPhase1);
// 更新设备的唤醒状态,如果返回true表示wakefulness有变化
if (!updateWakefulnessLocked(dirtyPhase1)) {
break;
}
}
// Phase 2: Lock profiles that became inactive/not kept awake.
// 阶段2:锁定已停用/未唤醒的配置文件
// 检查配置文件超时并通知应锁定的配置文件
updateProfilesLocked(now);
// Phase 3: Update display power state.
// 阶段3:更新显示状态
// 异步更新显示状态
// 更新完成之后,mDisplayReady将设置为true。方法返回为true,表示显示准备就绪
final boolean displayBecameReady = updateDisplayPowerStateLocked(dirtyPhase2);
// Phase 4: Update dream state (depends on display ready signal).
// 阶段4:更新dream状态(取决于显示就绪信号)
// 异步更新
updateDreamLocked(dirtyPhase2, displayBecameReady);
// Phase 5: Send notifications, if needed.
// 阶段5:如果需要发送通知
finishWakefulnessChangeIfNeededLocked();
// Phase 6: Update suspend blocker.
// Because we might release the last suspend blocker here, we need to make sure
// we finished everything else first!
// 更新暂停阻止程序
// 更新使CPU保持活动状态的暂停阻塞程序
updateSuspendBlockerLocked();
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
}
二.常见的灭屏方式
1.Power键灭屏
Power键的按键实现从native层到java层的整个流程我们后续会介绍。这里从java层之上开始看。
流程图如下:
具体的代码实现分析如下:
InputManagerService类中interceptKeyBeforeQueueing方法:
// Native callback.
private int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
return mWindowManagerCallbacks.interceptKeyBeforeQueueing(event, policyFlags);
}
调用WindowManagerCallbacks接口的interceptKeyBeforeQueueing方法,来看接口实现类InputMonitor:
@Override
public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
return mService.mPolicy.interceptKeyBeforeQueueing(event, policyFlags);
}
调用的接口WindowManagerPolicy的interceptKeyBeforeQueueing方法,来看实现类是PhoneWindowManager类:
@Override
public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
if (!mSystemBooted) {
// If we have not yet booted, don't let key events do anything.
return 0;
}
......
// Handle special keys.
switch (keyCode) {
case KeyEvent.KEYCODE_BACK: {
if (down) {
interceptBackKeyDown();
} else {
boolean handled = interceptBackKeyUp(event);
// Don't pass back press to app if we've already handled it via long press
if (handled) {
result &= ~ACTION_PASS_TO_USER;
}
}
break;
}
......
case KeyEvent.KEYCODE_POWER: {
EventLogTags.writeInterceptPower(
KeyEvent.actionToString(event.getAction()),
mPowerKeyHandled ? 1 : 0, mPowerKeyPressCounter);
// Any activity on the power button stops the accessibility shortcut
cancelPendingAccessibilityShortcutAction();
result &= ~ACTION_PASS_TO_USER;
isWakeKey = false; // wake-up will be handled separately
if (down) {
interceptPowerKeyDown(event, interactive)