Android O關(guān)機(jī)流程
問題起因
*今天測試提出了一個(gè)問題缨叫,關(guān)機(jī)過程中(播放關(guān)機(jī)動畫)按Power鍵可以熄屏卒煞、亮屏狸驳。
解決方案
*首先我想應(yīng)該從關(guān)機(jī)流程開始吧藕咏,然后自己一步步跟進(jìn)代碼,修改framework代碼邏輯贸铜,在關(guān)機(jī)時(shí)堡纬,禁用Power鍵
關(guān)機(jī)流程
想必都很清楚正常關(guān)機(jī)是如何操作的,按Power鍵來確定關(guān)機(jī)蒿秦,這里首先來分析一下PhoneWindowManager這個(gè)類隐轩,這個(gè)類Power、volum等事件處理
PhoneWindowManager.java
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;
}
...
}
}
因?yàn)槭前聪翽ower走的interceptPowerKeyDown這個(gè)函數(shù)渤早。
private void interceptPowerKeyDown(KeyEvent event, boolean interactive) {
...
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.
if (hasLongPressOnPowerBehavior()) {
Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS);
msg.setAsynchronous(true);
mHandler.sendMessageDelayed(msg,
ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
}
} else {
wakeUpFromPowerKey(event.getDownTime());
if (mSupportLongPressPowerWhenNonInteractive && hasLongPressOnPowerBehavior()) {
Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS);
msg.setAsynchronous(true);
mHandler.sendMessageDelayed(msg,
ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
mBeganFromNonInteractive = true;
} else {
final int maxCount = getMaxMultiPressPowerCount();
if (maxCount <= 1) {
mPowerKeyHandled = true;
} else {
mBeganFromNonInteractive = true;
}
}
}
}
}
直接看關(guān)鍵部分,判斷是否是LongPress职车,是的話就通過Handler發(fā)送消息處理,追蹤到mHandler鹊杖,handlemessage里面調(diào)用powerLongPress()這個(gè)私有函數(shù)來處理長按power悴灵。
private void powerLongPress() {
final int behavior = getResolvedLongPressOnPowerBehavior();
switch (behavior) {
case LONG_PRESS_POWER_NOTHING:
break;
case LONG_PRESS_POWER_GLOBAL_ACTIONS:
mPowerKeyHandled = true;
if (!performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false)) {
performAuditoryFeedbackForAccessibilityIfNeed();
}
showGlobalActionsInternal();
break;
case LONG_PRESS_POWER_SHUT_OFF:
case LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM:
mPowerKeyHandled = true;
performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
mWindowManagerFuncs.shutdown(behavior == LONG_PRESS_POWER_SHUT_OFF);
break;
}
}
將mPowerKeyHandled設(shè)置為true表示這個(gè)行為已經(jīng)被處理了,其實(shí)是正在處理骂蓖。showGlobalActionsInternal()這個(gè)函數(shù)我想應(yīng)該就是處理長按power顯示的對話框吧积瞒。
void showGlobalActionsInternal() {
sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
if (mGlobalActions == null) {
mGlobalActions = new GlobalActions(mContext, mWindowManagerFuncs);
}
final boolean keyguardShowing = isKeyguardShowingAndNotOccluded();
mGlobalActions.showDialog(keyguardShowing, isDeviceProvisioned());
if (keyguardShowing) {
// since it took two seconds of long press to bring this up,
// poke the wake lock so they have some time to see the dialog.
mPowerManager.userActivity(SystemClock.uptimeMillis(), false);
}
}
果不其然,創(chuàng)建了GlobalActions類對象登下,而從注釋該類介紹來看是一個(gè)創(chuàng)建全局對話框的幫助類茫孔,構(gòu)造方法中獲得各種系統(tǒng)服務(wù),其中有AudioManager被芳、WindowManagerFuncs缰贝,其中關(guān)機(jī)我們應(yīng)該看的是WindowManagerFuncs這個(gè)服務(wù),他獲取的是WindowManagerService畔濒。再來看showDialog這個(gè)方法剩晴。
public void showDialog(boolean keyguardShowing, boolean isDeviceProvisioned) {
mKeyguardShowing = keyguardShowing;
mDeviceProvisioned = isDeviceProvisioned;
if (mDialog != null) {
mDialog.dismiss();
mDialog = null;
// Show delayed, so that the dismiss of the previous dialog completes
mHandler.sendEmptyMessage(MESSAGE_SHOW);
} else {
handleShow();
}
}
private GlobalActionsDialog createDialog() {
...
if (GLOBAL_ACTION_KEY_POWER.equals(actionKey)) {
mItems.add(new PowerAction());
} else if (GLOBAL_ACTION_KEY_REBOOT.equals(actionKey)) {
mItems.add(new RebootAction());
}
...
}
其中handleShow方法最終調(diào)用createDialog();這個(gè)方法來創(chuàng)建GlobalActionsDialog這個(gè)對話框?qū)ο螅渲欣酶鞣N參數(shù)Action來控制item的各種行為侵状,我們這里要看的就是PowerAction
private final class PowerAction extends SinglePressAction implements LongPressAction {
...
@Override
public void onPress() {
mWindowManagerFuncs.shutdown(true/* confirm */);
}
}
看到這里就都明白了赞弥,通過對話框關(guān)機(jī),這里調(diào)用的是mWindowManagerFuncs.shutdown趣兄,這個(gè)方法绽左,這里mWindowManagerFuncs也就是WindowManagerService這個(gè)服務(wù)
@Override
public void shutdown(boolean confirm) {
ShutdownThread.shutdown(mContext, PowerManager.SHUTDOWN_USER_REQUESTED, confirm);
}
其中通過名字可以知道調(diào)用了一個(gè)關(guān)機(jī)線程來處理,簡單點(diǎn)的話就可以直接追蹤到run方法艇潭。這里就不知道看代碼了拼窥,通過打印信息來看看做了什么
11-18 20:00:17.061 1361-5920/system_process I/ShutdownThread: Sending shutdown broadcast...
11-18 20:00:18.710 1361-5920/system_process I/ShutdownThread: Shutting down activity manager...
11-18 20:00:18.913 1361-5920/system_process I/ShutdownThread: Shutting down package manager...
11-18 20:00:18.937 1361-6051/system_process W/ShutdownThread: Turning off cellular radios...
11-18 20:00:18.953 1361-6051/system_process I/ShutdownThread: Waiting for NFC, Bluetooth and Radio...
11-18 20:00:19.455 1361-6051/system_process I/ShutdownThread: Radio turned off.
11-18 20:00:19.455 1361-6051/system_process I/ShutdownThread: NFC, Radio and Bluetooth shutdown complete.
11-18 20:00:19.459 1361-5920/system_process I/ShutdownThread: Shutting down MountService
11-18 20:00:20.461 1361-5920/system_process W/ShutdownThread: Shutdown wait timed out
11-18 20:00:20.504 1361-5920/system_process I/ShutdownThread: waitShutdownAnimation true
11-18 20:00:20.510 1361-5920/system_process I/ShutdownThread: wait SHUTDOWN_ANIMATION_SERVICE completed. time out 14
11-18 20:00:20.836 1361-1712/system_process W/ShutdownThread: Result code 0 from MountService.shutdown
11-18 20:00:21.510 1361-5920/system_process I/ShutdownThread: wait SHUTDOWN_ANIMATION_SERVICE completed. time out 13
11-18 20:00:22.511 1361-5920/system_process I/ShutdownThread: wait SHUTDOWN_ANIMATION_SERVICE completed. time out 12
11-18 20:00:23.511 1361-5920/system_process I/ShutdownThread: wait SHUTDOWN_ANIMATION_SERVICE completed. time out 11
11-18 20:00:24.512 1361-5920/system_process I/ShutdownThread: wait SHUTDOWN_ANIMATION_SERVICE completed. time out 10
11-18 20:00:26.014 1361-5920/system_process I/ShutdownThread: Performing low-level shutdown...
首先發(fā)送關(guān)機(jī)廣播承粤,關(guān)閉一系列服務(wù)AMS、PKMS闯团、radio、NFC等等等仙粱,等待關(guān)機(jī)動畫完成房交。
- 流程理清楚了,解決起來就很簡單了伐割,在ShutdownThread設(shè)置一個(gè)靜態(tài)成員變量 public static boolean isShutDowning = false; 候味,執(zhí)行run方法就將這個(gè)標(biāo)示設(shè)為true
- 然后在PhoneWindowManager的powerPress函數(shù)中添加判斷是否禁用Power。
驗(yàn)證了也確實(shí)OK