Power键使用的场景和使用的频率都很高,本次从浅层次了解它.首先看一下使用它的场景:
power键:
单击事件:
1,息屏休眠
2,亮屏唤醒
长按事件:
3,长按关机
4,长按开机
双击事件:
5,双击进相机
组合事件:
关机:
6,power + vol-进recovery
7,power + vol+进Factory test mode
开机:
8,power + vol-截屏
特殊事件:
9,通话挂断
上面是一个参考示例,不一定所有手机厂商都是这样做的,但都大同小异.1,2,3,5,8,9是在Android正常模式下作用的,4是SoC级作用的,6,7是在uboot下作用的.
篇幅有限,本次只研究前4种情况,其它情况不做详细介绍.其中第4中情况(长按开机)已经在第7篇开机流程中介绍过了.
首先是power的物理操作,会通过底层驱动一层层上传,到Framework时,经过InputManagerService处理按键事件后,最终将传递给PhoneWindowManager的dispatchUnhandledKey().
public KeyEvent dispatchUnhandledKey(WindowState win, KeyEvent event, int policyFlags) {
...
if (!interceptFallback(win, fallbackEvent, policyFlags)) {
fallbackEvent.recycle();
fallbackEvent = null;
}
...
}
private boolean interceptFallback(WindowState win, KeyEvent fallbackEvent, int policyFlags) {
int actions = interceptKeyBeforeQueueing(fallbackEvent, policyFlags);
if ((actions & ACTION_PASS_TO_USER) != 0) {
long delayMillis = interceptKeyBeforeDispatching(
win, fallbackEvent, policyFlags);
if (delayMillis == 0) {
return true;
}
}
return false;
}
其中interceptKeyBeforeQueueing()处理具体的业务逻辑:
public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
...
switch (keyCode) {
...
case KeyEvent.KEYCODE_POWER: {
// 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;
}
...
}
...
if (isWakeKey) {
// 按power键时,isWakeKey置为false,于是不会调用wakeUp函数,即不会唤醒系统点亮屏幕
wakeUp(event.getEventTime(), mAllowTheaterModeWakeFromKey, "android.policy:KEY");
}
return result;
}
接下来我们分别看一下interceptPowerKeyDown()和interceptPowerKeyUp()处理流程.
1,息屏休眠
息屏休眠过程用到的是interceptPowerKeyUp,代码如下:
private void interceptPowerKeyUp(KeyEvent event, boolean interactive, boolean canceled) {
// 事件被取消,或者在按下Power键时,该事件已被消耗掉,那么就不用继续处理
final boolean handled = canceled || mPowerKeyHandled;
mScreenshotChordPowerKeyTriggered = false;
// 退出截屏
cancelPendingScreenshotChordAction();
// 取消MSG_POWER_LONG_PRESS事件,即在一定事件内Power键弹起,则表示这一次不是长按Power键
cancelPendingPowerKeyAction();
if (!handled) {
// Figure out how to handle the key now that it has been released.
mPowerKeyPressCounter += 1;
final int maxCount = getMaxMultiPressPowerCount();
final long eventTime = event.getDownTime();
if (mPowerKeyPressCounter < maxCount) {
// This could be a multi-press. Wait a little bit longer to confirm.
// Continue holding the wake lock.
// 处理Power键被多次按下场景对应,
Message msg = mHandler.obtainMessage(MSG_POWER_DELAYED_PRESS,
interactive ? 1 : 0, mPowerKeyPressCounter, eventTime);
msg.setAsynchronous(true);
mHandler.sendMessageDelayed(msg, ViewConfiguration.getMultiPressTimeout());
return;
}
// No other actions. Handle it immediately.
powerPress(eventTime, interactive, mPowerKeyPressCounter);
}
// Done. Reset our state.
finishPowerKeyPress();
}
其中powerPress处理具体时间,finishPowerKeyPress复位按键状态,这里,我们跟一下powerPress:
private void powerPress(long eventTime, boolean interactive, int count) {
...
if (count == 2) {
powerMultiPressAction(eventTime, interactive, mDoublePressOnPowerBehavior);
} else if (count == 3) {
powerMultiPressAction(eventTime, interactive, mTriplePressOnPowerBehavior);
} else if (interactive && !mBeganFromNonInteractive) {
switch (mShortPressOnPowerBehavior) {
case SHORT_PRESS_POWER_NOTHING:
break;
case SHORT_PRESS_POWER_GO_TO_SLEEP: // 最终执行这里,调用PMS的goToSleep
goToSleep(eventTime, PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, 0);
break;
...
}
}
}
PowerManagerService.java
private void goToSleepInternal(long eventTime, int reason, int flags, int uid) {
synchronized (mLock) {
if (goToSleepNoUpdateLocked(eventTime, reason, flags, uid)) {
updatePowerStateLocked();
}
}
}
public void goToSleep(long eventTime, int reason, int flags) {
...
try {
goToSleepInternal(eventTime, reason, flags, uid);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
会执行goToSleepNoUpdateLocked:
@SuppressWarnings("deprecation")
private boolean goToSleepNoUpdateLocked(long eventTime, int reason, int flags, int uid) {
...
try {
...
// 标记最后一次灭屏时间
mLastSleepTime = eventTime;
// 是否进入屏保
mSandmanSummoned = true;
// 设置wakefulness值为WAKEFULNESS_DOZING,因此先进Doze状态
setWakefulnessLocked(WAKEFULNESS_DOZING, reason);
// Report the number of wake locks that will be cleared by going to sleep.
// 灭屏时,将清除以下三种使得屏幕保持亮屏的wakelock锁
int numWakeLocksCleared = 0;
fin