前言

因为源码剖析的代码量比拟大,大部分博客网站的内容显示页面都比拟窄,显示进去的成果都异样俊俏,所以您也能够间接查看 《 Thinking in Android 》 来浏览这边文章,心愿这篇文章能帮你梳理分明 “Android 关机流程”


外围源码

要害类门路
GlobalActions.javaframeworks/base/services/core/java/com/android/server/policy/GlobalActions.java
LegacyGlobalActions.javaframeworks/base/services/core/java/com/android/server/policy/LegacyGlobalActions.java
PhoneWindowManager.javaframeworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java
PowerManagerService.javaframeworks/base/services/core/java/com/android/server/power/PowerManagerService.java
ShutdownThread.javaframeworks/base/services/core/java/com/android/server/power/ShutdownThread.java
WindowManagerService.javaframeworks/base/services/core/java/com/android/server/wm/WindowManagerService.java


一、PhoneWindowManager

Android 零碎的关机流程是从用户按 power 键开始的,所有的按键解决都是通过 PhoneWindowManager.interceptKeyBeforeQueueing() 办法进行解决。

2.1 PhoneWindowManager.interceptKeyBeforeQueueing()

// frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.javapublic class PhoneWindowManager implements WindowManagerPolicy {    @Override    public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {        ... ...                // Handle special keys.        switch (keyCode) {            ... ...                        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) {                    // down 为 true,代表按下 power 键,走 interceptPowerKeyDown() 办法                    interceptPowerKeyDown(event, interactive);                } else {                    interceptPowerKeyUp(event, interactive, canceled);                }                break;            }            ... ...    }}

2.2 PhoneWindowManager.interceptPowerKeyDown()

// frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.javapublic class PhoneWindowManager implements WindowManagerPolicy {    private void interceptPowerKeyDown(KeyEvent event, boolean interactive) {        ... ...        // 截屏性能        if (interactive && !mScreenshotChordPowerKeyTriggered                && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {            mScreenshotChordPowerKeyTriggered = true;            mScreenshotChordPowerKeyTime = event.getDownTime();            interceptScreenshotChord();            interceptRingerToggleChord();        }        TelecomManager telecomManager = getTelecommService();        boolean hungUp = false;        if (telecomManager != null) {            if (telecomManager.isRinging()) {                telecomManager.silenceRinger();    // 如果复电时,按 Power 则静音            } else if ((mIncallPowerBehavior                    & Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP) != 0                    && telecomManager.isInCall() && interactive) {                hungUp = telecomManager.endCall();            }        }        ... ...        mPowerKeyHandled = hungUp || mScreenshotChordVolumeDownKeyTriggered                || mA11yShortcutChordVolumeUpKeyTriggered || gesturedServiceIntercepted;        if (!mPowerKeyHandled) {            if (interactive) {                if (hasLongPressOnPowerBehavior()) {                    if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) {                        powerLongPress();    // 长按 Power 键,外围办法                    } else {                        ... ...                    }                }            } else {                wakeUpFromPowerKey(event.getDownTime());                if (mSupportLongPressPowerWhenNonInteractive && hasLongPressOnPowerBehavior()) {                    if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) {                        powerLongPress();    // 长按 Power 键,外围办法                    } else {                        ... ...                    }                    mBeganFromNonInteractive = true;                } else {                    ... ...                }            }        }    }}

2.3 PhoneWindowManager.powerLongPress()

// frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.javapublic class PhoneWindowManager implements WindowManagerPolicy {    private void powerLongPress() {        final int behavior = getResolvedLongPressOnPowerBehavior();    // 失去长按电源键的行为        switch (behavior) {            case LONG_PRESS_POWER_NOTHING:                break;            case LONG_PRESS_POWER_GLOBAL_ACTIONS:    // 原生的会走这个 case                mPowerKeyHandled = true;                performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);                showGlobalActionsInternal();         // 调用 showGlobalActionsInternal() 办法                break;            ... ...        }    }}

powerLongPress() 有两个外围办法,getResolvedLongPressOnPowerBehavior()showGlobalActionsInternal(),咱们别离看下。

