前言

由于源码分析的代码量比较大,大部分博客网站的内容显示页面都比较窄,显示出来的效果都异常丑陋,所以您也可以直接查看 《 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.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.xml1    // 可设置默认值

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

更多相关文章

  1. 浅谈Java中Collections.sort对List排序的两种方法
  2. Python list sort方法的具体使用
  3. python list.sort()根据多个关键字排序的方法实现
  4. Android(安卓)8.1 中Systemui中的常见修改(六)NavigationBar加载流
  5. Android中如何像 360 一样优雅的杀死后台服务而不启动
  6. android调用第三方软件打开下载的附件
  7. 自定义View系列教程07--详解ViewGroup分发Touch事件
  8. Android(安卓)Menu学习
  9. android:configChanges属性

随机推荐

  1. android java开发 第一天 之熟悉eclipse
  2. 获取手机通讯录
  3. 修复 XE8 for Android 方向传感器 headin
  4. android发生主机无法解析错误的问题(
  5. Android 内存数据库
  6. Android(安卓)中sp、dp、px转换,以及获取
  7. 2011.06.21(2)——— android invalidate
  8. android 长按power键弹出对话框
  9. Android(安卓)Action静态广播收不到(系统
  10. android NoSuchMethodError getDrawable