SoFunction
Updated on 2025-03-11

Analysis of the entire process of Android system shutdown

In the PowerManager API documentation, a shutdown/restart interface is given:
public void reboot (String reason)

The description of this interface is very simple, just a few words.
The function of the interface is to restart the device, and even if the restart is successful, there is no return value.
REBOOT permission is required, that is
The only parameter reason represents the specific restart mode required, such as recovery, and of course it can be null.

1. Upper space
/base/core/java/android/os/

/** 
 * Reboot the device. Will not return if the reboot is 
 * successful. Requires the {@link #REBOOT} 
 * permission. 
 * 
 * @param reason code to pass to the kernel (., "recovery") to 
 *        request special boot modes, or null. 
 */ 
public void reboot(String reason) 
{   
  try { 
    (reason); 
  } catch (RemoteException e) { 
  }   
}  

mService serves the IPowerManager Binder interface.

/** 
 * {@hide} 
 */ 
public PowerManager(IPowerManager service, Handler handler) 
{ 
  mService = service; 
  mHandler = handler; 
} 

/base/core/java/android/os/

interface IPowerManager 
{ 
... 
void reboot(String reason); 
... 
} 

/base/services/java/com/android/server/

/**  
 * Reboot the device immediately, passing 'reason' (may be null) 
 * to the underlying __reboot system call. Should not return. 
 */ 
public void reboot(String reason) 
{   
  (, null); 
 
  if (mHandler == null || !()) { 
    throw new IllegalStateException("Too early to call reboot()"); 
  }   
 
  final String finalReason = reason; 
  Runnable runnable = new Runnable() { 
    public void run() { 
      synchronized (this) { 
        (getUiContext(), finalReason, false); 
      }   
 
    }   
  };   
  // ShutdownThread must run on a looper capable of displaying the UI. 
  (runnable); 
 
  // () is documented not to return so just wait for the inevitable. 
  synchronized (runnable) { 
    while (true) { 
      try { 
        (); 
      } catch (InterruptedException e) {  
      }   
    }   
  }   
} 

/base/services/java/com/android/server/pm/

/** 
 * Request a clean shutdown, waiting for subsystems to clean up their 
 * state etc. Must be called from a Looper thread in which its UI 
 * is shown. 
 * 
 * @param context Context used to display the shutdown progress dialog. 
 * @param reason code to pass to the kernel (. "recovery"), or null. 
 * @param confirm true if user confirmation is needed before shutting down. 
 */ 
public static void reboot(final Context context, String reason, boolean confirm) { 
  mReboot = true; 
  mRebootSafeMode = false; 
  mRebootReason = reason; 
  shutdownInner(context, confirm); 
} 

This means that it needs to be restarted, and it is not a safe mode. The restart parameter is the passed reason. The confirm parameter of shutdownInner is used to set whether there is a confirmation prompt box. There is no restart through the reboot interface, which is false.
The restart implementation is in run(), because ShutdownThread is an extension of Thread, run will run automatically.

/** 
 * Makes sure we handle the shutdown gracefully. 
 * Shuts off power regardless of radio and bluetooth state if the alloted time has passed. 
 */  
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(); 
    } 
  }; 
 
  /* 
   * Write a system property in case the system_server reboots before we 
   * get to the actual hardware restart. If that happens, we'll retry at 
   * the beginning of the SystemServer startup. 
   */  
  {   
    String reason = (mReboot ? "1" : "0") + (mRebootReason != null ? mRebootReason : ""); 
    (SHUTDOWN_ACTION_PROPERTY, reason); 
  } 
 
  /* 
   * If we are rebooting into safe mode, write a system property 
   * indicating so. 
   */  
  if (mRebootSafeMode) { 
    (REBOOT_SAFEMODE_PROPERTY, "1"); 
  } 
  ... 
  rebootOrShutdown(mReboot, mRebootReason); 
}  

