android 关机流程详细分析(转)

前面的博客有提到过android事件上报流程,InputReaderThread 从EventHub读到按键事件后,交给InputDispatcher 往上上报,我们从这里跟踪一下长按power键关键流程,

frameworks/native/services/inputflinger/InputDispatcher.cpp

 
  1. void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {

  2. mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags);

  3. }

 

这里的mPolicy是NativeInputManager对象.

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

 

 
  1. void NativeInputManager::interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags) {

  2. jobject keyEventObj = android_view_KeyEvent_fromNative(env, keyEvent);

  3. 886 jint wmActions;

  4. 887 if (keyEventObj) {

  5. 888 wmActions = env->CallIntMethod(mServiceObj,

  6. 889 gServiceClassInfo.interceptKeyBeforeQueueing,

  7. 890 keyEventObj, policyFlags);

  8. 891 if (checkAndClearExceptionFromCallback(env, "interceptKeyBeforeQueueing")) {

  9. 892 wmActions = 0;

  10. 893 }

  11. 894 android_view_KeyEvent_recycle(env, keyEventObj);

  12. 895 env->DeleteLocalRef(keyEventObj);

  13. 896 } else {

  14. 897 ALOGE("Failed to obtain key event object for interceptKeyBeforeQueueing.");

  15. 898 wmActions = 0;

  16. 899 }

  17. }

  18.  

这里会call到java层,call 到InputManagerService里面。

 

