Power 键长按 3s 可触发设备关机流程,关机我们能想到的有首先结束当前正在运行的界面,接着关闭显示屏,然后各种设备下电,最后设备彻底关闭。

在《Android 源码 输入系统之 InputReader》一节中,调用 InputDispatcher 类 notifyKey 方法,其中调用了 InputDispatcherPolicyInterface(mPolicy) 类的 interceptKeyBeforeQueueing 方法,这会拦截关机键输入事件。

frameworks/native/services/inputflinger/InputDispatcher.cpp

void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {
    ......
    // 验证按键事件是否有效
    if (!validateKeyEvent(args->action)) {
        return;
    }
    ......
    // 创建 KeyEvent 对象
    KeyEvent event;
    event.initialize(args->deviceId, args->source, args->action,
            flags, keyCode, args->scanCode, metaState, 0,
            args->downTime, args->eventTime);
    // 在排队之前,先拦截触摸,轨迹球或其他运动事件。
    // 策略可以将此方法用作执行电源管理功能和早期事件预处理(例如更新策略标志)的机会。
    // 如果应将事件分派给应用程序,则此方法应设置POLICY_FLAG_PASS_TO_USER策略标志。
    mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags);
    ......
}

NativeInputManager 继承自 InputDispatcherPolicyInterface 类,最终 interceptKeyBeforeQueueing 实现在 NativeInputManager 类中。

  1. keyEvent 转化为 keyEventObj;
  2. Native 直接调用 Java 层 InputManagerService 类的 interceptKeyBeforeQueueing 方法。

frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp

void NativeInputManager::interceptKeyBeforeQueueing(const KeyEvent* keyEvent,
        uint32_t& policyFlags) {
    ......
    if ((policyFlags & POLICY_FLAG_TRUSTED)) {
        nsecs_t when = keyEvent->getEventTime();
        JNIEnv* env = jniEnv();
        jobject keyEventObj = android_view_KeyEvent_fromNative(env, keyEvent);
        jint wmActions;
        if (keyEventObj) {
            wmActions = env->CallIntMethod(mServiceObj,
                    gServiceClassInfo.interceptKeyBeforeQueueing,
                    keyEventObj, policyFlags);
            ......
            android_view_KeyEvent_recycle(env, keyEventObj);
            env->DeleteLocalRef(keyEventObj);
        } else {
            ......
        }
        ......
    } else {
        ......
    }
}

回顾《Android 源码 InputManagerService 初始化》一节,InputManagerService 初始化之后,马上调用了其 setWindowManagerCallbacks 方法,入参是通过 WindowManagerService 类 getInputMonitor() 方法获取的,它是 InputMonitor 类型。

所以 InputManagerService 类的 interceptKeyBeforeQueueing 方法的实现实际上是由 InputMonitor 类 interceptKeyBeforeQueueing 方法支持的。

frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp

public class InputManagerService extends IInputManager.Stub
        implements Watchdog.Monitor {
    ......
    // Native callback.
    private int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
        return mWindowManagerCallbacks.interceptKeyBeforeQueueing(event, policyFlags);
    }
    ......
}

InputMonitor 类 interceptKeyBeforeQueueing 方法将工作直接委托给了 PhoneWindowManager 类 interceptKeyBeforeQueueing 方法。

frameworks/base/services/core/java/com/android/server/wm/InputMonitor.java

final class InputMonitor implements InputManagerService.WindowManagerCallbacks {
    private final WindowManagerService mService;
    ......
    @Override
    public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
        return mService.mPolicy.interceptKeyBeforeQueueing(event, policyFlags);
    }
    ......
}

WindowManagerService 类 mPolicy 成员实际指向 PhoneWindowManager 对象。

frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java

public class WindowManagerService extends IWindowManager.Stub
        implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {
    ......
    final WindowManagerPolicy mPolicy = new PhoneWindowManager();
    ......
}

POWER 键在此处做了处理,由于长按首先是 POWER 键按下事件,因此会进入 interceptPowerKeyDown 方法处理。

frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java