Before restarting, the restart reason will be written. If not, it will be empty. If it is safe mode, it will be set. After that, some pre-shut processing will be performed, the ActivityManager and MountService will be closed, and rebootOrShutdown will be called for shutdown.

 

  /** 
   * Do not call this directly. Use {@link #reboot(Context, String, boolean)} 
   * or {@link #shutdown(Context, boolean)} instead. 
   * 
   * @param reboot true to reboot or false to shutdown 
   * @param reason reason for reboot 
   */ 
  public static void rebootOrShutdown(boolean reboot, String reason) { 
    if (reboot) { 
      (TAG, "Rebooting, reason: " + reason);  
      try { 
        (reason); 
      } catch (Exception e) { 
        (TAG, "Reboot failed, will attempt shutdown instead", e); 
      }  
    } else if (SHUTDOWN_VIBRATE_MS > 0) { 
      // vibrate before shutting down 
      Vibrator vibrator = new SystemVibrator(); 
      try { 
        (SHUTDOWN_VIBRATE_MS); 
      } catch (Exception e) { 
        // Failure to vibrate shouldn't interrupt shutdown. Just log it. 
        (TAG, "Failed to vibrate during shutdown.", e); 
      }   
         
      // vibrator is asynchronous so we need to wait to avoid shutting down too soon. 
      try { 
        (SHUTDOWN_VIBRATE_MS); 
      } catch (InterruptedException unused) { 
      }   
    }   
       
    // Shutdown power 
    (TAG, "Performing low-level shutdown..."); 
    (); 
  } 
} 

If you confirm the restart, call the lowLevelReboot function of PowerManagerService. The parameters are the passed reason and analyze it later. If it is not restarting, that is, mReboot=false, it means that it needs to be shut down, and you can know it in the shutdown function.

/** 
 * Request a clean shutdown, waiting for subsystems to clean up their 
 * state etc. Must be called from a Looper thread in which its UI 
 * is shown. 
 * 
 * @param context Context used to display the shutdown progress dialog. 
 * @param confirm true if user confirmation is needed before shutting down. 
 */ 
public static void shutdown(final Context context, boolean confirm) { 
  mReboot = false; 
  mRebootSafeMode = false; 
  shutdownInner(context, confirm); 
} 

When shutting down, it needs to vibrate, which is here SHUTDOWN_VIBRATE_MS, the default definition is 500ms. But in the code, no matter what, the lowLevelShutdown function will be called in the end, that is, shutdown. Logically, this may be a problem, but in reality, if the restart operation can be called successfully, the entire system will be restarted, and of course the subsequent code will not be executed.
Turn your eyes back to PowerManagerService
/base/services/java/com/android/server/

/**  
 * Low-level function to reboot the device. 
 * 
 * @param reason code to pass to the kernel (. "recovery"), or null. 
 * @throws IOException if reboot fails for some reason (eg, lack of 
 *     permission) 
 */ 
public static void lowLevelReboot(String reason) throws IOException { 
  nativeReboot(reason); 
}  
 
/**  
 * Low-level function turn the device off immediately, without trying 
 * to be clean. Most people should use 
 * {@link } for a clean shutdown. 
 */ 
public static void lowLevelShutdown() { 
  nativeShutdown(); 
} 

 

The familiar word native is called by JNI:

private static native void nativeShutdown(); 
private static native void nativeReboot(String reason) throws IOException; 

/base/services/jni/com_android_server_PowerManagerService.cpp

static JNINativeMethod gPowerManagerServiceMethods[] = {  
  /* name, signature, funcPtr */ 
  ... 
  { "nativeShutdown", "()V", 
      (void*) nativeShutdown }, 
  { "nativeReboot", "(Ljava/lang/String;)V", 
      (void*) nativeReboot }, 
  ... 
}; 

The two good brothers also realize each other:

static void nativeShutdown(JNIEnv *env, jobject clazz) { 
  android_reboot(ANDROID_RB_POWEROFF, 0, 0); 
} 
 
static void nativeReboot(JNIEnv *env, jobject clazz, jstring reason) { 
  if (reason == NULL) { 
    android_reboot(ANDROID_RB_RESTART, 0, 0); 
  } else { 
    const char *chars = env->GetStringUTFChars(reason, NULL); 
    android_reboot(ANDROID_RB_RESTART2, 0, (char *) chars); 
    env->ReleaseStringUTFChars(reason, chars); // In case it fails. 
  } 
  jniThrowIOException(env, errno); 
} 

It can be seen that whether it is shutdown or restart, it is implemented by calling android_reboot, but the parameters are different.

/core/libcutils/android_reboot.c

