一、回顾

先回顾下上部分得分析,从最开始的PM.reboot(),经过层层调用,最终调用

SystemProperties.set(“sys.powerctl”, “reboot,” + reason);

二、重启流程

aosp/system/core/init/property_service.cpp

aosp/system/core/init/reboot.cpp

aosp/system/core/init/reboot_utils.cpp

aosp/system/core/init/init.cpp

PM.reboot最终也就是setprop sys.powerctl,那么谁来监听sys.powerctl 值呢,肯定是init了,接下来就也就引入本节得重点,

init监听 sys.powerctl 处理关机后半部流程

2.1 HandlePropertySet

[->property_service.cpp]

// This returns one of the enum of PROP_SUCCESS or PROP_ERROR*.

uint32_t HandlePropertySet(const std::string& name, const std::string& value,

const std::string& source_context, const ucred& cr, std::string* error) {

...

// sys.powerctl is a special property that is used to make the device reboot. We want to log

// any process that sets this property to be able to accurately blame the cause of a shutdown.

//此时会记录到logcat中,那个进程设置sys.powerctl得以及原因

if (name == "sys.powerctl") {

std::string cmdline_path = StringPrintf("proc/%d/cmdline", cr.pid);

std::string process_cmdline;

std::string process_log_string;

if (ReadFileToString(cmdline_path, &process_cmdline)) {

// Since cmdline is null deliminated, .c_str() conveniently gives us just the process

// path.

process_log_string = StringPrintf(" (%s)", process_cmdline.c_str());

}

LOG(INFO) << "Received sys.powerctl='" << value << "' from pid: " << cr.pid

<< process_log_string;

}

...

return PropertySet(name, value, error); //设置属性值

}

2.2 HandlePropertySet

[->property_service.cpp]

static uint32_t PropertySet(const std::string& name, const std::string& value, std::string* error) {

...

property_changed(name, value);// 会通知init property值改变

return PROP_SUCCESS;

}

2.3  property_changed

[->init.cpp]

void property_changed(const std::string& name, const std::string& value) {

// If the property is sys.powerctl, we bypass the event queue and immediately handle it.

// This is to ensure that init will always and immediately shutdown/reboot, regardless of

// if there are other pending events to process or if init is waiting on an exec service or

// waiting on a property.

// In non-thermal-shutdown case, 'shutdown' trigger will be fired to let device specific

// commands to be executed.

if (name == "sys.powerctl") { //当init检测到某个进程设置 sys.powerctl时,会把do_shutdown 置true,init主循环会执行关机动作 见2.3节

// Despite the above comment, we can't call HandlePowerctlMessage() in this function,

// because it modifies the contents of the action queue, which can cause the action queue

// to get into a bad state if this function is called from a command being executed by the

// action queue. Instead we set this flag and ensure that shutdown happens before the next

// command is run in the main init loop.

// TODO: once property service is removed from init, this will never happen from a builtin,

// but rather from a callback from the property service socket, in which case this hack can

// go away.

shutdown_command = value;

do_shutdown = true;

}

if (property_triggers_enabled) ActionManager::GetInstance().QueuePropertyChange(name, value);

if (waiting_for_prop) {

if (wait_prop_name == name && wait_prop_value == value) {

LOG(INFO) << "Wait for property took " << *waiting_for_prop;

ResetWaitForProp();

}

}

}

2.4 SecondStageMain

[->init.cpp]