public class PhoneWindowManager implements WindowManagerPolicy {
    ......
    @Override
    public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
        ......
        final boolean interactive = (policyFlags & FLAG_INTERACTIVE) != 0;
        final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
        final boolean canceled = event.isCanceled();
        final int keyCode = event.getKeyCode();
        ......
        // 处理特殊键。
        switch (keyCode) {
            ......
            case KeyEvent.KEYCODE_POWER: {
                result &= ~ACTION_PASS_TO_USER;
                isWakeKey = false; // 唤醒将另行处理
                if (down) {
                    interceptPowerKeyDown(event, interactive);
                } else {
                    interceptPowerKeyUp(event, interactive, canceled);
                }
                break;
            }
            ......
        }
        ......
        return result;
    }
    ......
}

interactive 为 true 表示在事件被拦截时设备处于交互状态。通过 Handler 发送一个延时消息 MSG_POWER_LONG_PRESS。

frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java

public class PhoneWindowManager implements WindowManagerPolicy {
    ......
    private void interceptPowerKeyDown(KeyEvent event, boolean interactive) {
        ......
        // 如果仍未处理电源键,则检测短按、长按或多按并决定要做什么。
        mPowerKeyHandled = hungUp || mScreenshotChordVolumeDownKeyTriggered
                || mScreenshotChordVolumeUpKeyTriggered || gesturedServiceIntercepted;
        if (!mPowerKeyHandled) {
            if (interactive) {
                if (hasLongPressOnPowerBehavior()) {
                    Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS);
                    // 异步消息
                    msg.setAsynchronous(true);
                    mHandler.sendMessageDelayed(msg,
                            ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
                }
            } else {
                ......
            }
        }
    }
    ......
}

mHandler 是一个 PolicyHandler 对象,MSG_POWER_LONG_PRESS 延时消息最终在 handleMessage 方法中处理,调用 powerLongPress() 进行下一步处理。

frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java

public class PhoneWindowManager implements WindowManagerPolicy {
    ......
    private class PolicyHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                ......
                case MSG_POWER_LONG_PRESS:
                    powerLongPress();
                    break;
                ......
            }
        }
    }
    ......
    @Override
    public void init(Context context, IWindowManager windowManager,
            WindowManagerFuncs windowManagerFuncs) {
        ......
        mHandler = new PolicyHandler();
        ......
    }
    ......
}

长按电源键会弹出确认关机对话框,所以实际进入了 LONG_PRESS_POWER_GLOBAL_ACTIONS 分支。接下来会执行 showGlobalActionsInternal() 方法。

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_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;
        }
    }
    ......
}
  1. 创建 GlobalActions 对象
  2. 调用 GlobalActions 类 showDialog 方法显示关机对话框(列表对话框只有一项–关机)

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

调用 handleShow() 显示对话框。

  1. 调用 createDialog() 创建对话框
  2. 调用 Dialog 类 show() 方法显示对话框

frameworks/base/services/core/java/com/android/server/policy/GlobalActions.java

class GlobalActions implements DialogInterface.OnDismissListener, DialogInterface.OnClickListener  {
    ......
    public void showDialog(boolean keyguardShowing, boolean isDeviceProvisioned) {
        mKeyguardShowing = keyguardShowing;
        mDeviceProvisioned = isDeviceProvisioned;
        if (mDialog != null) {
            ......
        } else {
            // 显示对话框
            handleShow();
        }
    }
    ......
    private void handleShow() {
        awakenIfNecessary();
        // 创建对话框
        mDialog = createDialog();
        prepareDialog();

        // 如果只有一项,并且是个简单按钮动作,直接执行相应的操作
        if (mAdapter.getCount() == 1
                && mAdapter.getItem(0) instanceof SinglePressAction
                && !(mAdapter.getItem(0) instanceof LongPressAction)) {
            ((SinglePressAction) mAdapter.getItem(0)).onPress();
        } else {
            WindowManager.LayoutParams attrs = mDialog.getWindow().getAttributes();
            attrs.setTitle("GlobalActions");
            mDialog.getWindow().setAttributes(attrs);
            // 显示对话框
            mDialog.show();
            mDialog.getWindow().getDecorView().setSystemUiVisibility(View.STATUS_BAR_DISABLE_EXPAND);
        }
    }
    ......
}

点击关机项最终会调用 PowerAction 类的 onPress(),方法内会调用 WindowManagerService 类 shutdown 实现关机处理。

frameworks/base/services/core/java/com/android/server/policy/GlobalActions.java

