Android关机方法
Android系统关机接口总结如下,看下实现流程
一.framework接口关机二.adb reboot -p三.echo "o" > /proc/sysrq-trigger
一.framework接口关机
如低电量会自动关机,走如下流程
frameworks/base/services/java/com/android/server/power/PowerManagerService.java(http://aospxref.com/android-4.4.4_r2.0.1/xref/frameworks/base/services/java/com/android/server/power/PowerManagerService.java)
/** * Low-level function turn the device off immediately, without trying * to be clean. Most people should use {@link ShutdownThread} for a clean shutdown. */ public static void lowLevelShutdown() { SystemProperties.set("sys.powerctl", "shutdown"); } /** * Low-level function to reboot the device. On success, this function * doesn't return. If more than 5 seconds passes from the time, * a reboot is requested, this method returns. * * @param reason code to pass to the kernel (e.g. "recovery"), or null. */ public static void lowLevelReboot(String reason) { if (reason == null) { reason = ""; } SystemProperties.set("sys.powerctl", "reboot," + reason); try { Thread.sleep(20000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } }
system/core/rootdir/init.rc(http://aospxref.com/android-4.4.4_r2.0.1/xref/system/core/rootdir/init.rc#404)
on property:sys.powerctl=* powerctl ${sys.powerctl}
system/core/init/keywords.h(http://aospxref.com/android-4.4.4_r2.0.1/xref/system/core/init/keywords.h)
KEYWORD(powerctl, COMMAND, 1, do_powerctl)
system/core/init/builtins.c(http://aospxref.com/android-4.4.4_r2.0.1/xref/system/core/init/builtins.c)
int do_powerctl(int nargs, char **args){ char command[PROP_VALUE_MAX]; int res; int len = 0; int cmd = 0; char *reboot_target; res = expand_props(command, args[1], sizeof(command)); if (res) { ERROR("powerctl: cannot expand '%s'\n", args[1]); return -EINVAL; } if (strncmp(command, "shutdown", 8) == 0) { cmd = ANDROID_RB_POWEROFF; len = 8; } else if (strncmp(command, "reboot", 6) == 0) { cmd = ANDROID_RB_RESTART2; len = 6; } else { ERROR("powerctl: unrecognized command '%s'\n", command); return -EINVAL; } if (command[len] == ',') { reboot_target = &command[len + 1]; } else if (command[len] == '\0') { reboot_target = ""; } else { ERROR("powerctl: unrecognized reboot target '%s'\n", &command[len]); return -EINVAL; } return android_reboot(cmd, 0, reboot_target);}
system/core/libcutils/android_reboot.c(http://aospxref.com/android-4.4.4_r2.0.1/xref/system/core/libcutils/android_reboot.c#104)
int android_reboot(int cmd, int flags, char *arg){ int ret; sync(); remount_ro(); switch (cmd) { case ANDROID_RB_RESTART: ret = reboot(RB_AUTOBOOT); break; case ANDROID_RB_POWEROFF: ret = reboot(RB_POWER_OFF); break; case ANDROID_RB_RESTART2: ret = __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, arg); break; default: ret = -1; } return ret;}
bionic/libc/bionic/reboot.c(http://aospxref.com/android-4.4.4_r2.0.1/xref/bionic/libc/bionic/reboot.c)
int reboot (int mode) { return __reboot( LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, mode, NULL );}
bionic/libc/arch-arm/syscalls/__reboot.S(http://aospxref.com/android-4.4.4_r2.0.1/xref/bionic/libc/arch-arm/syscalls/__reboot.S)
ENTRY(__reboot) mov ip, r7 ldr r7, =__NR_reboot swi #0 mov r7, ip cmn r0, #(MAX_ERRNO + 1) bxls lr neg r0, r0 b __set_errnoEND(__reboot)
bionic/libc/kernel/arch-arm/asm/unistd.h(http://aospxref.com/android-4.4.4_r2.0.1/xref/bionic/libc/kernel/arch-arm/asm/unistd.h)
#define __NR_reboot (__NR_SYSCALL_BASE+ 88)
接下看下内核的系统调用
arch/arm/kernel/calls.S(https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/arm/kernel/calls.S?h=v4.4-rc1)
/* 85 */CALL(sys_readlink)CALL(sys_uselib)CALL(sys_swapon)CALL(sys_reboot)CALL(OBSOLETE(sys_old_readdir))/* used by libc4 *//* 90 */CALL(OBSOLETE(sys_old_mmap))/* used by libc4 */
kernel/reboot.c(https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/kernel/reboot.c?h=v4.4-rc1)
/* * 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){struct pid_namespace *pid_ns = task_active_pid_ns(current);char buffer[256];int ret = 0;/* We only trust the superuser with rebooting the system. */if (!ns_capable(pid_ns->user_ns, 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;/* * If pid namespaces are enabled and the current task is in a child * pid_namespace, the command is handled by reboot_pid_ns() which will * call do_exit(). */ret = reboot_pid_ns(pid_ns, cmd);if (ret)return ret;/* 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(&system_transition_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:ret = strncpy_from_user(&buffer[0], arg, sizeof(buffer) - 1);if (ret < 0) {ret = -EFAULT;break;}buffer[sizeof(buffer) - 1] = '\0';kernel_restart(buffer);break;#ifdef CONFIG_KEXEC_COREcase LINUX_REBOOT_CMD_KEXEC:ret = kernel_kexec();break;#endif#ifdef CONFIG_HIBERNATIONcase LINUX_REBOOT_CMD_SW_SUSPEND:ret = hibernate();break;#endifdefault:ret = -EINVAL;break;}mutex_unlock(&system_transition_mutex);return ret;}
也就是调用内核的kernel_power_off函数进行关机。
二.adb reboot -p
system/core/adb/commandline.c(http://aospxref.com/android-4.4.4_r2.0.1/xref/system/core/adb/commandline.c#924)
这里对命令进行了封装(加了分号)
int adb_commandline(int argc, char **argv){ ... if(!strcmp(argv[0], "remount") || !strcmp(argv[0], "reboot") || !strcmp(argv[0], "reboot-bootloader") || !strcmp(argv[0], "tcpip") || !strcmp(argv[0], "usb") || !strcmp(argv[0], "root")) { char command[100]; if (!strcmp(argv[0], "reboot-bootloader")) snprintf(command, sizeof(command), "reboot:bootloader"); else if (argc > 1) snprintf(command, sizeof(command), "%s:%s", argv[0], argv[1]); else snprintf(command, sizeof(command), "%s:", argv[0]); int fd = adb_connect(command); if(fd >= 0) { read_and_dump(fd); adb_close(fd); return 0; } fprintf(stderr,"error: %s\n", adb_error()); return 1; } ...}
system/core/adb/services.c(http://aospxref.com/android-4.4.4_r2.0.1/xref/system/core/adb/services.c)
int service_to_fd(const char *name){ int ret = -1; if(!strncmp(name, "tcp:", 4)) { } else if(!strncmp(name, "remount:", 8)) { ret = create_service_thread(remount_service, NULL); } else if(!strncmp(name, "reboot:", 7)) { void* arg = strdup(name + 7); if(arg == 0) return -1; ret = create_service_thread(reboot_service, arg); } }void reboot_service(int fd, void *arg){ char buf[100]; char property_val[PROPERTY_VALUE_MAX]; int ret; sync(); ret = snprintf(property_val, sizeof(property_val), "reboot,%s", (char *) arg); if (ret >= (int) sizeof(property_val)) { snprintf(buf, sizeof(buf), "reboot string too long. length=%d\n", ret); writex(fd, buf, strlen(buf)); goto cleanup; } ret = property_set(ANDROID_RB_PROPERTY, property_val); if (ret < 0) { snprintf(buf, sizeof(buf), "reboot failed: %d\n", ret); writex(fd, buf, strlen(buf)); goto cleanup; } // Don't return early. Give the reboot command time to take effect // to avoid messing up scripts which do "adb reboot && adb wait-for-device" while(1) { pause(); }cleanup: free(arg); adb_close(fd);}
而ANDROID_RB_PROPERTY定义为sys.powerctl,后面的流程跟方法一一致
system/core/include/cutils/android_reboot.h(http://aospxref.com/android-4.4.4_r2.0.1/xref/system/core/include/cutils/android_reboot.h)
#define ANDROID_RB_PROPERTY "sys.powerctl"
三.echo "o" > /proc/sysrq-trigger
drivers/tty/sysrq.c(https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/drivers/tty/sysrq.c?h=v4.4.219)
static struct sysrq_key_op *sysrq_key_table[36] = {&sysrq_loglevel_op,/* 0 */&sysrq_loglevel_op,/* 1 */&sysrq_loglevel_op,/* 2 */&sysrq_loglevel_op,/* 3 */&sysrq_loglevel_op,/* 4 */&sysrq_loglevel_op,/* 5 */&sysrq_loglevel_op,/* 6 */&sysrq_loglevel_op,/* 7 */&sysrq_loglevel_op,/* 8 */&sysrq_loglevel_op,/* 9 *//* * a: Don't use for system provided sysrqs, it is handled specially on * sparc and will never arrive. */NULL,/* a */&sysrq_reboot_op,/* b */&sysrq_crash_op,/* c & ibm_emac driver debug */&sysrq_showlocks_op,/* d */&sysrq_term_op,/* e */&sysrq_moom_op,/* f *//* g: May be registered for the kernel debugger */NULL,/* g */NULL,/* h - reserved for help */&sysrq_kill_op,/* i */#ifdef CONFIG_BLOCK&sysrq_thaw_op,/* j */#elseNULL,/* j */#endif&sysrq_SAK_op,/* k */#ifdef CONFIG_SMP&sysrq_showallcpus_op,/* l */#elseNULL,/* l */#endif&sysrq_showmem_op,/* m */&sysrq_unrt_op,/* n *//* o: This will often be registered as 'Off' at init time */NULL,/* o */&sysrq_showregs_op,/* p */&sysrq_show_timers_op,/* q */&sysrq_unraw_op,/* r */&sysrq_sync_op,/* s */&sysrq_showstate_op,/* t */&sysrq_mountro_op,/* u *//* v: May be registered for frame buffer console restore */NULL,/* v */&sysrq_showstate_blocked_op,/* w *//* x: May be registered on mips for TLB dump *//* x: May be registered on ppc/powerpc for xmon *//* x: May be registered on sparc64 for global PMU dump */NULL,/* x *//* y: May be registered on sparc64 for global register dump */NULL,/* y */&sysrq_ftrace_dump_op,/* z */};void __handle_sysrq(int key, bool check_mask){ op_p = __sysrq_get_key_op(key); if (op_p) {op_p->handler(key);} }static ssize_t write_sysrq_trigger(struct file *file, const char __user *buf, size_t count, loff_t *ppos){if (count) {char c;if (get_user(c, buf))return -EFAULT;__handle_sysrq(c, false);}return count;}static const struct file_operations proc_sysrq_trigger_operations = {.write= write_sysrq_trigger,.llseek= noop_llseek,};static void sysrq_init_procfs(void){if (!proc_create("sysrq-trigger", S_IWUSR, NULL, &proc_sysrq_trigger_operations))pr_err("Failed to register proc interface\n");}
"o"参数目前为NULL,那在哪里赋值呢
kernel/power/poweroff.c(https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/kernel/power/poweroff.c)
static void do_poweroff(struct work_struct *dummy){kernel_power_off();}static DECLARE_WORK(poweroff_work, do_poweroff);static void handle_poweroff(int key){/* run sysrq poweroff on boot cpu */schedule_work_on(cpumask_first(cpu_online_mask), &poweroff_work);}static struct sysrq_key_opsysrq_poweroff_op = {.handler = handle_poweroff,.help_msg = "poweroff(o)",.action_msg = "Power Off",.enable_mask= SYSRQ_ENABLE_BOOT,};static int __init pm_sysrq_init(void){register_sysrq_key('o', &sysrq_poweroff_op);return 0;}subsys_initcall(pm_sysrq_init);
也就是上面三种方法都是通过调用内核的kernel_power_off函数进行关机的。当然,小编最喜欢的是拔电池进行关机,简单快捷高效。
更多相关文章
- android重启流程
- Android4.4 Activity启动流程
- android开机动画启动流程
- Android Phone拨出电话流程
- android button light 流程分析(三) — framework
- android NDK/JNI-实例开发流程
- 64位Ubuntu Kylin14编译android内核
- Android 深入理解 View 的绘制流程和机制