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函数进行关机的。当然,小编最喜欢的是拔电池进行关机,简单快捷高效。

更多相关文章

  1. android重启流程
  2. Android4.4 Activity启动流程
  3. android开机动画启动流程
  4. Android Phone拨出电话流程
  5. android button light 流程分析(三) — framework
  6. android NDK/JNI-实例开发流程
  7. 64位Ubuntu Kylin14编译android内核
  8. Android 深入理解 View 的绘制流程和机制

随机推荐

  1. Android中手机震动的设置(Vibrator)的步骤(A
  2. Android(安卓)4.0 开发者指南(28) —— R
  3. Android寮€鍙戦」鐩疄璁璂ay_2
  4. CactiPhone: 移动设备上查看Cacti
  5. 【起航计划 016】2015 起航计划 Android(
  6. 如何使Android应用程序获取系统权限【转
  7. android之有返回结果跳转intent
  8. 通过终端命令生成并在手机上运行dex文件
  9. Robotium---环境搭建及入门示例
  10. Android学习笔记:Android基础知识总结