Android O关机流程

Android O关机流程


问题起因

*今天测试提出了一个问题,关机过程中(播放关机动画)按Power键可以熄屏、亮屏。

解决方案

*首先我想应该从关机流程开始吧,然后自己一步步跟进代码,修改framework代码逻辑,在关机时,禁用Power键

关机流程

想必都很清楚正常关机是如何操作的,按Power键来确定关机,这里首先来分析一下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这个函数。

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;
                }
            }
        }
    }
}

直接看关键部分,判断是否是LongPress,是的话就通过Handler发送消息处理,追踪到mHandler,handlemessage里面调用powerLongPress()这个私有函数来处理长按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设置为true表示这个行为已经被处理了,其实是正在处理。showGlobalActionsInternal()这个函数我想应该就是处理长按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);
    }
}

果不其然,创建了GlobalActions类对象,而从注释该类介绍来看是一个创建全局对话框的帮助类,构造方法中获得各种系统服务,其中有AudioManager、WindowManagerFuncs,其中关机我们应该看的是WindowManagerFuncs这个服务,他获取的是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方法最终调用createDialog();这个方法来创建GlobalActionsDialog这个对话框对象,其中利用各种参数Action来控制item的各种行为,我们这里要看的就是PowerAction

private final class PowerAction extends SinglePressAction implements LongPressAction {
    ...
    @Override
    public void onPress() {         
       mWindowManagerFuncs.shutdown(true/* confirm */);      
    }
}

看到这里就都明白了,通过对话框关机,这里调用的是mWindowManagerFuncs.shutdown,这个方法,这里mWindowManagerFuncs也就是WindowManagerService这个服务

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

其中通过名字可以知道调用了一个关机线程来处理,简单点的话就可以直接追踪到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...

首先发送关机广播,关闭一系列服务AMS、PKMS、radio、NFC等等等,等待关机动画完成。

  • 流程理清楚了,解决起来就很简单了,在ShutdownThread设置一个静态成员变量 public static boolean isShutDowning = false; ,执行run方法就将这个标示设为true
  • 然后在PhoneWindowManager的powerPress函数中添加判断是否禁用Power。

验证了也确实OK

你可能感兴趣的:(Android O关机流程)