2.4 PhoneWindowManager.getResolvedLongPressOnPowerBehavior()

// frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.javapublic class PhoneWindowManager implements WindowManagerPolicy {    int mLongPressOnPowerBehavior;    mLongPressOnPowerBehavior = mContext.getResources().getInteger(                com.android.internal.R.integer.config_longPressOnPowerBehavior);    private int getResolvedLongPressOnPowerBehavior() {        if (FactoryTest.isLongPressOnPowerOffEnabled()) {            return LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM;        }        return mLongPressOnPowerBehavior;    // 返回 config_longPressOnPowerBehavior 的值    }}

其实就是获取 config_longPressOnPowerBehavior 的值,这个值是什么?

// frameworks/base/core/res/res/values/config.xml<!-- Control the behavior when the user long presses the power button.        0 - Nothing                             // 示意间接关机        1 - Global actions menu                 // 关机要显示 Global actions        2 - Power off (with confirmation)       // 关机要弹出对话框再次确认        3 - Power off (without confirmation)    // 关机不须要弹出对话框        4 - Go to voice assist--><integer name="config_longPressOnPowerBehavior">1</integer>    // 可设置默认值

2.5 PhoneWindowManager.showGlobalActionsInternal()

// frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.javapublic class PhoneWindowManager implements WindowManagerPolicy {    void showGlobalActionsInternal() {        if (mGlobalActions == null) {            mGlobalActions = new GlobalActions(mContext, mWindowManagerFuncs);        }        final boolean keyguardShowing = isKeyguardShowingAndNotOccluded();        mGlobalActions.showDialog(keyguardShowing, isDeviceProvisioned());    // 弹出关机的对话框        // 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);    }}

2.6 GlobalActions.showDialog()

// frameworks/base/services/core/java/com/android/server/policy/GlobalActions.javaclass GlobalActions implements GlobalActionsProvider.GlobalActionsListener {    private LegacyGlobalActions mLegacyGlobalActions;    public void showDialog(boolean keyguardShowing, boolean deviceProvisioned) {        if (DEBUG) Slog.d(TAG, "showDialog " + keyguardShowing + " " + deviceProvisioned);        if (mGlobalActionsProvider != null && mGlobalActionsProvider.isGlobalActionsDisabled()) {            return;        }        mKeyguardShowing = keyguardShowing;        mDeviceProvisioned = deviceProvisioned;        mShowing = true;        if (mGlobalActionsAvailable) {            mHandler.postDelayed(mShowTimeout, 5000);            mGlobalActionsProvider.showGlobalActions();        } else {            // SysUI isn't alive, show legacy menu.            ensureLegacyCreated();            // 调用 LegacyGlobalActions.showDialog() 办法            mLegacyGlobalActions.showDialog(mKeyguardShowing, mDeviceProvisioned);        }    }}

2.7 LegacyGlobalActions.showDialog()

// frameworks/base/services/core/java/com/android/server/policy/LegacyGlobalActions.javaclass LegacyGlobalActions implements DialogInterface.OnDismissListener, DialogInterface.OnClickListener  {    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();    // 如果 Dialog 不为空,则创立        }    }}

2.8 LegacyGlobalActions.handleShow()

// frameworks/base/services/core/java/com/android/server/policy/LegacyGlobalActions.javaclass LegacyGlobalActions implements DialogInterface.OnDismissListener, DialogInterface.OnClickListener  {    private void handleShow() {        awakenIfNecessary();        mDialog = createDialog();        prepareDialog();        // If we only have 1 item and it's a simple press action, just do this action.        if (mAdapter.getCount() == 1                && mAdapter.getItem(0) instanceof SinglePressAction                && !(mAdapter.getItem(0) instanceof LongPressAction)) {            ((SinglePressAction) mAdapter.getItem(0)).onPress();    // 调用 onPress() 办法        } else {            if (mDialog != null) {                WindowManager.LayoutParams attrs = mDialog.getWindow().getAttributes();                attrs.setTitle("LegacyGlobalActions");                mDialog.getWindow().setAttributes(attrs);                mDialog.show();                mDialog.getWindow().getDecorView().setSystemUiVisibility(                        View.STATUS_BAR_DISABLE_EXPAND);            }        }    }}

