前面的博客有提到过android事件上报流程,InputReaderThread 从EventHub读到按键事件后,交给InputDispatcher 往上上报,我们从这里跟踪一下长按power键关键流程,
frameworks/native/services/inputflinger/InputDispatcher.cpp
void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {
…
mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags);
…
}
这里的mPolicy是NativeInputManager对象.
frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
void NativeInputManager::interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags) {
…
jobject keyEventObj = android_view_KeyEvent_fromNative(env, keyEvent);
886 jint wmActions;
887 if (keyEventObj) {
888 wmActions = env->CallIntMethod(mServiceObj,
889 gServiceClassInfo.interceptKeyBeforeQueueing,
890 keyEventObj, policyFlags);
891 if (checkAndClearExceptionFromCallback(env, "interceptKeyBeforeQueueing")) {
892 wmActions = 0;
893 }
894 android_view_KeyEvent_recycle(env, keyEventObj);
895 env->DeleteLocalRef(keyEventObj);
896 } else {
897 ALOGE("Failed to obtain key event object for interceptKeyBeforeQueueing.");
898 wmActions = 0;
899 }
…
}
这里会call到java层,call 到InputManagerService里面。
frameworks/base/services/core/java/com/android/server/input/InputManagerService.java
// Native callback.
1871 private int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
1872 return mWindowManagerCallbacks.interceptKeyBeforeQueueing(event, policyFlags);
}
这个mWindowManagerCallbacks 是通过下面的接口设置的。
inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
继续追查下去,就是一个InputMonitor 实例。
frameworks/base/services/core/java/com/android/server/wm/InputMonitor.java
public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
return mService.mPolicy.interceptKeyBeforeQueueing(event, policyFlags);
}
这里的mService就是WindowManagerService。
frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.javafinal WindowManagerPolicy mPolicy = new PhoneWindowManager();
所以这个mPolicy就是PhoneWindowManager对象。
public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
@Override
public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
case KeyEvent.KEYCODE_POWER: {
5815 result &= ~ACTION_PASS_TO_USER;
5816 isWakeKey = false; // wake-up will be handled separately
5817 if (down) {
5818 interceptPowerKeyDown(event, interactive);
5819 } else {
5820 interceptPowerKeyUp(event, interactive, canceled);
5821 }
5822 break;
5823 }
}
继续走到interceptPowerKeyDown()函数里面。
private void interceptPowerKeyDown(KeyEvent event, boolean interactive) {
...
if (interactive) {
1087 // When interactive, we're already awake.
1088 // Wait for a long press or for the button to be released to decide what to do.
1089 if (hasLongPressOnPowerBehavior()) {
1090 Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS);
1091 msg.setAsynchronous(true);
1092 mHandler.sendMessageDelayed(msg,
1093 ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
1094 }
1095 }
}
这里面判断是长按power键后会发一个MSG_POWER_LONG_PRESS消息出来,我们看一下它的处理。
private class PolicyHandler extends Handler {
...
746 @Override
747 public void handleMessage(Message msg) {
748 switch (msg.what) {
case MSG_POWER_LONG_PRESS:
790 powerLongPress();
791 break;
}
}
private void powerLongPress() {
1255 final int behavior = getResolvedLongPressOnPowerBehavior();
1256 switch (behavior) {
1257 case LONG_PRESS_POWER_NOTHING:
1258 break;
1259 case LONG_PRESS_POWER_GLOBAL_ACTIONS:
1260 mPowerKeyHandled = true;
1261 if (!performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false)) {
1262 performAuditoryFeedbackForAccessibilityIfNeed();
1263 }
1264 showGlobalActionsInternal();
1265 break;
1273 }
1274 }
接下来会走到showGlobalActionsInternal()函数里面。
void showGlobalActionsInternal() {
1389 sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
1390 if (mGlobalActions == null) {
1391 mGlobalActions = new GlobalActions(mContext, mWindowManagerFuncs);
1392 }
1393 final boolean keyguardShowing = isKeyguardShowingAndNotOccluded();
1394 mGlobalActions.showDialog(keyguardShowing, isDeviceProvisioned());
1395 if (keyguardShowing) {
1396 // since it took two seconds of long press to bring this up,
1397 // poke the wake lock so they have some time to see the dialog.
1398 mPowerManager.userActivity(SystemClock.uptimeMillis(), false);
1399 }
1400 }
showDialog(keyguardShowing, isDeviceProvisioned());会弹出选择界面。
public void showDialog(boolean keyguardShowing, boolean isDeviceProvisioned) {
172 mKeyguardShowing = keyguardShowing;
173 mDeviceProvisioned = isDeviceProvisioned;
174 if (mDialog != null) {
175 mDialog.dismiss();
176 mDialog = null;
177 // Show delayed, so that the dismiss of the previous dialog completes
178 mHandler.sendEmptyMessage(MESSAGE_SHOW);
179 } else {
180 handleShow();
181 }
182 }
private void handleShow() {
197 awakenIfNecessary();
198 mDialog = createDialog();
199 prepareDialog();
200
201 // If we only have 1 item and it's a simple press action, just do this action.
202 if (mAdapter.getCount() == 1
203 && mAdapter.getItem(0) instanceof SinglePressAction
204 && !(mAdapter.getItem(0) instanceof LongPressAction)) {
205 ((SinglePressAction) mAdapter.getItem(0)).onPress();
206 } else {
207 WindowManager.LayoutParams attrs = mDialog.getWindow().getAttributes();
208 attrs.setTitle("GlobalActions");
209 mDialog.getWindow().setAttributes(attrs);
210 mDialog.show();
211 mDialog.getWindow().getDecorView().setSystemUiVisibility(View.STATUS_BAR_DISABLE_EXPAND);
212 }
213 }
createDialog()里面很重要的一点是创建了多项选项按钮,并绑定了对应的处理函数。
private GlobalActionsDialog createDialog() {
if (GLOBAL_ACTION_KEY_POWER.equals(actionKey)) {
281 mItems.add(new PowerAction());
282 } else if (GLOBAL_ACTION_KEY_AIRPLANE.equals(actionKey)) {
283 mItems.add(mAirplaneModeOn);
284 }
}
关机对应的是PowerAction 。
private final class PowerAction extends SinglePressAction implements LongPressAction {
@Override
376 public void onPress() {
377 // shutdown by making sure radio and power are handled accordingly.
378 mWindowManagerFuncs.shutdown(false /* confirm */);
379 }
380 }
如果点击关机按钮,就会走到onPress(),调用WindowManagerservice的shutdown接口。
// Called by window manager policy. Not exposed externally.
5823 @Override
5824 public void shutdown(boolean confirm) {
5825 ShutdownThread.shutdown(mContext, PowerManager.SHUTDOWN_USER_REQUESTED, confirm);
5826 }
frameworks/base/services/core/java/com/android/server/power/ShutdownThread.java
public static void shutdown(final Context context, String reason, boolean confirm) {
133 mReboot = false;
134 mRebootSafeMode = false;
135 mReason = reason;
136 shutdownInner(context, confirm);
137 }
static void shutdownInner(final Context context, boolean confirm) {
...
159 if (confirm) {
160 final CloseDialogReceiver closer = new CloseDialogReceiver(context);
161 if (sConfirmDialog != null) {
162 sConfirmDialog.dismiss();
163 }
164 sConfirmDialog = new AlertDialog.Builder(context)
165 .setTitle(mRebootSafeMode
166 ? com.android.internal.R.string.reboot_safemode_title
167 : com.android.internal.R.string.power_off)
168 .setMessage(resourceId)
169 .setPositiveButton(com.android.internal.R.string.yes, new DialogInterface.OnClickListener() {
170 public void onClick(DialogInterface dialog, int which) {
171 beginShutdownSequence(context);
172 }
173 })
174 .setNegativeButton(com.android.internal.R.string.no, null)
175 .create();
176 closer.dialog = sConfirmDialog;
177 sConfirmDialog.setOnDismissListener(closer);
178 sConfirmDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
179 sConfirmDialog.show();
180 } else {
181 beginShutdownSequence(context);
182 }
183 }
如果confirm为true,则弹出确认对话框,总之最终会走beginShutdownSequence(context) 进行接下来的关机流程。
private static void beginShutdownSequence(Context context) {
...
276 if (PowerManager.REBOOT_RECOVERY_UPDATE.equals(mReason)) {
...
301 } else {
302 pd.setTitle(context.getText(com.android.internal.R.string.power_off));
303 pd.setMessage(context.getText(com.android.internal.R.string.shutdown_progress));
304 pd.setIndeterminate(true);
305 }
306 pd.setCancelable(false);
307 pd.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
308
309 pd.show();
310 ...
341 // start the thread that initiates shutdown
342 sInstance.mHandler = new Handler() {
343 };
344 sInstance.start();
345 }
pd.show(); 显示关机的进度界面, sInstance.start(); 会启动另外一个线程,走接下来的关机流程。
private static final ShutdownThread sInstance = new ShutdownThread();
358 public void run() {
359 ...
384 Log.i(TAG, "Sending shutdown broadcast...");
385
386 // First send the high-level shut down broadcast.
387 mActionDone = false;
388 Intent intent = new Intent(Intent.ACTION_SHUTDOWN);
389 intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
390 mContext.sendOrderedBroadcastAsUser(intent,
391 UserHandle.ALL, null, br, mHandler, 0, null, null);
392
393 ...
497 rebootOrShutdown(mContext, mReboot, mReason);
498 }
ShutdownThread启动之后,就会跑它的run()函数,做了很多工作,发送关机广播,做一些状态检查和清理工作。
public static void rebootOrShutdown(final Context context, boolean reboot, String reason) {
644 if (reboot) {
645 Log.i(TAG, "Rebooting, reason: " + reason);
646 PowerManagerService.lowLevelReboot(reason);
647 Log.e(TAG, "Reboot failed, will attempt shutdown instead");
648 reason = null;
649 } else if (SHUTDOWN_VIBRATE_MS > 0 && context != null) {
...
664 }
665
666 // Shutdown power
667 Log.i(TAG, "Performing low-level shutdown...");
668 PowerManagerService.lowLevelShutdown(reason);
669 }
最后又跑到PowerManagerService 的lowLevelShutdown()。
frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java public static void lowLevelShutdown(String reason) {
2787 if (reason == null) {
2788 reason = "";
2789 }
2790 SystemProperties.set("sys.powerctl", "shutdown," + reason);
2791 }
很多人疑惑SystemProperties.set("sys.powerctl", "shutdown,"+ reason);又跑到了哪里?
首先sys.powerctl 在init.rc中有配置,它是一类特殊的property,可以认为是command。
它对应的处理函数定义在/system/core/init/builtins.cpp中。
{"mount", {3, kMax, do_mount}},
{"umount", {1, 1, do_umount}},
{"powerctl", {1, 1, do_powerctl}},
{"restart", {1, 1, do_restart}},
所以接着会调到do_powerctl(),注意传下来的参数有shutdown,所以cmd是ANDROID_RB_POWEROFF,reboot_target是上面传的reason字符串。
static int do_powerctl(const std::vector& args) {
696 const char* command = args[1].c_str();
697 int len = 0;
698 unsigned int cmd = 0;
699 const char *reboot_target = "";
700 void (*callback_on_ro_remount)(const struct mntent*) = NULL;
701
702 if (strncmp(command, "shutdown", 8) == 0) {
703 cmd = ANDROID_RB_POWEROFF;
704 len = 8;
705 } else if (strncmp(command, "reboot", 6) == 0) {
706 cmd = ANDROID_RB_RESTART2;
707 len = 6;
708 }
...
763 return android_reboot_with_callback(cmd, 0, reboot_target,
764 callback_on_ro_remount);
765 }
函数和cmd值在/system/core/include/cutils/android_reboot.h 中有声明
int android_reboot_with_callback(
213 int cmd, int flags __unused, const char *arg,
214 void (*cb_on_remount)(const struct mntent*))
215 {
216 int ret;
217 remount_ro(cb_on_remount);
218 switch (cmd) {
219 case ANDROID_RB_RESTART:
220 ret = reboot(RB_AUTOBOOT);
221 break;
222
223 case ANDROID_RB_POWEROFF:
224 ret = reboot(RB_POWER_OFF);
225 break;
226
227 case ANDROID_RB_RESTART2:
228 ret = syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
229 LINUX_REBOOT_CMD_RESTART2, arg);
230 break;
231
232 default:
233 ret = -1;
234 }
235
236 return ret;
237 }
所以最后又调用到了reboot()函数,传入的参数是RB_POWER_OFF。
reboot()定义在/bionic/libc/bionic/reboot.cpp
#include
30 #include
31
32 extern "C" int __reboot(int, int, int, void*);
33
34 int reboot(int mode) {
35 return __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, mode, NULL);
36 }
又调用到了__reboot(),在__reboot.s中用汇编实现,不同的cpu架构在不同目录下,比如32为arm平台。
bionic/libc/arch-arm/syscalls/__reboot.S3 #include
4
5 ENTRY(__reboot)
6 mov ip, r7
7 .cfi_register r7, ip
8 ldr r7, =__NR_reboot
9 swi #0
10 mov r7, ip
11 .cfi_restore r7
12 cmn r0, #(MAX_ERRNO + 1)
13 bxls lr
14 neg r0, r0
15 b __set_errno_internal
16 END(__reboot)
这里又将__reboot的实现映射到了__NR_reboot。
bionic/libc/kernel/uapi/asm-generic/unistd.h/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
219 #define __NR_rt_sigreturn 139
220 #define __NR_setpriority 140
221 #define __NR_getpriority 141
222 #define __NR_reboot 142
__NR_reboot对应的系统调用声明在Unistd.h中
linux-4.10/include/uapi/asm-generic/unistd.h #define __NR_rt_sigreturn 139
419 __SC_COMP(__NR_rt_sigreturn, sys_rt_sigreturn, compat_sys_rt_sigreturn)
420
421 /* kernel/sys.c */
422 #define __NR_setpriority 140
423 __SYSCALL(__NR_setpriority, sys_setpriority)
424 #define __NR_getpriority 141
425 __SYSCALL(__NR_getpriority, sys_getpriority)
426 #define __NR_reboot 142
427 __SYSCALL(__NR_reboot, sys_reboot)
对应的函数是sys_reboot(),声明在linux-4.10\include\linux\syscalls.h
struct timespec __user *interval);
311 asmlinkage long sys_setpriority(int which, int who, int niceval);
312 asmlinkage long sys_getpriority(int which, int who);
313
314 asmlinkage long sys_shutdown(int, int);
315 asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd,
316 void __user *arg);
sys_reboot()的定义在linux-4.10.3\kernel\reboot.c。
280 SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,
281 void __user *, arg)
282 {
283 ...
314 mutex_lock(&reboot_mutex);
315 switch (cmd) {
316 case LINUX_REBOOT_CMD_RESTART:
317 kernel_restart(NULL);
318 break;
319
320 case LINUX_REBOOT_CMD_CAD_ON:
321 C_A_D = 1;
322 break;
323
324 case LINUX_REBOOT_CMD_CAD_OFF:
325 C_A_D = 0;
326 break;
327
328 case LINUX_REBOOT_CMD_HALT:
329 kernel_halt();
330 do_exit(0);
331 panic("cannot halt");
332
333 case LINUX_REBOOT_CMD_POWER_OFF:
334 kernel_power_off();
335 do_exit(0);
336 break;
...
361 default:
362 ret = -EINVAL;
363 break;
364 }
365 mutex_unlock(&reboot_mutex);
366 return ret;
367 }
mode从上面传下来的值是RB_POWER_OFF。
/* use glibc names as well */
37
38 #define RB_AUTOBOOT LINUX_REBOOT_CMD_RESTART
39 #define RB_HALT_SYSTEM LINUX_REBOOT_CMD_HALT
40 #define RB_ENABLE_CAD LINUX_REBOOT_CMD_CAD_ON
41 #define RB_DISABLE_CAD LINUX_REBOOT_CMD_CAD_OFF
42 #define RB_POWER_OFF LINUX_REBOOT_CMD_POWER_OFF
所以接下来走到kernel_power_off();
/**
253 * kernel_power_off - power_off the system
254 *
255 * Shutdown everything and perform a clean system power_off.
256 */
257 void kernel_power_off(void)
258 {
259 kernel_shutdown_prepare(SYSTEM_POWER_OFF);
260 if (pm_power_off_prepare)
261 pm_power_off_prepare();
262 migrate_to_reboot_cpu();
263 syscore_shutdown();
264 pr_emerg("Power down\n");
265 kmsg_dump(KMSG_DUMP_POWEROFF);
266 machine_power_off();
267 }
268 EXPORT_SYMBOL_GPL(kernel_power_off);