frameworks/base/services/core/java/com/android/server/input/InputManagerService.java

 

 
  1. // Native callback.

  2. 1871 private int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {

  3. 1872 return mWindowManagerCallbacks.interceptKeyBeforeQueueing(event, policyFlags);

 

这个mWindowManagerCallbacks 是通过下面的接口设置的。

inputManager.setWindowManagerCallbacks(wm.getInputMonitor());

继续追查下去,就是一个InputMonitor 实例。

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

 

 
  1. public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {

  2. return mService.mPolicy.interceptKeyBeforeQueueing(event, policyFlags);

  3. }

 

这里的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

 

 

 
  1. public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {

  2.  
  3. @Override

  4. public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {

  5. case KeyEvent.KEYCODE_POWER: {

  6. 5815 result &= ~ACTION_PASS_TO_USER;

  7. 5816 isWakeKey = false; // wake-up will be handled separately

  8. 5817 if (down) {

  9. 5818 interceptPowerKeyDown(event, interactive);

  10. 5819 } else {

  11. 5820 interceptPowerKeyUp(event, interactive, canceled);

  12. 5821 }

  13. 5822 break;

  14. 5823 }

继续走到interceptPowerKeyDown()函数里面。

 

 

private void interceptPowerKeyDown(KeyEvent event, boolean interactive) {
 
  1. ...

  2. if (interactive) {

  3. 1087 // When interactive, we're already awake.

  4. 1088 // Wait for a long press or for the button to be released to decide what to do.

  5. 1089 if (hasLongPressOnPowerBehavior()) {

  6. 1090 Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS);

  7. 1091 msg.setAsynchronous(true);

  8. 1092 mHandler.sendMessageDelayed(msg,

  9. 1093 ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());

  10. 1094 }

  11. 1095 }

}

这里面判断是长按power键后会发一个MSG_POWER_LONG_PRESS消息出来,我们看一下它的处理。

 

 

 
  1. private class PolicyHandler extends Handler {

  2. ...

  3. 746 @Override

  4. 747 public void handleMessage(Message msg) {

  5. 748 switch (msg.what) {

  6. case MSG_POWER_LONG_PRESS:

  7. 790 powerLongPress();

  8. 791 break;

 

 
  1. private void powerLongPress() {

  2. 1255 final int behavior = getResolvedLongPressOnPowerBehavior();

  3. 1256 switch (behavior) {

  4. 1257 case LONG_PRESS_POWER_NOTHING:

  5. 1258 break;

  6. 1259 case LONG_PRESS_POWER_GLOBAL_ACTIONS:

  7. 1260 mPowerKeyHandled = true;

  8. 1261 if (!performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false)) {

  9. 1262 performAuditoryFeedbackForAccessibilityIfNeed();

  10. 1263 }

  11. 1264 showGlobalActionsInternal();

  12. 1265 break;

  13. 1273 }

  14. 1274 }

接下来会走到showGlobalActionsInternal()函数里面。

 

 

 
  1. void showGlobalActionsInternal() {

  2. 1389 sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);

  3. 1390 if (mGlobalActions == null) {

  4. 1391 mGlobalActions = new GlobalActions(mContext, mWindowManagerFuncs);

  5. 1392 }

  6. 1393 final boolean keyguardShowing = isKeyguardShowingAndNotOccluded();

  7. 1394 mGlobalActions.showDialog(keyguardShowing, isDeviceProvisioned());

  8. 1395 if (keyguardShowing) {

  9. 1396 // since it took two seconds of long press to bring this up,

  10. 1397 // poke the wake lock so they have some time to see the dialog.

  11. 1398 mPowerManager.userActivity(SystemClock.uptimeMillis(), false);

  12. 1399 }

  13. 1400 }

 

showDialog(keyguardShowing, isDeviceProvisioned());会弹出选择界面。

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

 

 
  1. public void showDialog(boolean keyguardShowing, boolean isDeviceProvisioned) {

  2. 172 mKeyguardShowing = keyguardShowing;

  3. 173 mDeviceProvisioned = isDeviceProvisioned;

  4. 174 if (mDialog != null) {

  5. 175 mDialog.dismiss();

  6. 176 mDialog = null;

  7. 177 // Show delayed, so that the dismiss of the previous dialog completes

  8. 178 mHandler.sendEmptyMessage(MESSAGE_SHOW);

  9. 179 } else {

  10. 180 handleShow();

  11. 181 }

  12. 182 }

 

 
  1. private void handleShow() {

  2. 197 awakenIfNecessary();

  3. 198 mDialog = createDialog();

  4. 199 prepareDialog();

  5. 200

  6. 201 // If we only have 1 item and it's a simple press action, just do this action.

  7. 202 if (mAdapter.getCount() == 1

  8. 203 && mAdapter.getItem(0) instanceof SinglePressAction

  9. 204 && !(mAdapter.getItem(0) instanceof LongPressAction)) {

  10. 205 ((SinglePressAction) mAdapter.getItem(0)).onPress();

  11. 206 } else {

  12. 207 WindowManager.LayoutParams attrs = mDialog.getWindow().getAttributes();

  13. 208 attrs.setTitle("GlobalActions");

  14. 209 mDialog.getWindow().setAttributes(attrs);

  15. 210 mDialog.show();

  16. 211 mDialog.getWindow().getDecorView().setSystemUiVisibility(View.STATUS_BAR_DISABLE_EXPAND);

  17. 212 }

  18. 213 }

createDialog()里面很重要的一点是创建了多项选项按钮,并绑定了对应的处理函数。

 
  1. private GlobalActionsDialog createDialog() {

  2. if (GLOBAL_ACTION_KEY_POWER.equals(actionKey)) {

  3. 281 mItems.add(new PowerAction());

  4. 282 } else if (GLOBAL_ACTION_KEY_AIRPLANE.equals(actionKey)) {

  5. 283 mItems.add(mAirplaneModeOn);

  6. 284 }

  7.  
  8. }

关机对应的是PowerAction 。

 

 

 
  1. private final class PowerAction extends SinglePressAction implements LongPressAction {

  2. @Override

  3. 376 public void onPress() {

  4. 377 // shutdown by making sure radio and power are handled accordingly.

  5. 378 mWindowManagerFuncs.shutdown(false /* confirm */);

  6. 379 }

  7. 380 }

 

如果点击关机按钮,就会走到onPress(),调用WindowManagerservice的shutdown接口。

 

 
  1. // Called by window manager policy. Not exposed externally.

  2. 5823 @Override

  3. 5824 public void shutdown(boolean confirm) {

  4. 5825 ShutdownThread.shutdown(mContext, PowerManager.SHUTDOWN_USER_REQUESTED, confirm);

  5. 5826 }

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

 

 

 
  1. public static void shutdown(final Context context, String reason, boolean confirm) {

  2. 133 mReboot = false;

  3. 134 mRebootSafeMode = false;

  4. 135 mReason = reason;

  5. 136 shutdownInner(context, confirm);

  6. 137 }

 
  1. static void shutdownInner(final Context context, boolean confirm) {

  2. ...

  3. 159 if (confirm) {

  4. 160 final CloseDialogReceiver closer = new CloseDialogReceiver(context);

  5. 161 if (sConfirmDialog != null) {

  6. 162 sConfirmDialog.dismiss();

  7. 163 }

  8. 164 sConfirmDialog = new AlertDialog.Builder(context)

  9. 165 .setTitle(mRebootSafeMode

  10. 166 ? com.android.internal.R.string.reboot_safemode_title

  11. 167 : com.android.internal.R.string.power_off)

  12. 168 .setMessage(resourceId)

  13. 169 .setPositiveButton(com.android.internal.R.string.yes, new DialogInterface.OnClickListener() {

  14. 170 public void onClick(DialogInterface dialog, int which) {

  15. 171 beginShutdownSequence(context);

  16. 172 }

  17. 173 })

  18. 174 .setNegativeButton(com.android.internal.R.string.no, null)

  19. 175 .create();

  20. 176 closer.dialog = sConfirmDialog;

  21. 177 sConfirmDialog.setOnDismissListener(closer);

  22. 178 sConfirmDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);

  23. 179 sConfirmDialog.show();

  24. 180 } else {

  25. 181 beginShutdownSequence(context);

  26. 182 }

  27. 183 }

如果confirm为true,则弹出确认对话框,总之最终会走beginShutdownSequence(context) 进行接下来的关机流程。

 

 

 
  1. private static void beginShutdownSequence(Context context) {

  2. ...

  3. 276 if (PowerManager.REBOOT_RECOVERY_UPDATE.equals(mReason)) {

  4. ...

  5. 301 } else {

  6. 302 pd.setTitle(context.getText(com.android.internal.R.string.power_off));

  7. 303 pd.setMessage(context.getText(com.android.internal.R.string.shutdown_progress));

  8. 304 pd.setIndeterminate(true);

  9. 305 }

  10. 306 pd.setCancelable(false);

  11. 307 pd.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);

  12. 308

  13. 309 pd.show();

  14. 310 ...

  15. 341 // start the thread that initiates shutdown

  16. 342 sInstance.mHandler = new Handler() {

  17. 343 };

  18. 344 sInstance.start();

  19. 345 }

pd.show(); 显示关机的进度界面, sInstance.start(); 会启动另外一个线程,走接下来的关机流程。

 

 

private static final ShutdownThread sInstance = new ShutdownThread();

 

 

 
  1. 358 public void run() {

  2. 359 ...

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

  4. 385

  5. 386 // First send the high-level shut down broadcast.

  6. 387 mActionDone = false;

  7. 388 Intent intent = new Intent(Intent.ACTION_SHUTDOWN);

  8. 389 intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);

  9. 390 mContext.sendOrderedBroadcastAsUser(intent,

  10. 391 UserHandle.ALL, null, br, mHandler, 0, null, null);

  11. 392

  12. 393 ...

  13. 497 rebootOrShutdown(mContext, mReboot, mReason);

  14. 498 }

