Android shutdown/reboot流程
基于Android-9 + msm-4.4
一、简介
当执行 adb reboot XXX 或 adb reboot -p 时会分别走 reboot 流程和 shutdown 流程。
二、用户代码流程
1. 相关文件
/system/core/init/init.cpp //用户空间reboot实现逻辑文件 /system/core/init/reboot.cpp /system/core/init/property_service.cpp /system/core/reboot/reboot.c //提供reboot命令行工具 /bionic/libc/bionic/reboot.cpp //提供reboot()库函数
init.cpp 的一个编译产物是 /init
2. reboot执行流程
reboot //命令, 在 reboot.c 中实现,只是写了一个属性 snprintf(property_val, sizeof(property_val), "%s,%s", cmd, optarg); //cmd为"reboot"或"shutdown",optarg默认为shell property_set(ANDROID_RB_PROPERTY , property_val); //reboot.c 只是设置临时属性 "sys.powerctl" ####### PropertySet(name, value, error) //property_service.cpp property_changed(name, value) //init.cpp if (name == "sys.powerctl") { shutdown_command = value; do_shutdown = true; }
若是直接执行 reboot 命令的话,传给 sys.powerctl 属性的就是 "reboot,shell"; 若是直接执行 reboot -p 命令的话,传给 sys.powerctl 属性的就是 "shutdown,shell"; 若是直接执行 reboot -p HelloWorld 命令的话,传给 sys.powerctl 属性的就是 'shutdown,HelloWorld';
执行完这个后会唤醒init的主线程,然后会执行 HandlePowerctlMessage(),先看下其调用位置,调用位置在init主线程的死循环中:
kernel_init //init/main.c 内核init线程 run_init_process(execute_command); //proc/cmdline中"init=/init", 只包含一个init.cpp文件 main //init.cpp init进程的主函数,参数通过"Booting kernel"传入,应该没参数 while (true) { if (do_shutdown && !shutting_down) { do_shutdown = false; if (HandlePowerctlMessage(shutdown_command)) { shutting_down = true; } } ... epoll_wait(epoll_fd, &ev, 1, epoll_timeout_ms); }
shutting_down 是定义在 init.cpp 中的 static 变量,没有赋值为flase的地方,即init的主线程的shutdown流程只能执行一次。
HandlePowerctlMessage 的执行流程:
HandlePowerctlMessage(shutdown_command) //参数就是向临时属性"sys.powerctl"中设的值 DoReboot(cmd, command, reboot_target, run_fsck) //reboot_target是argv[2]如"bootloader" LOG(INFO) << "Reboot start, reason: " << reason << ", rebootTarget: " << rebootTarget; //有个打印 property_set(LAST_REBOOT_REASON_PROPERTY, reason.c_str() + skip); //设置属性 persist.sys.boot.reason sync(); //将缓存刷回文件系统 if (shutdown_timeout > 0ms) //默认不执行 for (s : ServiceList::GetInstance()) //【1】先终止所有服务(毧失败下面还有杀掉) s->Terminate(); for (s : ServiceList::GetInstance()) //【2】杀掉shutdown流程不需要的所有服务 s->Stop(); ShutdownVold(); //【3】send volume shutdown to vold voldService->Stop(); sync(); TryUmountAndFsck //【4】sync,尝试umount,并为shutdown运行fsck stat = UmountPartitions(timeout - t.duration()); if (stat != UMOUNT_STAT_SUCCESS) KillAllProcesses WriteStringToFile("i", "/proc/sysrq-trigger") //借助sysrq去杀所有进程 sync(); LogShutdownTime(stat, &t); LOG(WARNING) << "powerctl_shutdown_time_ms:" << t->duration().count() << ":" << stat; //有打印耗时 RebootSystem(cmd, rebootTarget); //如往属性中写"shutdown",cmd=ANDROID_RB_POWEROFF, 若是"reboot"则 ANDROID_RB_RESTART2 if (!IsRebootCapable()) //必须要有reboot内核的权限 exit(0); switch (cmd) case ANDROID_RB_POWEROFF: //对应往属性中写"shutdown", 直接调用C库的reboot函数。 reboot(RB_POWER_OFF); //bionic/reboot.cpp __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, mode, NULL); //mode=LINUX_REBOOT_CMD_POWER_OFF case ANDROID_RB_RESTART2: //对应往属性中写"reboot" syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, rebootTarget.c_str()) //reboot系统调用,比如bootloader等。
上面用到的宏:
//bionic/libc/include/sys/reboot.h
#define RB_POWER_OFF LINUX_REBOOT_CMD_POWER_OFF
可以看到,无论是shutdown还是reboot,最终都会调用 reboot() 系统调用函数,其定义在内核 reboot.c 中。
三、内核代码流程
1. 调用流程
SYSCALL_DEFINE4(reboot, magic1, magic2, cmd, arg) //reboot.c ns_capable(pid_ns->user_ns, CAP_SYS_BOOT) //调用者必须要有root权限,且mgic要通过检查 switch (cmd) case LINUX_REBOOT_CMD_HALT: kernel_halt(); do_exit(0); panic("cannot halt"); case LINUX_REBOOT_CMD_POWER_OFF: //"shutdown"走这里 kernel_power_off(); /* 通过 reboot_notifier_list 往外广播 SYS_POWER_OFF 并将全局 system_state 设置为 * SYSTEM_POWER_OFF,然后调用各驱动的shutdown回调 */ kernel_shutdown_prepare(SYSTEM_POWER_OFF); migrate_to_reboot_cpu() //将当前线程绑定到 reboot_cpu 上 syscore_shutdown() //回调 syscore_ops_list 链表上所有 syscore_ops 的 ops->shutdown() 回调 pr_emerg("Power down\n"); //检索没有这个打印 kmsg_dump(KMSG_DUMP_POWEROFF); //将kernel log dump到dumper中, pstore注册了一个, pstore_register_kmsg() machine_power_off(); //向其它所有cpu发送 IPI_CPU_STOP 中断让其它cpu停下来 pm_power_off do_msm_poweroff //msm-poweroff.c pr_notice("Powering off the SoC\n"); //没有打印出来 deassert_ps_hold(); //取消置位 PS_HOLD,向 PMIC 发出信号,告知我们已准备好关机或复位 pr_err("Powering off has failed\n"); //没有打印出来 do_exit(0); break; case LINUX_REBOOT_CMD_RESTART2: //"reboot"走这里,arg是参数如"shell"/"bootloader kernel_restart(arg); kernel_restart_prepare(cmd); migrate_to_reboot_cpu(); syscore_shutdown(); if (!cmd) pr_emerg("Restarting system\n"); else pr_emerg("Restarting system with command '%s'\n", cmd); //有打印,正常重启cmd="adb"/"shell" kmsg_dump(KMSG_DUMP_RESTART); machine_restart(cmd); pr_emerg("%s enter\n",__func__); //有打印出来 smp_send_stop(); arm_pm_restart do_msm_restart //msm-poweroff.c pr_notice("Going down for restart now\n"); //有打印出来 msm_restart_prepare //判断了reboot的类型,如"bootloader" "recovery" "rtc" 等#### deassert_ps_hold(); break;
四、相关调试-日志
1. kernel log
//来自 last_kmsg.txt: [ 88.866737] (0)[1:init]init: Received sys.powerctl='reboot,shell' from pid: 4207 (reboot) //表示在shell命令行中执行reboot命令导致重启的 [ 88.866915] (0)[1:init]init: Clear action queue and start shutdown trigger [ 88.867159] (0)[1:init]init: processing action (shutdown_done) from (<Builtin Action>:0) [ 88.867197] (0)[1:init]init: Reboot start, reason: reboot,shell, rebootTarget: shell [ 88.896010] (3)[1:init]init: Shutdown timeout: 0 ms [ 88.896135] (3)[1:init]init: Could not start shutdown critical service 'rmt_storage': Cannot find '/vendor/bin/rmt_storage': No such file or directory [ 88.896900] (3)[1:init]init: starting service 'blank_screen'... [ 88.898827] (3)[1:init]init: Sending signal 9 to service 'mdnsd' (pid 1977) process group... [ 88.904811] (3)[1:init]libprocessgroup: Successfully killed process cgroup uid 1020 pid 1977 in 5ms ... [ 90.258250] (2)[1:init]libprocessgroup: Failed to kill process cgroup uid 0 pid 551 in 257ms, 1 processes remain [ 90.279079] (2)[1:init]init: Service 'incidentd' (pid 824) received signal 9 [ 90.279371] (2)[1:init]init: Service 'installd' (pid 825) received signal 9 ... [ 90.788846] (3)[1:init]init: Sending signal 9 to service 'logd' (pid 512) process group... [ 90.807763] (1)[1:init]init: Unmounting /dev/block/bootdevice/by-name/vmap:/mnt/vmap opts rw,seclabel,nosuid,nodev,noatime,data=ordered [ 90.853054] (0)[1:init]init: Umounted /dev/block/bootdevice/by-name/vmap:/mnt/vmap opts rw,seclabel,nosuid,nodev,noatime,data=ordered ... [ 91.676064] (2)[1:init]init: powerctl_shutdown_time_ms:2808:0 //用户空间kill任务init进程执行时间 [ 91.676121] (2)[1:init]init: Reboot ending, jumping to kernel //进入内核 [ 91.677918] (2)[1:init]sd 0:0:0:0: [sda] Synchronizing SCSI cache [ 91.685350] (2)[1:init]tda75610_mute_on_off_force: set mute 1 [ 92.293744] (0)[1:init]tda75610_shutdown: success [ 92.306601] (2)[1:init][inap562t]inap562t_video_on,enter.--> 0 reset remote to aline [ 92.306630] (2)[1:init][inap562t_remote]inap562t_clear_error clear error [ 92.324104] (2)[1:init][inap562t]panel_onOff_call,type 0x0 . [ 92.324133] (2)[1:init][inap562t_remote]inap562t_remote_suspend 252 [ 92.328938] (3)[1:init][inap562t_remote]inap562t_setState 1562 screen state set 1 [ 93.345958] (3)[1:init][inap562t_remote]suspend timeout 101 [ 93.345979] (3)[1:init][inap562t_remote]inap562t_change_mode change mode to 4 [ 93.350692] (3)[1:init]Unbalanced regulator off //这里出现了一个崩溃 [ 93.362658] (0)[601:composer@2.1-se]WARNING: at ffffff80085435c0 [verbose debug info unavailable] [ 93.425690] (0)[1:init]reboot: Restarting system with command 'shell' //kernel_restart()中的打印, shell终端执行reboot命令默认参数就是shell [ 93.434779] (0)[1:init]machine_restart enter //进入到 machine_restart() [ 93.462655] (0)[1:init]Going down for restart now //do_msm_restart()中的打印
看起来init进程的日志主要在main log中。
2. main log
F:\>adb reboot HelloWorld_1 /data/Log/log0 # grep HelloWorld_1 -r ./ ./last_kmsg.txt:[43795.524845] (1)[1:init]init: Received sys.powerctl='reboot,HelloWorld_1' from pid: 688 (/system/bin/adbd) ./last_kmsg.txt:[43795.526667] (1)[1:init]init: Reboot start, reason: reboot,HelloWorld_1, rebootTarget: HelloWorld_1 ./last_kmsg.txt:[43800.509268] (0)[1:init]reboot: Restarting system with command 'HelloWorld_1' /data/Log/log1 # /data/Log/log1 # grep HelloWorld_1 -r ./ /data/Log/log1 # /data/Log # grep ShutdownThread -r ./ /data/Log #
adb重启,main log中默认是没有打印的。
若是上层逻辑触发的重启:
kernel.txt: <14>[79443.634028] (3)[1:init]init: Received sys.powerctl='reboot,soc:ota' from pid: 875 (system_server) main.txt: 06-05 20:18:23.200 875 6689 I ShutdownThread: Shutting down package manager... 06-05 20:18:23.210 875 6691 I ShutdownThread: Waiting for Radio... 06-05 20:18:23.210 875 6691 I ShutdownThread: Radio shutdown complete. 06-05 20:18:23.211 875 6689 I ShutdownThread: Rebooting, reason: soc:ota
相关文件: /frameworks/base/services/core/java/com/android/server/power/ShutdownThread.java
五、小结
1. 上层shutdown流程
向临时属性 sys.powerctl 中写 shutdown 或 reboot 触发关机或重启;
然后init主线程被唤醒,向所有 services 发送 terminate 信号, 并等待其退出;
如果 services 没有主动退出,则发送 kill 信号,强制杀掉 service;
给 vold 发送 shutdown 命令,主动卸载挂载的设备,例如SD卡;
执行 sync 操作,同步文件系统;
调用 kernel reboot 系统调用;
2. kernel shutdown流程
通过 notifier 机制广播将要 shutdown 或 reboot;
调用各设备的 shutdown 回调,优先级class > bus > driover;
调用各个 syscore_ops->shutdown() 回调;
将 kernel log dump 到 dumper 中, 其中pstore就注册了一个 dumper;
向其它所有cpu发送 IPI_CPU_STOP 中断让其它cpu停下来;
取消置位 PS_HOLD,向 PMIC 发出信号,告知我们已准备好关机或复位;
posted on 2025-06-17 22:10 Hello-World3 阅读(291) 评论(0) 收藏 举报