int android_reboot(int cmd, int flags, char *arg) 
{ 
  int ret = 0; 
  int reason = -1; 
 
#ifdef RECOVERY_PRE_COMMAND 
  if (cmd == (int) ANDROID_RB_RESTART2) { 
    if (arg && strlen(arg) > 0) { 
      char cmd[PATH_MAX]; 
      sprintf(cmd, RECOVERY_PRE_COMMAND " %s", arg); 
      system(cmd); 
    } 
  } 
#endif 
 
  if (!(flags & ANDROID_RB_FLAG_NO_SYNC)) 
    sync(); 
 
  if (!(flags & ANDROID_RB_FLAG_NO_REMOUNT_RO)) 
    remount_ro(); 
 
  switch (cmd) { 
    case ANDROID_RB_RESTART: 
      reason = RB_AUTOBOOT; 
      break; 
 
    case ANDROID_RB_POWEROFF: 
      ret = reboot(RB_POWER_OFF); 
      return ret; 
 
    case ANDROID_RB_RESTART2: 
      // REBOOT_MAGIC 
      break; 
 
    default: 
      return -1; 
  } 
 
#ifdef RECOVERY_PRE_COMMAND_CLEAR_REASON 
  reason = RB_AUTOBOOT; 
#endif 
 
  if (reason != -1) 
    ret = reboot(reason); 
  else 
    ret = __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, 
              LINUX_REBOOT_CMD_RESTART2, arg); 
 
  return ret; 
} 

Taking reboot recovery as an example, arg is recovery. ANDROID_RB_RESTART2 will be passed in the fifth step. When you arrive in the android_reboot function, you will see the definition #ifdef RECOVERY_PRE_COMMAND, which is a command that will be executed before restarting. If it is defined, it will be executed.
The following also does some preprocessing work before shutdown and restart. The function of sync() is to write the information in the cache to disk to avoid the abnormal end of the program and causing the file to be corrupted. The Linux system will do such actions several times before shutting down. The function of remount_ro() is to force the file system to be mounted as read-only by calling emergency_remount(), and no write operations are allowed. At the same time, it will check the device status of /proc/mounts to confirm whether all the current writes have been completed. This checking process is a blocking operation.
Next is the parsing process of parameters:
1) Normal restart ANDROID_RB_RESTART, reason = RB_AUTOBOOT;
2) Shutdown ANDROID_RB_POWEROFF, no reason is required, directly call reboot to shut down;
3) Special restart with parameters ANDROID_RB_RESTART2, reason will be the default value -1
Here again, #ifdef RECOVERY_PRE_COMMAND_CLEAR_REASON appears. If you define it, no matter what the parameters passed down from the upper layer are, it will be just a normal restart in the end. The way to define it is to add TARGET_RECOVERY_PRE_COMMAND_CLEAR_REASON := true. Some manufacturers should like to do this. After all, except for ordinary restarts, they may bring certain risks to users.
Finally, a detection of the reason will be performed. Then, through the above analysis, only the special restart with parameters will be -1. In cases where it is not equal to -1, there will be normal restarts and shutdowns, and shutdowns have been solved by itself... Therefore, in cases where it does not equal to -1, there will be only normal restarts. In the end, this is where the normal restart and special restart are distinguished. Here is another question. What are the values ​​of the other cmds? The answer is in bionic/libc/include/sys/:

#define RB_AUTOBOOT   LINUX_REBOOT_CMD_RESTART 
#define RB_HALT_SYSTEM LINUX_REBOOT_CMD_HALT 
#define RB_ENABLE_CAD  LINUX_REBOOT_CMD_CAD_ON 
#define RB_DISABLE_CAD LINUX_REBOOT_CMD_CAD_OFF 
#define RB_POWER_OFF  LINUX_REBOOT_CMD_POWER_OFF 

And, LINUX_REBOOT_XXXX and others are in bionic/libc/kernel/common/linux/:

#define LINUX_REBOOT_MAGIC1 0xfee1dead 
#define LINUX_REBOOT_MAGIC2 672274793 
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ 
#define LINUX_REBOOT_MAGIC2A 85072278 
#define LINUX_REBOOT_MAGIC2B 369367448 
#define LINUX_REBOOT_MAGIC2C 537993216 
#define LINUX_REBOOT_CMD_RESTART 0x01234567 
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ 
#define LINUX_REBOOT_CMD_HALT 0xCDEF0123 
#define LINUX_REBOOT_CMD_CAD_ON 0x89ABCDEF 
#define LINUX_REBOOT_CMD_CAD_OFF 0x00000000 
#define LINUX_REBOOT_CMD_POWER_OFF 0x4321FEDC 
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ 
#define LINUX_REBOOT_CMD_RESTART2 0xA1B2C3D4 
#define LINUX_REBOOT_CMD_SW_SUSPEND 0xD000FCE2 
#define LINUX_REBOOT_CMD_KEXEC 0x45584543 