ShutdownThread启动之后,就会跑它的run()函数,做了很多工作,发送关机广播,做一些状态检查和清理工作。

 

 

 
  1. public static void rebootOrShutdown(final Context context, boolean reboot, String reason) {

  2. 644 if (reboot) {

  3. 645 Log.i(TAG, "Rebooting, reason: " + reason);

  4. 646 PowerManagerService.lowLevelReboot(reason);

  5. 647 Log.e(TAG, "Reboot failed, will attempt shutdown instead");

  6. 648 reason = null;

  7. 649 } else if (SHUTDOWN_VIBRATE_MS > 0 && context != null) {

  8. ...

  9. 664 }

  10. 665

  11. 666 // Shutdown power

  12. 667 Log.i(TAG, "Performing low-level shutdown...");

  13. 668 PowerManagerService.lowLevelShutdown(reason);

  14. 669 }

 

最后又跑到PowerManagerService 的lowLevelShutdown()。

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

 

 
  1. public static void lowLevelShutdown(String reason) {

  2. 2787 if (reason == null) {

  3. 2788 reason = "";

  4. 2789 }

  5. 2790 SystemProperties.set("sys.powerctl", "shutdown," + reason);

  6. 2791 }

 

很多人疑惑SystemProperties.set("sys.powerctl", "shutdown,"+ reason);又跑到了哪里?


 