int SecondStageMain(int argc, char** argv) {

...

while (true) {

// By default, sleep until something happens.

auto epoll_timeout = std::optional<:chrono::milliseconds>{};

if (do_shutdown && !shutting_down) {

do_shutdown = false;

if (HandlePowerctlMessage(shutdown_command)) { //执行关机重启流程

shutting_down = true;

}

}

if (!(waiting_for_prop || Service::is_exec_service_running())) {

am.ExecuteOneCommand();

}

if (!(waiting_for_prop || Service::is_exec_service_running())) {

if (!shutting_down) {

auto next_process_action_time = HandleProcessActions();

// If there's a process that needs restarting, wake up in time for that.

if (next_process_action_time) {

epoll_timeout = std::chrono::ceil<:chrono::milliseconds>(

*next_process_action_time - boot_clock::now());

if (*epoll_timeout < 0ms) epoll_timeout = 0ms;

}

}

// If there's more work to do, wake up again immediately.

if (am.HasMoreCommands()) epoll_timeout = 0ms;

}

if (auto result = epoll.Wait(epoll_timeout); !result) {

LOG(ERROR) << result.error();

}

}

return 0;

}

2.5 HandlePowerctlMessage

[->reboot.cpp]

bool HandlePowerctlMessage(const std::string& command) {

unsigned int cmd = 0;

std::vector<:string> cmd_params = Split(command, ",");

std::string reboot_target = "";

bool run_fsck = false;

bool command_invalid = false;

if (cmd_params.size() > 3) {

command_invalid = true;

} else if (cmd_params[0] == "shutdown") {

cmd = ANDROID_RB_POWEROFF;

if (cmd_params.size() == 2) {

if (cmd_params[1] == "userrequested") {

// The shutdown reason is PowerManager.SHUTDOWN_USER_REQUESTED.

// Run fsck once the file system is remounted in read-only mode.

run_fsck = true;

} else if (cmd_params[1] == "thermal") {

// Turn off sources of heat immediately.

TurnOffBacklight();

// run_fsck is false to avoid delay

cmd = ANDROID_RB_THERMOFF;

}

}

} else if (cmd_params[0] == "reboot") {

cmd = ANDROID_RB_RESTART2;

if (cmd_params.size() >= 2) {

reboot_target = cmd_params[1];

// adb reboot fastboot should boot into bootloader for devices not

// supporting logical partitions.

if (reboot_target == "fastboot" &&

!android::base::GetBoolProperty("ro.boot.dynamic_partitions", false)) {

reboot_target = "bootloader";

}

// When rebooting to the bootloader notify the bootloader writing

// also the BCB.

if (reboot_target == "bootloader") {

std::string err;

if (!write_reboot_bootloader(&err)) {//会把bootloader写到kernel,重启使用

LOG(ERROR) << "reboot-bootloader: Error writing "

"bootloader_message: "

<< err;

}

} else if (reboot_target == "sideload" || reboot_target == "sideload-auto-reboot" ||

reboot_target == "fastboot") {

std::string arg = reboot_target == "sideload-auto-reboot" ? "sideload_auto_reboot"

: reboot_target;

const std::vector<:string> options = {

"--" + arg,

};

std::string err;

if (!write_bootloader_message(options, &err)) {//会把recovery写到kernel,重启使用

LOG(ERROR) << "Failed to set bootloader message: " << err;

return false;

}

reboot_target = "recovery";

}

// If there is an additional parameter, pass it along

if ((cmd_params.size() == 3) && cmd_params[2].size()) {

reboot_target += "," + cmd_params[2];

}

}

} else {

command_invalid = true;

}

if (command_invalid) {

LOG(ERROR) << "powerctl: unrecognized command '" << command << "'";

return false;

}

LOG(INFO) << "Clear action queue and start shutdown trigger";

ActionManager::GetInstance().ClearQueue();

// Queue shutdown trigger first

ActionManager::GetInstance().QueueEventTrigger("shutdown");//处理init.rc中shutdown部分,依次关闭各个模块

// Queue built-in shutdown_done

auto shutdown_handler = [cmd, command, reboot_target, run_fsck](const BuiltinArguments&) {

DoReboot(cmd, command, reboot_target, run_fsck); //reboot 流程核心,见下节

return Success();

};

ActionManager::GetInstance().QueueBuiltinAction(shutdown_handler, "shutdown_done");//设置中shutdown_done部分,shutdown执行完会执行DoReboot

// Skip wait for prop if it is in progress

ResetWaitForProp();

// Clear EXEC flag if there is one pending

for (const auto& s : ServiceList::GetInstance()) {

s->UnSetExec();

}

return true;

}

