Android O關(guān)機(jī)流程

Android O關(guān)機(jī)流程


問題起因

*今天測試提出了一個問題,關(guān)機(jī)過程中(播放關(guān)機(jī)動畫)按Power鍵可以熄屏、亮屏。

解決方案

*首先我想應(yīng)該從關(guān)機(jī)流程開始吧,然后自己一步步跟進(jìn)代碼,修改framework代碼邏輯,在關(guān)機(jī)時,禁用Power鍵

關(guān)機(jī)流程

想必都很清楚正常關(guān)機(jī)是如何操作的,按Power鍵來確定關(guān)機(jī),這里首先來分析一下PhoneWindowManager這個類,這個類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;
        }
     ...
     }
 }

因為是按下Power走的interceptPowerKeyDown這個函數(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()這個私有函數(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表示這個行為已經(jīng)被處理了,其實是正在處理。showGlobalActionsInternal()這個函數(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類對象,而從注釋該類介紹來看是一個創(chuàng)建全局對話框的幫助類,構(gòu)造方法中獲得各種系統(tǒng)服務(wù),其中有AudioManager、WindowManagerFuncs,其中關(guān)機(jī)我們應(yīng)該看的是WindowManagerFuncs這個服務(wù),他獲取的是WindowManagerService。再來看showDialog這個方法。

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();這個方法來創(chuàng)建GlobalActionsDialog這個對話框?qū)ο?,其中利用各種參數(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,這個方法,這里mWindowManagerFuncs也就是WindowManagerService這個服務(wù)

@Override
public void shutdown(boolean confirm) {
    ShutdownThread.shutdown(mContext, PowerManager.SHUTDOWN_USER_REQUESTED, confirm);
}

其中通過名字可以知道調(diào)用了一個關(guān)機(jī)線程來處理,簡單點的話就可以直接追蹤到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è)置一個靜態(tài)成員變量 public static boolean isShutDowning = false; ,執(zhí)行run方法就將這個標(biāo)示設(shè)為true
  • 然后在PhoneWindowManager的powerPress函數(shù)中添加判斷是否禁用Power。

驗證了也確實OK

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 前面我們講解了系統(tǒng)截屏按鍵處理流程,HOME按鍵處理流程,今天再來講解一下電源開關(guān)機(jī)按鍵事件流程。關(guān)機(jī)操作也是系統(tǒng)...
    一航j(luò)ason閱讀 2,261評論 0 0
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,214評論 25 708
  • 1:InputChannel提供函數(shù)創(chuàng)建底層的Pipe對象 2: 1)客戶端需要新建窗口 2)new ViewRo...
    自由人是工程師閱讀 5,717評論 0 18
  • 今天是我的生日,父親! 哦,忘了,這不需要我提醒你的,你一直都記得從來不會忘記,從小到大,從我成為你的兒子...
    稻泓閱讀 286評論 0 0
  • 懂得那么多的道理卻還是過不好這一生,或許是現(xiàn)代人最真實的寫照。困頓,迷惘,彷徨,誰都有過,有人終其一生也無法自拔。...
    李彧飛閱讀 311評論 6 1

友情鏈接更多精彩內(nèi)容