首先sys.powerctl 在init.rc中有配置,它是一类特殊的property,可以认为是command。

它对应的处理函数定义在/system/core/init/builtins.cpp中。

 
  1. {"mount", {3, kMax, do_mount}},

  2. {"umount", {1, 1, do_umount}},

  3. {"powerctl", {1, 1, do_powerctl}},

  4. {"restart", {1, 1, do_restart}},

所以接着会调到do_powerctl(),注意传下来的参数有shutdown,所以cmd是ANDROID_RB_POWEROFF,reboot_target是上面传的reason字符串。

 
  1. static int do_powerctl(const std::vector<std::string>& args) {

  2. 696 const char* command = args[1].c_str();

  3. 697 int len = 0;

  4. 698 unsigned int cmd = 0;

  5. 699 const char *reboot_target = "";

  6. 700 void (*callback_on_ro_remount)(const struct mntent*) = NULL;

  7. 701

  8. 702 if (strncmp(command, "shutdown", 8) == 0) {

  9. 703 cmd = ANDROID_RB_POWEROFF;

  10. 704 len = 8;

  11. 705 } else if (strncmp(command, "reboot", 6) == 0) {

  12. 706 cmd = ANDROID_RB_RESTART2;

  13. 707 len = 6;

  14. 708 }

  15. ...

  16. 763 return android_reboot_with_callback(cmd, 0, reboot_target,

  17. 764 callback_on_ro_remount);

  18. 765 }

函数和cmd值在/system/core/include/cutils/android_reboot.h 中有声明

 
  1. int android_reboot_with_callback(

  2. 213 int cmd, int flags __unused, const char *arg,

  3. 214 void (*cb_on_remount)(const struct mntent*))

  4. 215 {

  5. 216 int ret;

  6. 217 remount_ro(cb_on_remount);

  7. 218 switch (cmd) {

  8. 219 case ANDROID_RB_RESTART:

  9. 220 ret = reboot(RB_AUTOBOOT);

  10. 221 break;

  11. 222

  12. 223 case ANDROID_RB_POWEROFF:

  13. 224 ret = reboot(RB_POWER_OFF);

  14. 225 break;

  15. 226

  16. 227 case ANDROID_RB_RESTART2:

  17. 228 ret = syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,

  18. 229 LINUX_REBOOT_CMD_RESTART2, arg);

  19. 230 break;

  20. 231

  21. 232 default:

  22. 233 ret = -1;

  23. 234 }

  24. 235

  25. 236 return ret;

  26. 237 }

所以最后又调用到了reboot()函数,传入的参数是RB_POWER_OFF。

reboot()定义在/bionic/libc/bionic/reboot.cpp

 
  1. #include <unistd.h>

  2. 30 #include <sys/reboot.h>

  3. 31

  4. 32 extern "C" int __reboot(int, int, int, void*);

  5. 33

  6. 34 int reboot(int mode) {

  7. 35 return __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, mode, NULL);

  8. 36 }

又调用到了__reboot(),在__reboot.s中用汇编实现,不同的cpu架构在不同目录下,比如32为arm平台。

bionic/libc/arch-arm/syscalls/__reboot.S

 

 
  1. 3 #include <private/bionic_asm.h>

  2. 4

  3. 5 ENTRY(__reboot)

  4. 6 mov ip, r7

  5. 7 .cfi_register r7, ip

  6. 8 ldr r7, =__NR_reboot

  7. 9 swi #0

  8. 10 mov r7, ip

  9. 11 .cfi_restore r7

  10. 12 cmn r0, #(MAX_ERRNO + 1)

  11. 13 bxls lr

  12. 14 neg r0, r0

  13. 15 b __set_errno_internal

  14. 16 END(__reboot)

 

这里又将__reboot的实现映射到了__NR_reboot。

bionic/libc/kernel/uapi/asm-generic/unistd.h

 

 
  1. /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */

  2. 219 #define __NR_rt_sigreturn 139

  3. 220 #define __NR_setpriority 140

  4. 221 #define __NR_getpriority 141

  5. 222 #define __NR_reboot 142

 

