Android系统关机的全流程解析

2019-12-10 19:02:04刘景俊

整合后等价于:

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

这样就不难看出,SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd, void __user *, arg)就是sys_reboot,也就是上层调用的__reboot的最终实现。函数实现如下:

/* 
 * 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] = ''; 
 
    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; 
}