As for the question of why they have such a strange value, I can only say that they are magic number. Magic is something that normal people cannot understand, so~~~ Let them go, as long as they know that they are not -1, it will be OK.
Let’s first look at the reboot function. According to usual experience, reboot will definitely call __reboot in the end.

/libc/unistd/

int reboot (int mode)  
{ 
  return __reboot( LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, mode, NULL ); 
} 

Bingo! As expected, it would be nice to write this way to reboot(reason) -> reboot(RB_AUTOBOOT) -> __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART, NULL ), it would be great if I could write it directly~~~~~ I wouldn't go around this layer.

2. KERNEL domain
8.__reboot comes to the kernel through syscall
Here I will briefly introduce syscall in some space, so I can better track it if I encounter similar things in the future.
The implementation of __reboot in the arm architecture in step 7 is like this (bionic/libc/arch-arm/syscalls/__reboot.S)

ENTRY(__reboot) 
  .save  {r4, r7}  
  stmfd  sp!, {r4, r7} 
  ldr   r7, =__NR_reboot 
  swi   #0  
  ldmfd  sp!, {r4, r7} 
  movs  r0, r0 
  bxpl  lr  
  b    __set_syscall_errno 
END(__reboot) 

It can be seen that the implementation of __reboot is mapped to __NR_reboot, and in bionic/libc/sys/ can be found:

#define __NR_reboot            (__NR_SYSCALL_BASE + 88) 

It is specified with a fixed offset, and when it is called, it is through this offset to find the corresponding entrance in the kernel. It can be seen that there must be the same definition in the kernel, otherwise it will not be successfully called. The definition of syscall offset in the kernel is arch/arm/include/asm/ in the kernel source code, and the relevant information is completely consistent.
The corresponding map in the kernel has been found, so the next step is to find the real implementation function. In include/asm-generic/, you can find the kernel syscall function map to __NR_reboot, that is,

/* kernel/ */ 
#define __NR_setpriority 140 
__SYSCALL(__NR_setpriority, sys_setpriority) 
#define __NR_getpriority 141 
__SYSCALL(__NR_getpriority, sys_getpriority) 
#define __NR_reboot 142 
__SYSCALL(__NR_reboot, sys_reboot) 

At the same time, to discover such a warm scene, the kernel has guided us where to look for sys_reboot, that is, kernel/.

/
Before entering this file, let's first check the definition of sys_reboot in include/linux/:

asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd, 
        void __user *arg); 

Consistent with the call parameter of __reboot.
After entering the file, no function named sys_reboot was found. After careful searching, I found a very interesting function, which is defined as SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd, void __user *, arg), and can be matched by the parameters of __reboot. Is this function?
Also in the include/linux/ file, you can find several definitions like this:

#define SYSCALL_DEFINE1(name, ...) SYSCALL_DEFINEx(1, _##name, __VA_ARGS__) 
#define SYSCALL_DEFINE2(name, ...) SYSCALL_DEFINEx(2, _##name, __VA_ARGS__) 
#define SYSCALL_DEFINE3(name, ...) SYSCALL_DEFINEx(3, _##name, __VA_ARGS__) 
#define SYSCALL_DEFINE4(name, ...) SYSCALL_DEFINEx(4, _##name, __VA_ARGS__) 
#define SYSCALL_DEFINE5(name, ...) SYSCALL_DEFINEx(5, _##name, __VA_ARGS__) 
#define SYSCALL_DEFINE6(name, ...) SYSCALL_DEFINEx(6, _##name, __VA_ARGS__) 
... 
 
#define SYSCALL_DEFINEx(x, sname, ...)       \ 
  __SYSCALL_DEFINEx(x, sname, __VA_ARGS__) 
... 
 
#define __SYSCALL_DEFINEx(x, name, ...)         \ 
  asmlinkage long sys##name(__SC_DECL##x(__VA_ARGS__)) 

After integration, it is equivalent to:

#define SYSCALL_DEFINE4(name, ...) \ 
  asmlinkage long sys##_name(__SC_DECL##4(__VA_ARGS__)) 

It is not difficult to see that SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd, void __user *, arg) is the final implementation of sys_reboot called by the upper layer. The function implementation is as follows:

/* 
 * Reboot system call: for obvious reasons only root may call it, 
 * and even root needs to set up some magic numbers in the registers 
 * so that some mistake won't make this reboot the whole machine. 
 * You can also set the meaning of the ctrl-alt-del-key here. 
 * 
 * reboot doesn't sync: do that yourself before calling this. 
 */ 
SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd, 
    void __user *, arg) 
{ 
  char buffer[256]; 
  int ret = 0; 
 
  /* We only trust the superuser with rebooting the system. */ 
  if (!capable(CAP_SYS_BOOT)) 
    return -EPERM; 
 
  /* For safety, we require "magic" arguments. */ 
  if (magic1 != LINUX_REBOOT_MAGIC1 || 
    (magic2 != LINUX_REBOOT_MAGIC2 && 
          magic2 != LINUX_REBOOT_MAGIC2A && 
      magic2 != LINUX_REBOOT_MAGIC2B && 
          magic2 != LINUX_REBOOT_MAGIC2C)) 
    return -EINVAL; 
 
  /* Instead of trying to make the power_off code look like 
   * halt when pm_power_off is not set do it the easy way. 
   */ 
  if ((cmd == LINUX_REBOOT_CMD_POWER_OFF) && !pm_power_off) 
    cmd = LINUX_REBOOT_CMD_HALT; 
 
  mutex_lock(&reboot_mutex); 
  switch (cmd) { 
  case LINUX_REBOOT_CMD_RESTART: 
    kernel_restart(NULL); 
    break; 
 
  case LINUX_REBOOT_CMD_CAD_ON: 
    C_A_D = 1; 
    break; 
 
  case LINUX_REBOOT_CMD_CAD_OFF: 
    C_A_D = 0; 
    break; 
 
  case LINUX_REBOOT_CMD_HALT: 
    kernel_halt(); 
    do_exit(0); 
    panic("cannot halt"); 
 
  case LINUX_REBOOT_CMD_POWER_OFF: 
    kernel_power_off(); 
    do_exit(0); 
    break; 
 
  case LINUX_REBOOT_CMD_RESTART2: 
    if (strncpy_from_user(&buffer[0], arg, sizeof(buffer) - 1) < 0) { 
      ret = -EFAULT; 
      break; 
    } 
    buffer[sizeof(buffer) - 1] = '\0'; 
 
    kernel_restart(buffer); 
    break; 
 
#ifdef CONFIG_KEXEC 
  case LINUX_REBOOT_CMD_KEXEC: 
    ret = kernel_kexec(); 
    break; 
#endif 
 
#ifdef CONFIG_HIBERNATION 
  case LINUX_REBOOT_CMD_SW_SUSPEND: 
    ret = hibernate(); 
    break; 
#endif 
 
  default: 
    ret = -EINVAL; 
    break; 
  } 
  mutex_unlock(&reboot_mutex); 
  return ret; 
} 

In this function, the permission problem will be detected first, and only the super user can perform the operation of restarting the system:

/* We only trust the superuser with rebooting the system. */ 
if (!capable(CAP_SYS_BOOT)) 
  return -EPERM; 

Otherwise, a permission error will be returned. The corresponding permission list is in include/linux/, and the restart operation is 22.
The magic number is then checked:

/* For safety, we require "magic" arguments. */ 
if (magic1 != LINUX_REBOOT_MAGIC1 || 
  (magic2 != LINUX_REBOOT_MAGIC2 && 
        magic2 != LINUX_REBOOT_MAGIC2A && 
    magic2 != LINUX_REBOOT_MAGIC2B && 
        magic2 != LINUX_REBOOT_MAGIC2C)) 
  return -EINVAL; 

If no error occurs during data transmission, of course there will be no problem here, so it is just a security verification and basically no error occurs.
There is an interesting check after that. If the user requests shutdown and pm_power_off is empty, the user's shutdown command will be converted to suspend:

/* Instead of trying to make the power_off code look like 
 * halt when pm_power_off is not set do it the easy way. 
 */ 
if ((cmd == LINUX_REBOOT_CMD_POWER_OFF) && !pm_power_off) 
  cmd = LINUX_REBOOT_CMD_HALT; 

Its definition can be found in arch/arm/kernel/:

/* 
 * Function pointers to optional machine specific functions 
 */ 
void (*pm_power_off)(void); 
EXPORT_SYMBOL(pm_power_off); 