class GlobalActions implements DialogInterface.OnDismissListener, DialogInterface.OnClickListener  {
    ......
    private final class PowerAction extends SinglePressAction implements LongPressAction {
        private PowerAction() {
            super(com.android.internal.R.drawable.ic_lock_power_off,
                R.string.global_action_power_off);
        }

        ......

        @Override
        public void onPress() {
            // 关闭时,要确保 radio 和 power 都得到相应的处理。
            mWindowManagerFuncs.shutdown(false /* confirm */);
        }
    }
    ......
}

WindowManagerService 实现了 WindowManagerPolicy.WindowManagerFuncs 接口,mWindowManagerFuncs 是在 PhoneWindowManager 初始化的时候赋值的。

frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java

public class WindowManagerService extends IWindowManager.Stub
        implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {
    ......
    @Override
    public void shutdown(boolean confirm) {
        ShutdownThread.shutdown(mContext, confirm);
    }
    ......
}

传递来的 confirm = false,最终会执行 beginShutdownSequence 方法。

frameworks/base/services/core/java/com/android/server/power/ShutdownThread.java

public final class ShutdownThread extends Thread {
    ......
    public static void shutdown(final Context context, boolean confirm) {
        ......
        shutdownInner(context, confirm);
    }

    static void shutdownInner(final Context context, boolean confirm) {
        ......
        if (confirm) {
            ......
        } else {
            beginShutdownSequence(context);
        }
    }
    ......
}
  1. 创建 ProgressDialog
  2. 显示对话框
  3. ShutdownThread 成员变量各种赋值
  4. 启动 ShutdownThread 线程

frameworks/base/services/core/java/com/android/server/power/ShutdownThread.java

public final class ShutdownThread extends Thread {
    ......
    private static void beginShutdownSequence(Context context) {
        synchronized (sIsStartedGuard) {
            if (sIsStarted) {
                Log.d(TAG, "Shutdown sequence already running, returning.");
                return;
            }
            sIsStarted = true;
        }

        // 抛出系统对话框以指示设备正在重新启动/关闭。
        ProgressDialog pd = new ProgressDialog(context);
        ......
        if (PowerManager.REBOOT_RECOVERY.equals(mRebootReason)) {
            ......
        } else {
            pd.setTitle(context.getText(com.android.internal.R.string.power_off));
            pd.setMessage(context.getText(com.android.internal.R.string.shutdown_progress));
            pd.setIndeterminate(true);
        }
        pd.setCancelable(false);
        pd.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
        // 显示对话框
        pd.show();

        sInstance.mProgressDialog = pd;
        sInstance.mContext = context;
        sInstance.mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);

        // 确保我们再也不会 sleep
        sInstance.mCpuWakeLock = null;
        try {
            sInstance.mCpuWakeLock = sInstance.mPowerManager.newWakeLock(
                    PowerManager.PARTIAL_WAKE_LOCK, TAG + "-cpu");
            sInstance.mCpuWakeLock.setReferenceCounted(false);
            sInstance.mCpuWakeLock.acquire();
        } catch (SecurityException e) {
            Log.w(TAG, "No permission to acquire wake lock", e);
            sInstance.mCpuWakeLock = null;
        }

        // 还要确保屏幕一直点亮着
        sInstance.mScreenWakeLock = null;
        if (sInstance.mPowerManager.isScreenOn()) {
            try {
                sInstance.mScreenWakeLock = sInstance.mPowerManager.newWakeLock(
                        PowerManager.FULL_WAKE_LOCK, TAG + "-screen");
                sInstance.mScreenWakeLock.setReferenceCounted(false);
                sInstance.mScreenWakeLock.acquire();
            } catch (SecurityException e) {
                Log.w(TAG, "No permission to acquire wake lock", e);
                sInstance.mScreenWakeLock = null;
            }
        }

        sInstance.mHandler = new Handler() {
        };
        // 启动关机的线程
        sInstance.start();
    }
    ......
}
  1. 关闭各种核心服务
  2. 调用 rebootOrShutdown 方法进一步关机

frameworks/base/services/core/java/com/android/server/power/ShutdownThread.java

