深入了解PowerManagerService之Android 11.0 Power 键亮屏灭屏流程分析
Posted Mrsongs的心情杂货铺
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了深入了解PowerManagerService之Android 11.0 Power 键亮屏灭屏流程分析相关的知识,希望对你有一定的参考价值。
一、前言
环境:本文基于MTK 6765 Android 11
PowerManagerService(下文简称PMS)是Android系统的核心服务之一,控制着系统的亮灭屏,电源管理,等等重要的功能,本文将先从Power键亮灭屏流程分析入手去了解PMS。
二、PhoneWindowManager中Power键按键响应流程
-
代码路径:
frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java.`
-
Power键按键处理是在PhoneWindowManager中,分为按下事件和松开事件。interceptKeyBeforeDispatching方法中也是根据是按下事件还是松开事件分别对应处理。
final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
-
按下power键事件对应处理方法是interceptPowerKeyDown(event, interactive);
-
松开power键事件对应处理方法是interceptPowerKeyUp(event, interactive, canceled);
// TODO(b/117479243): handle it in InputPolicy
/** {@inheritDoc} */
@Override
public long interceptKeyBeforeDispatching(IBinder focusedToken, KeyEvent event,
int policyFlags) {
...省略部分代码
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);
} else {
interceptPowerKeyUp(event, interactive, canceled);
}
break;
}
...省略部分代码
// Let the application handle the key.
return 0;
}
Power键按下事件处理方法 interceptPowerKeyDown
主要做以下几件事:
- 1、获得一个PARTIAL_WAKE_LOCK 保持CPU运行,WAKE_LOCK这里不介绍,后面文章在介绍。
- 2、判断是否是组合键截图事件,并做对应的处理。
- 3、判断是否开启了对应的功能,power键可以直接挂断电话或者关闭来电响铃。
- 4、判断是否是手势事件对应处理。
- 5、根据interactive 当前是否Awake判断,如果是唤醒状态,则处理Power键长按事件, 如果不是唤醒状态即灭屏状态,则调用
wakeUpFromPowerKey
方法唤醒。 - 6、统计Power键按键次数
private void interceptPowerKeyDown(KeyEvent event, boolean interactive) {
// Hold a wake lock until the power key is released.
//获得一个PARTIAL_WAKE_LOCK 保持CPU运行,WAKE_LOCK这里不介绍,后面文章在介绍。
if (!mPowerKeyWakeLock.isHeld()) {
mPowerKeyWakeLock.acquire();
}
// Cancel multi-press detection timeout.
if (mPowerKeyPressCounter != 0) {
mHandler.removeMessages(MSG_POWER_DELAYED_PRESS);
}
mWindowManagerFuncs.onPowerKeyDown(interactive);
//2、判断是否是组合键截图事件,并做对应的处理。
// Latch power key state to detect screenshot chord.
if (interactive && !mScreenshotChordPowerKeyTriggered
&& (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
mScreenshotChordPowerKeyTriggered = true;
mScreenshotChordPowerKeyTime = event.getDownTime();
interceptScreenshotChord();
interceptRingerToggleChord();
}
//3、判断是否开启了对应的功能,power键可以直接挂断电话或者关闭来电响铃。
// Stop ringing or end call if configured to do so when power is pressed.
TelecomManager telecomManager = getTelecommService();
boolean hungUp = false;
if (telecomManager != null) {
if (telecomManager.isRinging()) {
// Pressing Power while there's a ringing incoming
// call should silence the ringer.
telecomManager.silenceRinger();
} else if ((mIncallPowerBehavior
& Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP) != 0
&& telecomManager.isInCall() && interactive) {
// Otherwise, if "Power button ends call" is enabled,
// the Power button will hang up any current active call.
hungUp = telecomManager.endCall();
}
}
//4、判断是否是手势事件对应处理。
GestureLauncherService gestureService = LocalServices.getService(
GestureLauncherService.class);
boolean gesturedServiceIntercepted = false;
if (gestureService != null) {
gesturedServiceIntercepted = gestureService.interceptPowerKeyDown(event, interactive,
mTmpBoolean);
if (mTmpBoolean.value && mRequestedOrGoingToSleep) {
mCameraGestureTriggeredDuringGoingToSleep = true;
}
}
// Inform the StatusBar; but do not allow it to consume the event.
sendSystemKeyToStatusBarAsync(event.getKeyCode());
schedulePossibleVeryLongPressReboot();
// If the power key has still not yet been handled, then detect short
// press, long press, or multi press and decide what to do.
mPowerKeyHandled = hungUp || mScreenshotChordVolumeDownKeyTriggered
|| mA11yShortcutChordVolumeUpKeyTriggered || gesturedServiceIntercepted;
if (!mPowerKeyHandled) {
if (interactive) {
// When interactive, we're already awake.
// Wait for a long press or for the button to be released to decide what to do.
//interactive为true,当前是Awake状态即亮屏状态,处理亮屏下的Power键长按事件
if (hasLongPressOnPowerBehavior()) {
if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) {
powerLongPress();
} else {
Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS);
msg.setAsynchronous(true);
mHandler.sendMessageDelayed(msg,
ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
if (hasVeryLongPressOnPowerBehavior()) {
Message longMsg = mHandler.obtainMessage(MSG_POWER_VERY_LONG_PRESS);
longMsg.setAsynchronous(true);
mHandler.sendMessageDelayed(longMsg, mVeryLongPressTimeout);
}
}
}
} else {
//interactive为false说明不是唤醒状态即灭屏状态,则调用 wakeUpFromPowerKey 方法唤醒系统。
wakeUpFromPowerKey(event.getDownTime());
if (mSupportLongPressPowerWhenNonInteractive && hasLongPressOnPowerBehavior()) {
if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) {
powerLongPress();
} else {
Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS);
msg.setAsynchronous(true);
mHandler.sendMessageDelayed(msg,
ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
if (hasVeryLongPressOnPowerBehavior()) {
Message longMsg = mHandler.obtainMessage(MSG_POWER_VERY_LONG_PRESS);
longMsg.setAsynchronous(true);
mHandler.sendMessageDelayed(longMsg, mVeryLongPressTimeout);
}
}
mBeganFromNonInteractive = true;
} else {
final int maxCount = getMaxMultiPressPowerCount();
if (maxCount <= 1) {
mPowerKeyHandled = true;
} else {
mBeganFromNonInteractive = true;
}
}
}
}
}
三、PowerManagerService 继续处理wakeup事件
3.1、power键按下时PowerManagerService 的wakeup到updatePowerStateLocked 调用过程
-
代码路径:
frameworks\\base\\services\\core\\java\\com\\android\\server\\power\\PowerManagerService.java.`
-
1、上文中 PhoneWindowManager的
wakeUpFromPowerKey
方法调用的是PowerManagerService
的WakeUp方法,再通过Binder 跨进程调用服务端PowerManagerService
的wakeUp
,最后除非是当前已经是唤醒等情况,否则都会调用到updatePowerStateLocked
方法。 -
2、wakeUpNoUpdateLocked 只有在如下几种情况下为false,正常情况都是true。
a)、当前事件时间比上次asleep 时间还早(这不可能,除非穿越了);
b)、当前已经是WAKEFULNESS_AWAKE 唤醒状态;
c)、mForceSuspendActive 为true,即有强制挂起激活标志;
d)、刚开机系统没有Ready 好;
-
3、
wakeUpNoUpdateLocked
主要是设置当前Wakefulness 为WAKEFULNESS_AWAKE
,然后通知wakeup,和调用userActivityNoUpdateLocked
更新用户活动时间,这个和超时休眠有关。
...此处省略部分代码
@Override // Binder call
public void wakeUp(long eventTime, @WakeReason int reason, String details,
String opPackageName) {
if (eventTime > mClock.uptimeMillis()) {
throw new IllegalArgumentException("event time must not be in the future");
}
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.DEVICE_POWER, null);
final int uid = Binder.getCallingUid();
final long ident = Binder.clearCallingIdentity();
try {
wakeUpInternal(eventTime, reason, details, uid, opPackageName, uid);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
...此处省略部分代码
private void wakeUpInternal(long eventTime, @WakeReason int reason, String details, int uid,
String opPackageName, int opUid) {
synchronized (mLock) {
/**wakeUpNoUpdateLocked 只有在如下几种情况下为false,正常情况都是true
*1、当前事件时间比上次asleep 时间还早(这不可能,除非穿越了);
*2、当前已经是WAKEFULNESS_AWAKE 唤醒状态;
*3、mForceSuspendActive 为true,即有强制挂起激活标志;
*4、刚开机系统没有Ready 好;
*/
if (wakeUpNoUpdateLocked(eventTime, reason, details, uid, opPackageName, opUid)) {
updatePowerStateLocked();
}
}
}
...此处省略部分代码
四、PowerManagerService 的核心方法 updatePowerStateLocked
-
代码路径:
frameworks\\base\\services\\core\\java\\com\\android\\server\\power\\PowerManagerService.java.`
-
PMS中updatePowerStateLocked 方法调用的非常频繁并且非常的重要,里面的case 情况非常多,如果能搞清楚这个方法,基本上对PMS的逻辑流程就很熟悉了。
/**
* Updates the global power state based on dirty bits recorded in mDirty.
*
* This is the main function that performs power state transitions.
* We centralize them here so that we can recompute the power state completely
* each time something important changes, and ensure that we do it the same
* way each time. The point is to gather all of the transition logic here.
*/
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.
//充电相关,插入充电器充电相关处理
updateIsPoweredLocked(mDirty);
//更新屏幕保持唤醒标识值mStayOn
updateStayOnLocked(mDirty);
//亮度增强相关
updateScreenBrightnessBoostLocked(mDirty);
// Phase 1: Update wakefulness.
// Loop because the wake lock and user activity computations are influenced
// by changes in wakefulness.
final long now = mClock.uptimeMillis();
int dirtyPhase2 = 0;
for (;;) {
int dirtyPhase1 = mDirty;
dirtyPhase2 |= dirtyPhase1;
mDirty = 0;
updateWakeLockSummaryLocked(dirtyPhase1);
updateUserActivitySummaryLocked(now, dirtyPhase1);
updateAttentiveStateLocked(now, dirtyPhase1);
if (!updateWakefulnessLocked(dirtyPhase1)) {
break;
}
}
// Phase 2: Lock profiles that became inactive/not kept awake.
updateProfilesLocked(now);
// Phase 3: Update display power state.
final boolean displayBecameReady = updateDisplayPowerStateLocked(dirtyPhase2);
// Phase 4: Update dream state (depends on display ready signal).
//更新屏保
updateDreamLocked(dirtyPhase2, displayBecameReady);
// Phase 5: Send notifications, if needed.
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!
updateSuspendBlockerLocked();
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
}
4.1 APP等进程向PowerManager申请的WakeLock在PowerManagerService中的名称变化
- 1、这里先简单提一下WakeLock,我们保持屏幕唤醒申请的是
PowerManager.PARTIAL_WAKE_LOCK
,使用距离传感器控制屏幕亮灭申请的是PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK
等等,这些是应用向PowerManager 申请的WakeLock,而且不同的应用申请各种WakeLock,因此在PMS 里面呢它用的是mWakeLockSummary与之对应,可以理解是持有wakeLock 的汇总概要,他的对应关系如下。
/** Get wake lock summary flags that correspond to the given wake lock. */
private int getWakeLockSummaryFlags(WakeLock wakeLock) {
switch (wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) {
case PowerManager.PARTIAL_WAKE_LOCK:
if (!wakeLock.mDisabled) {
// We only respect this if the wake lock is not disabled.
return WAKE_LOCK_CPU;
}
break;
case PowerManager.FULL_WAKE_LOCK:
return WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_BUTTON_BRIGHT;
case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
return WAKE_LOCK_SCREEN_BRIGHT;
case PowerManager.SCREEN_DIM_WAKE_LOCK:
return WAKE_LOCK_SCREEN_DIM;
case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK:
return WAKE_LOCK_PROXIMITY_SCREEN_OFF;
case PowerManager.DOZE_WAKE_LOCK:
return WAKE_LOCK_DOZE;
case PowerManager.DRAW_WAKE_LOCK:
return WAKE_LOCK_DRAW;
}
return 0;
}
4.2、updatePowerStateLocked 之 updateWakeLockSummaryLocked 整合PMS持有的wakelock 的状态
-
1、PMS整合所持有的Wakelock 过程都是一些按位运算,刚开始看的时候直接搞懵逼了。后来多看几遍发现清楚多了。
-
2、首选PMS获取从PowerManager里面申请的所有Wakelock的集合,然后将所有的Wakelock转化整合成 mWakeLockSummary。
-
3、通过getWakefulnessLocked()获取当前设置的Wakefulness,这里power键按下事件在前面设置过是
WAKEFULNESS_AWAKE
状态。然后根据当前的Wakefulness 和整合后的mWakeLockSummary,去对mWakeLockSummary重新赋值。
- 4、profile.mWakeLockSummary这个干嘛用的,我也不懂,有清除的记得Call 我。
/**
* Updates the value of mWakeLockSummary to summarize the state of all active wake locks.
* Note that most wake-locks are ignored when the system is asleep.
*
* This function must have no other side-effects.
*/
@SuppressWarnings("deprecation")
private void updateWakeLockSummaryLocked(int dirty) {
if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_WAKEFULNESS)) != 0) {
mWakeLockSummary = 0;
final int numProfiles = mProfilePowerState.size();
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);
final int wakeLockFlags = getWakeLockSummaryFlags(wakeLock);
mWakeLockSummary |= wakeLockFlags;
for (int j = 0; j < numProfiles; j++) {
final ProfilePowerState profile = mProfilePowerState.valueAt(j);
if (wakeLockAffectsUser(wakeLock, profile.mUserId)) {
profile.mWakeLockSummary |= wakeLockFlags;
}
}
}
mWakeLockSummary = adjustWakeLockSummaryLocked(mWakeLockSummary);
for (int i = 0; i < numProfiles; i++) {
final ProfilePowerState profile = mProfilePowerState.valueAt(i);
profile.mWakeLockSummary = adjustWakeLockSummaryLocked(profile.mWakeLockSummary);
}
if (DEBUG_SPEW) {
Slog.d(TAG, "updateWakeLockSummaryLocked: mWakefulness="
+ PowerManagerInternal.wakefulnessToString(getWakefulnessLocked())
+ ", mWakeLockSummary=0x" + Integer.toHexString(mWakeLockSummary));
}
}
}
private int adjustWakeLockSummaryLocked(int wakeLockSummary) {
// Cancel wake locks that make no sense based on the current state.
//如果当前wakefulness 不是打盹儿Dozing 状态就忽略WAKE_LOCK_DOZE 和WAKE_LOCK_DRAW
if (getWakefulnessLocked() != WAKEFULNESS_DOZING) {
wakeLockSummary &= ~(WAKE_LOCK_DOZE | WAKE_LOCK_DRAW);
}
//如果整合之后wakefulness 是 WAKEFULNESS_ASLEEP或者包含了WAKE_LOCK_DOZE状态就忽略WAKE_LOCK_SCREEN_BRIGHT 和WAKE_LOCK_SCREEN_DIM、WAKE_LOCK_BUTTON_BRIGHT这里还亮屏的状态。
if (getWakefulnessLocked() == WAKEFULNESS_ASLEEP
|| (wakeLockSummary & WAKE_LOCK_DOZE) != 0) {
wakeLockSummary &= ~(WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_SCREEN_DIM
| WAKE_LOCK_BUTTON_BRIGHT);
if (getWakefulnessLocked() == WAKEFULNESS_ASLEEP) {
wakeLockSummary &= ~WAKE_LOCK_PROXIMITY_SCREEN_OFF;
}
}
// Infer implied wake locks where necessary based on the current state.
/*这里开始应用整合之后的wakeLockSummary状态:
*1、如果整合之后wakefulness 包含亮屏的WAKE_LOCK_SCREEN_BRIGHT 或者 WAKE_LOCK_SCREEN_DIM,如果获取当前wakeLockSummary是WAKEFULNESS_AWAKE就把 wakeLockSummary 改为WAKE_LOCK_CPU | WAKE_LOCK_STAY_AWAKE.
*2、如果获取当前wakeLockSummary是WAKEFULNESS_DREAMING就把 wakeLockSummary 改为WAKE_LOCK_CPU.
*/
if ((wakeLockSummary & (WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_SCREEN_DIM)) != 0) {
if (getWakefulnessLocked() == WAKEFULNESS_AWAKE) {
wakeLockSummary |= WAKE_LOCK_CPU | WAKE_LOCK_STAY_AWAKE;
} Memcache技术之Memcached机制深入了解