OK, it's just a function pointer, and if you do global operations, the entire kernel can call it. Taking Qualcomm msm7x30 as an example, this function pointer is assigned in arch/arm/mach-msm/:

pm_power_off = msm_pm_power_off; 

The specific implementation of msm_pm_power_off will no longer be followed. Each company is different, and it doesn't make much sense to continue. Now as long as you know, the kernel I analyzed is assigned a value to this function pointer, so it is not empty, and the shutdown command will be executed normally.
Next is the topic of this function, which parses user commands. At the same time, this process is protected by reboot_mutex mutex to ensure that there is only one parsing process at the same time to avoid conflicts.
The following posts the command definitions related to restarting of all related machines:

/* 
 * Commands accepted by the _reboot() system call. 
 *    
 * RESTART   Restart system using default command and mode. 
 * HALT    Stop OS and give system control to ROM monitor, if any. 
 * CAD_ON   Ctrl-Alt-Del sequence causes RESTART command. 
 * CAD_OFF   Ctrl-Alt-Del sequence sends SIGINT to init task. 
 * POWER_OFF  Stop OS and remove all power from system, if possible. 
 * RESTART2  Restart system using given command string. 
 * SW_SUSPEND Suspend system using software suspend if compiled in. 
 * KEXEC    Restart system using a previously loaded Linux kernel 
 */    
     
#define LINUX_REBOOT_CMD_RESTART  0x01234567 
#define LINUX_REBOOT_CMD_HALT    0xCDEF0123 
#define LINUX_REBOOT_CMD_CAD_ON   0x89ABCDEF 
#define LINUX_REBOOT_CMD_CAD_OFF  0x00000000  
#define LINUX_REBOOT_CMD_POWER_OFF 0x4321FEDC 
#define LINUX_REBOOT_CMD_RESTART2  0xA1B2C3D4 
#define LINUX_REBOOT_CMD_SW_SUSPEND 0xD000FCE2 
#define LINUX_REBOOT_CMD_KEXEC   0x45584543 

The explanation in the comments is very detailed. What is unfamiliar is about CAD, which is actually used to operate with Ctrl+Alt+Del; then SW_SYSPEND is software dormant; KEXEC is too high-end, and is a patch of the kernel, used to restart using the old kernel. Detailed information: /developerworks/cn/linux/l-kexec/?ca=dwcn-newsletter-linux
Only the first six commands are used by the Android system. Why do you say that? You can check bionic/libc/include/sys/, which has been posted above. Although LINUX_REBOOT_CMD_HALT is defined, I have not found any calls in the Android system. If any expert finds it, I hope I can tell you. In the end, there are only three that can be used:

  • RESTART
  • POWER_OFF
  • RESTART2

10. Final implementation
Restart calls kernel_restart. The difference is whether the parameter is empty. When shutting down, kernel_power_off() is called. Let's look at shutdown first:

/** 
 * kernel_power_off - power_off the system 
 * 
 * Shutdown everything and perform a clean system power_off. 
 */ 
void kernel_power_off(void) 
{ 
  kernel_shutdown_prepare(SYSTEM_POWER_OFF); 
  if (pm_power_off_prepare) 
    pm_power_off_prepare(); 
  disable_nonboot_cpus(); 
  syscore_shutdown(); 
  printk(KERN_EMERG "Power down.\n"); 
  kmsg_dump(KMSG_DUMP_POWEROFF); 
  machine_power_off(); 
} 
EXPORT_SYMBOL_GPL(kernel_power_off); 

The most important series of preparations was finally called machine_power_off():

void machine_power_off(void) 
{   
  machine_shutdown(); 
  if (pm_power_off) 
    pm_power_off(); 
} 

The pm_power_off we looked for before is useful here, and it is the last step to shut down. The shutdown is completed, and then check the restart operation:

/** 
 * kernel_restart - reboot the system 
 * @cmd: pointer to buffer containing command to execute for restart 
 *   or %NULL 
 * 
 * Shutdown everything and perform a clean reboot. 
 * This is not safe to call in interrupt context. 
 */ 
void kernel_restart(char *cmd) 
{ 
  kernel_restart_prepare(cmd); 
  if (!cmd) 
    printk(KERN_EMERG "Restarting system.\n"); 
  else 
    printk(KERN_EMERG "Restarting system with command '%s'.\n", cmd); 
  kmsg_dump(KMSG_DUMP_RESTART); 
  machine_restart(cmd); 
} 
EXPORT_SYMBOL_GPL(kernel_restart); 