public final class ShutdownThread extends Thread {
    ......
    public void run() {
        BroadcastReceiver br = new BroadcastReceiver() {
            @Override public void onReceive(Context context, Intent intent) {
                // We don't allow apps to cancel this, so ignore the result.
                actionDone();
            }
        };

        /*
         * 编写一个系统属性,以防在实际重启硬件之前重新启动 system_server。
         * 如果发生这种情况,我们将在启动 SystemServer 时重试。
         */
        {
            String reason = (mReboot ? "1" : "0") + (mRebootReason != null ? mRebootReason : "");
            SystemProperties.set(SHUTDOWN_ACTION_PROPERTY, reason);
        }

        /*
         * 如果我们重新启动到安全模式,写一个系统属性指示。
         */
        if (mRebootSafeMode) {
            SystemProperties.set(REBOOT_SAFEMODE_PROPERTY, "1");
        }

        Log.i(TAG, "Sending shutdown broadcast...");

        // 首先发送高层关闭广播。
        mActionDone = false;
        Intent intent = new Intent(Intent.ACTION_SHUTDOWN);
        intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
        mContext.sendOrderedBroadcastAsUser(intent,
                UserHandle.ALL, null, br, mHandler, 0, null, null);

        final long endTime = SystemClock.elapsedRealtime() + MAX_BROADCAST_TIME;
        synchronized (mActionDoneSync) {
            while (!mActionDone) {
                long delay = endTime - SystemClock.elapsedRealtime();
                if (delay <= 0) {
                    Log.w(TAG, "Shutdown broadcast timed out");
                    break;
                } else if (mRebootUpdate) {
                    int status = (int)((MAX_BROADCAST_TIME - delay) * 1.0 *
                            BROADCAST_STOP_PERCENT / MAX_BROADCAST_TIME);
                    sInstance.setRebootProgress(status, null);
                }
                try {
                    mActionDoneSync.wait(Math.min(delay, PHONE_STATE_POLL_SLEEP_MSEC));
                } catch (InterruptedException e) {
                }
            }
        }
        if (mRebootUpdate) {
            sInstance.setRebootProgress(BROADCAST_STOP_PERCENT, null);
        }

        Log.i(TAG, "Shutting down activity manager...");
        // 关闭 ActivityManagerService
        final IActivityManager am =
            ActivityManagerNative.asInterface(ServiceManager.checkService("activity"));
        if (am != null) {
            try {
                am.shutdown(MAX_BROADCAST_TIME);
            } catch (RemoteException e) {
            }
        }
        if (mRebootUpdate) {
            sInstance.setRebootProgress(ACTIVITY_MANAGER_STOP_PERCENT, null);
        }

        Log.i(TAG, "Shutting down package manager...");
        // 关闭 PackageManagerService
        final PackageManagerService pm = (PackageManagerService)
            ServiceManager.getService("package");
        if (pm != null) {
            pm.shutdown();
        }
        if (mRebootUpdate) {
            sInstance.setRebootProgress(PACKAGE_MANAGER_STOP_PERCENT, null);
        }

        // 关闭 radios.
        shutdownRadios(MAX_RADIO_WAIT_TIME);
        if (mRebootUpdate) {
            sInstance.setRebootProgress(RADIO_STOP_PERCENT, null);
        }

        // 关闭 MountService,确保媒体处于安全状态
        IMountShutdownObserver observer = new IMountShutdownObserver.Stub() {
            public void onShutDownComplete(int statusCode) throws RemoteException {
                Log.w(TAG, "Result code " + statusCode + " from MountService.shutdown");
                actionDone();
            }
        };

        Log.i(TAG, "Shutting down MountService");

        // 设置初始变量和超时时间。
        mActionDone = false;
        final long endShutTime = SystemClock.elapsedRealtime() + MAX_SHUTDOWN_WAIT_TIME;
        synchronized (mActionDoneSync) {
            try {
                final IMountService mount = IMountService.Stub.asInterface(
                        ServiceManager.checkService("mount"));
                if (mount != null) {
                    mount.shutdown(observer);
                } else {
                    Log.w(TAG, "MountService unavailable for shutdown");
                }
            } catch (Exception e) {
                Log.e(TAG, "Exception during MountService shutdown", e);
            }
            while (!mActionDone) {
                long delay = endShutTime - SystemClock.elapsedRealtime();
                if (delay <= 0) {
                    Log.w(TAG, "Shutdown wait timed out");
                    break;
                } else if (mRebootUpdate) {
                    int status = (int)((MAX_SHUTDOWN_WAIT_TIME - delay) * 1.0 *
                            (MOUNT_SERVICE_STOP_PERCENT - RADIO_STOP_PERCENT) /
                            MAX_SHUTDOWN_WAIT_TIME);
                    status += RADIO_STOP_PERCENT;
                    sInstance.setRebootProgress(status, null);
                }
                try {
                    mActionDoneSync.wait(Math.min(delay, PHONE_STATE_POLL_SLEEP_MSEC));
                } catch (InterruptedException e) {
                }
            }
        }
        if (mRebootUpdate) {
            sInstance.setRebootProgress(MOUNT_SERVICE_STOP_PERCENT, null);

            // 如果要重新启动以安装更新,请通过 init 服务调用 uncrypt。
            uncrypt();
        }

        rebootOrShutdown(mContext, mReboot, mRebootReason);
    }

