【 Android 10 系统启动 】系列 -- ShutdownThread(关机流程)

# 前言

由于源码分析的代码量比较大,大部分博客网站的内容显示页面都比较窄,显示出来的效果都异常丑陋,所以您也可以直接查看 《 Thinking in Android 》 来阅读这边文章,希望这篇文章能帮你梳理清楚 “Android 关机流程”


# 核心源码

关键类 路径
GlobalActions.java frameworks/base/services/core/java/com/android/server/policy/GlobalActions.java
LegacyGlobalActions.java frameworks/base/services/core/java/com/android/server/policy/LegacyGlobalActions.java
PhoneWindowManager.java frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java
PowerManagerService.java frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
ShutdownThread.java frameworks/base/services/core/java/com/android/server/power/ShutdownThread.java
WindowManagerService.java frameworks/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.java

public 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.java

public 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.java

public 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.java

public 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.java

public 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.java

class 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.java

class 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.java

class 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.java

public 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.java

public 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.java

public 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.java

public 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.java

public 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.java

public 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.java

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

}

你可能感兴趣的:(【 Android 10 系统启动 】系列 -- ShutdownThread(关机流程))