The same routine will also carry out some preparation work, and then call machine_restart(cmd). If it is a normal restart, then the cmd will be NULL. If it is a special restart, then this cmd will be passed down layer by layer to layer.

void machine_restart(char *cmd) 
{ 
  machine_shutdown(); 
  arm_pm_restart(reboot_mode, cmd); 
} 
... 
void (*arm_pm_restart)(char str, const char *cmd) = arm_machine_restart; 
EXPORT_SYMBOL_GPL(arm_pm_restart); 

And still remember what just now? There is also pointer assignment to arm_pm_restart:

arm_pm_restart = msm_pm_restart; 

The function assigned is msm_pm_init, and its call is

late_initcall_sync(msm_pm_init); 

The startup priority of late_initcall_sync is the lowest, at 7. module_init is actually the priority of 6, and the larger the number, the lower the priority. So, if you infer this way, the ultimate pointer of arm_pm_restart will point to msm_pm_restart. I won’t look at the specific implementation of msm_pm_restart. It’s the same as mentioned earlier. It’s different from each company, just a few lines of code:

static void msm_pm_restart(char str, const char *cmd) 
{     
  msm_rpcrouter_close(); 
  msm_proc_comm(PCOM_RESET_CHIP, &restart_reason, 0); 
 
  for (;;) 
    ; 
}  

But careful friends may find that there is a restart_reason here, which is not a parameter passed down. In fact, this value has been set before kernel_restart_prepare(cmd).

void kernel_restart_prepare(char *cmd) 
{   
  blocking_notifier_call_chain(&reboot_notifier_list, SYS_RESTART, cmd); 
  system_state = SYSTEM_RESTART; 
  usermodehelper_disable(); 
  device_shutdown(); 
  syscore_shutdown(); 
} 

It is the blocking_notifier mechanism. This operation was also found in the previous shutdown operation, and it is the same list, both of which are reboot_notifier_list. It is also easy to understand, it is to pass the function registered on reboot_notifier_list into relevant parameters and execute it. For understanding, let’s see how it is used: (arch/arm/mach-msm/)

static int msm_reboot_call 
  (struct notifier_block *this, unsigned long code, void *_cmd) 
{   
  if ((code == SYS_RESTART) && _cmd) { 
    char *cmd = _cmd; 
    if (!strcmp(cmd, "bootloader")) { 
      restart_reason = 0x77665500; 
    } else if (!strcmp(cmd, "recovery")) { 
      restart_reason = 0x77665502; 
    } else if (!strcmp(cmd, "eraseflash")) { 
      restart_reason = 0x776655EF; 
    } else if (!strncmp(cmd, "oem-", 4)) { 
      unsigned code = simple_strtoul(cmd + 4, 0, 16) & 0xff; 
      restart_reason = 0x6f656d00 | code; 
    } else { 
      restart_reason = 0x77665501;  
    }   
  }     
  return NOTIFY_DONE; 
}       
     
static struct notifier_block msm_reboot_notifier = { 
  .notifier_call = msm_reboot_call, 
}; 
 
... 
 
static int __init msm_pm_init(void) 
{ 
... 
  register_reboot_notifier(&msm_reboot_notifier); 
... 
} 

OK, everything is fine. When kernel_restart_prepare msm_reboot_call will be called first. The function is to assign a value to restart_reason according to user commands, so that it will be used when msm_pm_restart is called later. Here we found that when reboot, the parameters that can be included are not only recovery, bootloader, but also erasflash and oem-???. Literally, it should be used to erase ROM and unlock operations.

3. How to use shutdown?
The analysis in this article starts with the reboot interface given by Android, but after analyzing it, you will find that the interface given by Android can only be restarted and cannot be shut down. You can find that during the process of tracking this process, you will find that there are indeed relevant interfaces for shutdown. So how should I use it when shutting down?
frameworks/base/services/java/com/android/

private final void shutdownIfNoPower() { 
// shut down gracefully if our battery is critically low and we are not powered. 
// wait until the system has booted before attempting to display the shutdown dialog. 
if (mBatteryLevel == 0 && !isPowered() && ()) { 
  Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN); 
  (Intent.EXTRA_KEY_CONFIRM, false); 
  (Intent.FLAG_ACTIVITY_NEW_TASK); 
  (intent); 
}