    ......
}
  1. 关机前震动
  2. 关闭电源

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) {
            ......
        } else if (SHUTDOWN_VIBRATE_MS > 0 && context != null) {
            // 在关机前震动
            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);
            }

            // 振动器是异步的,所以我们需要等待,以避免过早关闭。
            try {
                Thread.sleep(SHUTDOWN_VIBRATE_MS);
            } catch (InterruptedException unused) {
            }
        }

        // 关闭电源
        Log.i(TAG, "Performing low-level shutdown...");
        PowerManagerService.lowLevelShutdown();
    }

    ......
}

低级功能可立即关闭设备,而无需进行“清理”。

frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java

public final class PowerManagerService extends SystemService
        implements Watchdog.Monitor {
    ......
    public static void lowLevelShutdown() {
        SystemProperties.set("sys.powerctl", "shutdown");
    }
    ......
}

sys.powerctl 属性写入 shutdown 字符串,代表触发某种触发器(触发器是可用于匹配某些类型的事件并用于引起操作发生的字符串)。

powerctl 代表内部实现细节用于响应对“sys.powerctl”系统属性的更改,用于实现重启。

/system/core/rootdir/init.rc

on property:sys.powerctl=*
    powerctl ${sys.powerctl}

根据前面关于 init 文章分析,不难得出最终会执行 do_powerctl 函数。cmd 赋值为 ANDROID_RB_POWEROFF。

system/core/init/builtins.cpp

int do_powerctl(int nargs, char **args)
{
    char command[PROP_VALUE_MAX];
    int res;
    int len = 0;
    int cmd = 0;
    const char *reboot_target;

    res = expand_props(command, args[1], sizeof(command));
    if (res) {
        ERROR("powerctl: cannot expand '%s'\n", args[1]);
        return -EINVAL;
    }

    if (strncmp(command, "shutdown", 8) == 0) {
        cmd = ANDROID_RB_POWEROFF;
        len = 8;
    } else if (strncmp(command, "reboot", 6) == 0) {
        cmd = ANDROID_RB_RESTART2;
        len = 6;
    } else {
        ERROR("powerctl: unrecognized command '%s'\n", command);
        return -EINVAL;
    }

    if (command[len] == ',') {
        reboot_target = &command[len + 1];
    } else if (command[len] == '\0') {
        reboot_target = "";
    } else {
        ERROR("powerctl: unrecognized reboot target '%s'\n", &command[len]);
        return -EINVAL;
    }

    return android_reboot(cmd, 0, reboot_target);
}

分支到 ANDROID_RB_POWEROFF,最终调用了 sys/reboot.h 头文件下的 reboot 函数。

system/core/libcutils/android_reboot.c

int android_reboot(int cmd, int flags UNUSED, const char *arg)
{
    int ret;

    sync();
    remount_ro();

    switch (cmd) {
        ......
        case ANDROID_RB_POWEROFF:
            ret = reboot(RB_POWER_OFF);
            break;
        ......
    }

    return ret;
}

sys/reboot.h 头文件下的 reboot 函数实现在 reboot.cpp 中。最终进入 Linux 内核关机流程。

bionic/libc/bionic/reboot.cpp

#include <unistd.h>
#include <sys/reboot.h>

extern "C" int __reboot(int, int, int, void*);

int reboot(int mode) {
  return __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, mode, NULL);
}

最后画流程图总结一下。

简述Android系统关机流程 安卓关机流程_ide