当点击 dialogpower off 时,会调用 PowerActiononPress() 办法。

2.9 PowerAction.onPress()

// frameworks/base/services/core/java/com/android/server/policy/PowerAction.javapublic final class PowerAction extends SinglePressAction implements LongPressAction {    @Override    public void onPress() {        // shutdown by making sure radio and power are handled accordingly.        mWindowManagerFuncs.shutdown(false /* confirm */);    // 调用 WindowManagerService.shutdown() 办法    }}

2.10 WindowManagerService.shutdown()

// frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.javapublic class WindowManagerService extends IWindowManager.Stub        implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {    // Called by window manager policy.  Not exposed externally.    @Override    public void shutdown(boolean confirm) {        // Pass in the UI context, since ShutdownThread requires it (to show UI).        // 调用 ShutdownThread.shutdown() 办法        ShutdownThread.shutdown(ActivityThread.currentActivityThread().getSystemUiContext(),                PowerManager.SHUTDOWN_USER_REQUESTED, confirm);    }}


三、ShutdownThread

Android 关机的流程最终是通过 ShutdownThread 线程实现。

3.1 ShutdownThread.shutdown()

// frameworks/base/services/core/java/com/android/server/power/ShutdownThread.javapublic final class ShutdownThread extends Thread {    public static void shutdown(final Context context, String reason, boolean confirm) {        mReboot = false;        mRebootSafeMode = false;        mReason = reason;        shutdownInner(context, confirm);    // 外部调用 shutdownInner() 办法    }}

3.2 ShutdownThread.shutdownInner()

// frameworks/base/services/core/java/com/android/server/power/ShutdownThread.javapublic final class ShutdownThread extends Thread {    private static void shutdownInner(final Context context, boolean confirm) {        context.assertRuntimeOverlayThemable();            synchronized (sIsStartedGuard) {            if (sIsStarted) {                Log.d(TAG, "Request to shutdown already running, returning.");                return;            }        }        // 获取用户长按 Power 键的解决行为        final int longPressBehavior = context.getResources().getInteger(                        com.android.internal.R.integer.config_longPressOnPowerBehavior);        final int resourceId = mRebootSafeMode                ? com.android.internal.R.string.reboot_safemode_confirm                : (longPressBehavior == 2                        ? com.android.internal.R.string.shutdown_confirm_question                        : com.android.internal.R.string.shutdown_confirm);        Log.d(TAG, "Notifying thread to start shutdown longPressBehavior=" + longPressBehavior);        if (confirm) {    // 弹出关机、重启对话框,供用户抉择            final CloseDialogReceiver closer = new CloseDialogReceiver(context);    // 注册关机对话框播送            if (sConfirmDialog != null) {                sConfirmDialog.dismiss();            }            // 创立关机 Dialog            sConfirmDialog = new AlertDialog.Builder(context)                    .setTitle(mRebootSafeMode                            ? com.android.internal.R.string.reboot_safemode_title                            : com.android.internal.R.string.power_off)                    .setMessage(resourceId)                    .setPositiveButton(com.android.internal.R.string.yes, new DialogInterface.OnClickListener() {                        public void onClick(DialogInterface dialog, int which) {                            beginShutdownSequence(context);    // 执行 beginShutdownSequence() 办法,开始关机流程                        }                    })                    .setNegativeButton(com.android.internal.R.string.no, null)                    .create();            closer.dialog = sConfirmDialog;            sConfirmDialog.setOnDismissListener(closer);            sConfirmDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);            sConfirmDialog.show();        } else {            beginShutdownSequence(context);        }    }}

3.3 ShutdownThread.beginShutdownSequence()

// frameworks/base/services/core/java/com/android/server/power/ShutdownThread.javapublic final class ShutdownThread extends Thread {    // static instance of this thread    private static final ShutdownThread sInstance = new ShutdownThread();    // 咱们个别能够在这个办法外面增加关机动画    private static void beginShutdownSequence(Context context) {        synchronized (sIsStartedGuard) {            if (sIsStarted) {                Log.d(TAG, "Shutdown sequence already running, returning.");                return;            }            sIsStarted = true;        }        sInstance.mProgressDialog = showShutdownDialog(context);    // 显示关机进度对话框        sInstance.mContext = context;        sInstance.mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);        ... ...        // // start the thread that initiates shutdown -- 启动关机线程 ,执行 Run 办法        sInstance.mHandler = new Handler() {        };        sInstance.start();    }}