2.6 DoReboot

[->reboot.cpp]

//* Reboot / shutdown the system.

// cmd ANDROID_RB_* as defined in android_reboot.h

// reason Reason string like "reboot", "shutdown,userrequested"

// rebootTarget Reboot target string like "bootloader". Otherwise, it should be an

// empty string.

// runFsck Whether to run fsck after umount is done.

//

static void DoReboot(unsigned int cmd, const std::string& reason, const std::string& rebootTarget,

bool runFsck) {

Timer t;

LOG(INFO) << "Reboot start, reason: " << reason << ", rebootTarget: " << rebootTarget;

// Ensure last reboot reason is reduced to canonical

// alias reported in bootloader or system boot reason.

size_t skip = 0;

std::vector<:string> reasons = Split(reason, ",");

if (reasons.size() >= 2 && reasons[0] == "reboot" &&

(reasons[1] == "recovery" || reasons[1] == "bootloader" || reasons[1] == "cold" ||

reasons[1] == "hard" || reasons[1] == "warm")) {

skip = strlen("reboot,");

}

property_set(LAST_REBOOT_REASON_PROPERTY, reason.c_str() + skip);//设置reboot 重启原因到persist.sys.boot.reason,重启后可以查看

sync();

bool is_thermal_shutdown = cmd == ANDROID_RB_THERMOFF;

auto shutdown_timeout = 0ms;

if (!SHUTDOWN_ZERO_TIMEOUT) {

constexpr unsigned int shutdown_timeout_default = 6;

constexpr unsigned int max_thermal_shutdown_timeout = 3;

auto shutdown_timeout_final = android::base::GetUintProperty("ro.build.shutdown_timeout",

shutdown_timeout_default);

if (is_thermal_shutdown && shutdown_timeout_final > max_thermal_shutdown_timeout) {

shutdown_timeout_final = max_thermal_shutdown_timeout;

}

shutdown_timeout = std::chrono::seconds(shutdown_timeout_final);

}

LOG(INFO) << "Shutdown timeout: " << shutdown_timeout.count() << " ms";

// keep debugging tools until non critical ones are all gone.

const std::set<:string> kill_after_apps{"tombstoned", "logd", "adbd"};

// watchdogd is a vendor specific component but should be alive to complete shutdown safely.

const std::set<:string> to_starts{"watchdogd"};

for (const auto& s : ServiceList::GetInstance()) {

if (kill_after_apps.count(s->name())) {

s->SetShutdownCritical();

} else if (to_starts.count(s->name())) {

if (auto result = s->Start(); !result) {

LOG(ERROR) << "Could not start shutdown 'to_start' service '" << s->name()

<< "': " << result.error();

}

s->SetShutdownCritical();

} else if (s->IsShutdownCritical()) {

// Start shutdown critical service if not started.

if (auto result = s->Start(); !result) {

LOG(ERROR) << "Could not start shutdown critical service '" << s->name()

<< "': " << result.error();

}

}

}

// remaining operations (specifically fsck) may take a substantial duration

if (cmd == ANDROID_RB_POWEROFF || is_thermal_shutdown) {

TurnOffBacklight();

}

Service* bootAnim = ServiceList::GetInstance().FindService("bootanim");

Service* surfaceFlinger = ServiceList::GetInstance().FindService("surfaceflinger");

if (bootAnim != nullptr && surfaceFlinger != nullptr && surfaceFlinger->IsRunning()) {

// will not check animation class separately

for (const auto& service : ServiceList::GetInstance()) {

if (service->classnames().count("animation")) service->SetShutdownCritical();

}

}

// optional shutdown step

// 1. terminate all services except shutdown critical ones. wait for delay to finish

//终止除shutdown关键之外的所有服务。 等待完成

if (shutdown_timeout > 0ms) {

LOG(INFO) << "terminating init services";

// Ask all services to terminate except shutdown critical ones.

for (const auto& s : ServiceList::GetInstance().services_in_shutdown_order()) {

if (!s->IsShutdownCritical()) s->Terminate();

}

int service_count = 0;

// Only wait up to half of timeout here

auto termination_wait_timeout = shutdown_timeout / 2;

while (t.duration() < termination_wait_timeout) {

ReapAnyOutstandingChildren();

service_count = 0;

for (const auto& s : ServiceList::GetInstance()) {

// Count the number of services running except shutdown critical.

// Exclude the console as it will ignore the SIGTERM signal

// and not exit.

// Note: SVC_CONSOLE actually means "requires console" but

// it is only used by the shell.

if (!s->IsShutdownCritical() && s->pid() != 0 && (s->flags() & SVC_CONSOLE) == 0) {

service_count++;

}

}

if (service_count == 0) {

// All terminable services terminated. We can exit early.

break;

}

// Wait a bit before recounting the number or running services.

std::this_thread::sleep_for(50ms);

}

LOG(INFO) << "Terminating running services took " << t

<< " with remaining services:" << service_count;

}

// minimum safety steps before restarting

// 2. kill all services except ones that are necessary for the shutdown sequence.

//2. 关闭所有得服务

for (const auto& s : ServiceList::GetInstance().services_in_shutdown_order()) {

if (!s->IsShutdownCritical()) s->Stop();

}

SubcontextTerminate();

ReapAnyOutstandingChildren();

// 3. send volume shutdown to vold

// 3. 关闭vold

Service* voldService = ServiceList::GetInstance().FindService("vold");

if (voldService != nullptr && voldService->IsRunning()) {

ShutdownVold();

voldService->Stop();

} else {

LOG(INFO) << "vold not running, skipping vold shutdown";

}

// logcat stopped here

for (const auto& s : ServiceList::GetInstance().services_in_shutdown_order()) {

if (kill_after_apps.count(s->name())) s->Stop();

}

// 4. sync, try umount, and optionally run fsck for user shutdown

//4. 同步,卸载分区,

{

Timer sync_timer;

LOG(INFO) << "sync() before umount...";

sync();

LOG(INFO) << "sync() before umount took" << sync_timer;

}

UmountStat stat = TryUmountAndFsck(runFsck, shutdown_timeout - t.duration());

// Follow what linux shutdown is doing: one more sync with little bit delay

{

Timer sync_timer;

LOG(INFO) << "sync() after umount...";

sync();

LOG(INFO) << "sync() after umount took" << sync_timer;

}

if (!is_thermal_shutdown) std::this_thread::sleep_for(100ms);

LogShutdownTime(stat, &t);

// Reboot regardless of umount status. If umount fails, fsck after reboot will fix it.

RebootSystem(cmd, rebootTarget); //重启系统

abort();

}

2.7 RebootSystem

[->reboot_utils.cpp]

void __attribute__((noreturn)) RebootSystem(unsigned int cmd, const std::string& rebootTarget) {

LOG(INFO) << "Reboot ending, jumping to kernel";

if (!IsRebootCapable()) {

// On systems where init does not have the capability of rebooting the

// device, just exit cleanly.

exit(0);

}

//下面就是reboot的system call进入内核空间了:

switch (cmd) {

case ANDROID_RB_POWEROFF:

reboot(RB_POWER_OFF); //调用reboot函数执行关机

break;

case ANDROID_RB_RESTART2:

syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,

LINUX_REBOOT_CMD_RESTART2, rebootTarget.c_str());//调用syscall函数执行重启

break;

case ANDROID_RB_THERMOFF:

reboot(RB_POWER_OFF);//调用reboot函数执行重启

break;

}

// In normal case, reboot should not return.

PLOG(ERROR) << "reboot call returned";

abort();

}

三、总结

一句话总结,从 设置属性sys.powerctrl,最终重启调用libc库得  reboot或syscall, 也就意味这reboot下一步流程到达内核空间,

内核空间部分留着下一节继续。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