android 关机流程详细分析

来源:互联网 发布:男网络歌手好听的歌曲 编辑:程序博客网 时间:2024/05/21 22:57

前面的博客有提到过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) {@Overridepublic int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {   case KeyEvent.KEYCODE_POWER: {5815                  result &= ~ACTION_PASS_TO_USER;5816                  isWakeKey = false; // wake-up will be handled separately5817                  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          @Override747          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 completes178              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() == 1203                  && mAdapter.getItem(0) instanceof SinglePressAction204                  && !(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 {  @Override376          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      @Override5824      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(mRebootSafeMode166                              ? com.android.internal.R.string.reboot_safemode_title167                              : 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 shutdown342          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 power667          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, r77      .cfi_register r7, ip8      ldr     r7, =__NR_reboot9      swi     #010      mov     r7, ip11      .cfi_restore r712      cmn     r0, #(MAX_ERRNO + 1)13      bxls    lr14      neg     r0, r015      b       __set_errno_internal16  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 139220  #define __NR_setpriority 140221  #define __NR_getpriority 141222  #define __NR_reboot 142

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

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

 #define __NR_rt_sigreturn 139419  __SC_COMP(__NR_rt_sigreturn, sys_rt_sigreturn, compat_sys_rt_sigreturn)420  421  /* kernel/sys.c */422  #define __NR_setpriority 140423  __SYSCALL(__NR_setpriority, sys_setpriority)424  #define __NR_getpriority 141425  __SYSCALL(__NR_getpriority, sys_getpriority)426  #define __NR_reboot 142427  __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_RESTART39  #define RB_HALT_SYSTEM  LINUX_REBOOT_CMD_HALT40  #define RB_ENABLE_CAD   LINUX_REBOOT_CMD_CAD_ON41  #define RB_DISABLE_CAD  LINUX_REBOOT_CMD_CAD_OFF42  #define RB_POWER_OFF    LINUX_REBOOT_CMD_POWER_OFF
所以接下来走到kernel_power_off(); 

 /**253   *kernel_power_off - power_off the system254   *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);

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