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 类中。
- keyEvent 转化为 keyEventObj;
- 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;
}
}
......
}
- 创建 GlobalActions 对象
- 调用 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() 显示对话框。
- 调用 createDialog() 创建对话框
- 调用 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);
}
}
......
}
- 创建 ProgressDialog
- 显示对话框
- ShutdownThread 成员变量各种赋值
- 启动 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();
}
......
}
- 关闭各种核心服务
- 调用 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);
}
......
}
- 关机前震动
- 关闭电源
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);
}
最后画流程图总结一下。