3.4 ShutdownThread.run()

启动关机线程,执行 run();

// frameworks/base/services/core/java/com/android/server/power/ShutdownThread.javapublic final class ShutdownThread extends Thread {    public void run() {        ... ...        {            String reason = (mReboot ? "1" : "0") + (mReason != null ? mReason : "");            SystemProperties.set(SHUTDOWN_ACTION_PROPERTY, reason);    // 保留关机的起因        }        if (mRebootSafeMode) {            SystemProperties.set(REBOOT_SAFEMODE_PROPERTY, "1");        }        ... ...                // First send the high-level shut down broadcast.        mActionDone = false;        Intent intent = new Intent(Intent.ACTION_SHUTDOWN);        intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND | Intent.FLAG_RECEIVER_REGISTERED_ONLY);        // 发送关机播送        mContext.sendOrderedBroadcastAsUser(intent, UserHandle.ALL, null, br, mHandler, 0, null, null);        final long endTime = SystemClock.elapsedRealtime() + MAX_BROADCAST_TIME;        ... ...        if (mRebootHasProgressBar) {            sInstance.setRebootProgress(BROADCAST_STOP_PERCENT, null);        }        shutdownTimingLog.traceEnd(); // SendShutdownBroadcast -- 关机播送所用的工夫        ... ...        final IActivityManager am = IActivityManager.Stub.asInterface(ServiceManager.checkService("activity"));        if (am != null) {            try {                am.shutdown(MAX_BROADCAST_TIME);    // 敞开 ActivityManagerService 服务            } catch (RemoteException e) {            }        }        if (mRebootHasProgressBar) {            sInstance.setRebootProgress(ACTIVITY_MANAGER_STOP_PERCENT, null);        }        shutdownTimingLog.traceEnd();// ShutdownActivityManager        metricEnded(METRIC_AM);        Log.i(TAG, "Shutting down package manager...");        shutdownTimingLog.traceBegin("ShutdownPackageManager");        metricStarted(METRIC_PM);        final PackageManagerService pm = (PackageManagerService) ServiceManager.getService("package");        if (pm != null) {            pm.shutdown();    // 敞开 PackageManagerService 服务        }        ... ...    // 敞开一系列外围服务        saveMetrics(mReboot, mReason);        rebootOrShutdown(mContext, mReboot, mReason);    // 执行 rebootOrShutdown() 办法    }}

3.5 ShutdownThread.rebootOrShutdown()

rebootOrShutdown() 办法决定 关机 还是 重启

// frameworks/base/services/core/java/com/android/server/power/ShutdownThread.javapublic final class ShutdownThread extends Thread {    public static void rebootOrShutdown(final Context context, boolean reboot, String reason) {        if (reboot) {    // 判断是否重启            Log.i(TAG, "Rebooting, reason: " + reason);            PowerManagerService.lowLevelReboot(reason);            Log.e(TAG, "Reboot failed, will attempt shutdown instead");            reason = null;        } else if (SHUTDOWN_VIBRATE_MS > 0 && context != null) {            // vibrate before shutting down            Vibrator vibrator = new SystemVibrator(context);            try {                // 关机之前触动                vibrator.vibrate(SHUTDOWN_VIBRATE_MS, VIBRATION_ATTRIBUTES);            } catch (Exception e) {                // Failure to vibrate shouldn't interrupt shutdown.  Just log it.                Log.w(TAG, "Failed to vibrate during shutdown.", e);            }            // vibrator is asynchronous so we need to wait to avoid shutting down too soon.            try {                Thread.sleep(SHUTDOWN_VIBRATE_MS);            } catch (InterruptedException unused) {            }        }        // Shutdown power        Log.i(TAG, "Performing low-level shutdown...");        PowerManagerService.lowLevelShutdown(reason);    }}