前面的博客有提到过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.java
final WindowManagerPolicy mPolicy = new PhoneWindowManager();
所以这个mPolicy就是PhoneWindowManager对象。
frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java
-
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());会弹出选择界面。
frameworks/base/services/core/java/com/android/server/policy/GlobalActions.java
-
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<std::string>& 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 <unistd.h>
-
30 #include <sys/reboot.h>
-
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.S
-
3 #include <private/bionic_asm.h>
-
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。
bionic/libc/include/sys/reboot.h
-
/* 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);
走到这里就不再继续往下看了。