__NR_reboot对应的系统调用声明在Unistd.h中

linux-4.10/include/uapi/asm-generic/unistd.h

 

 
  1. #define __NR_rt_sigreturn 139

  2. 419 __SC_COMP(__NR_rt_sigreturn, sys_rt_sigreturn, compat_sys_rt_sigreturn)

  3. 420

  4. 421 /* kernel/sys.c */

  5. 422 #define __NR_setpriority 140

  6. 423 __SYSCALL(__NR_setpriority, sys_setpriority)

  7. 424 #define __NR_getpriority 141

  8. 425 __SYSCALL(__NR_getpriority, sys_getpriority)

  9. 426 #define __NR_reboot 142

  10. 427 __SYSCALL(__NR_reboot, sys_reboot)

 

对应的函数是sys_reboot(),声明在linux-4.10\include\linux\syscalls.h

 

 
  1. struct timespec __user *interval);

  2. 311 asmlinkage long sys_setpriority(int which, int who, int niceval);

  3. 312 asmlinkage long sys_getpriority(int which, int who);

  4. 313

  5. 314 asmlinkage long sys_shutdown(int, int);

  6. 315 asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd,

  7. 316 void __user *arg);

sys_reboot()的定义在linux-4.10.3\kernel\reboot.c。

 
  1. 280 SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,

  2. 281 void __user *, arg)

  3. 282 {

  4. 283 ...

  5. 314 mutex_lock(&reboot_mutex);

  6. 315 switch (cmd) {

  7. 316 case LINUX_REBOOT_CMD_RESTART:

  8. 317 kernel_restart(NULL);

  9. 318 break;

  10. 319

  11. 320 case LINUX_REBOOT_CMD_CAD_ON:

  12. 321 C_A_D = 1;

  13. 322 break;

  14. 323

  15. 324 case LINUX_REBOOT_CMD_CAD_OFF:

  16. 325 C_A_D = 0;

  17. 326 break;

  18. 327

  19. 328 case LINUX_REBOOT_CMD_HALT:

  20. 329 kernel_halt();

  21. 330 do_exit(0);

  22. 331 panic("cannot halt");

  23. 332

  24. 333 case LINUX_REBOOT_CMD_POWER_OFF:

  25. 334 kernel_power_off();

  26. 335 do_exit(0);

  27. 336 break;

  28. ...

  29. 361 default:

  30. 362 ret = -EINVAL;

  31. 363 break;

  32. 364 }

  33. 365 mutex_unlock(&reboot_mutex);

  34. 366 return ret;

  35. 367 }

mode从上面传下来的值是RB_POWER_OFF。
bionic/libc/include/sys/reboot.h

 

 
  1. /* use glibc names as well */

  2. 37

  3. 38 #define RB_AUTOBOOT LINUX_REBOOT_CMD_RESTART

  4. 39 #define RB_HALT_SYSTEM LINUX_REBOOT_CMD_HALT

  5. 40 #define RB_ENABLE_CAD LINUX_REBOOT_CMD_CAD_ON

  6. 41 #define RB_DISABLE_CAD LINUX_REBOOT_CMD_CAD_OFF

  7. 42 #define RB_POWER_OFF LINUX_REBOOT_CMD_POWER_OFF

所以接下来走到kernel_power_off(); 

 

 
  1. /**

  2. 253 * kernel_power_off - power_off the system

  3. 254 *

  4. 255 * Shutdown everything and perform a clean system power_off.

  5. 256 */

  6. 257 void kernel_power_off(void)

  7. 258 {

  8. 259 kernel_shutdown_prepare(SYSTEM_POWER_OFF);

  9. 260 if (pm_power_off_prepare)

  10. 261 pm_power_off_prepare();

  11. 262 migrate_to_reboot_cpu();

  12. 263 syscore_shutdown();

  13. 264 pr_emerg("Power down\n");

  14. 265 kmsg_dump(KMSG_DUMP_POWEROFF);

  15. 266 machine_power_off();

  16. 267 }

  17. 268 EXPORT_SYMBOL_GPL(kernel_power_off);


走到这里就不再继续往下看了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值