L 上面
on property:sys.powerctl=*
powerctl ${sys.powerctl}
O 上面:
...
// Don't write properties to disk until after we have read all default
// properties to prevent them from being overwritten by default values.
if (persistent_properties_loaded && android::base::StartsWith(name, "persist.")) {
write_persistent_property(name.c_str(), value.c_str());
}
property_changed(name, value);
222 #ifdef MTK_INIT
223 if (!(android::base::StartsWith(name, "ro.") || android::base::StartsWith(name, "persist.log.tag"))) {[ 139.622966] <1>.(1)[1:init]init: PropSet [sys.powerctl]=[shutdown,userrequested] Done
[ 139.624215] <1>.(1)[1:init]init: Clear action queue and start shutdown trigger
[ 139.630254] <1>.(1)[1:init]init: processing action (shutdown_done) from (
[ 139.631524] <1>.(1)[1:init]init: Reboot start, reason: shutdown,userrequested, rebootTarget:
[ 139.634069] <1>.(1)[1:init]init: Shutdown timeout: 0 ms
[ 139.635121] <1>.(1)[1:init]init: Sending signal 9 to service 'healthd' (pid 272) process group...kernel-
system/core/init/init.cpp
void property_changed(const std::string& name, const std::string& value) {
if (name == "sys.powerctl") {
// 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;
}
}
这里设置do_shutdown = true;
system/core/init/init.cpp
init 主循环中
main(..){
am.QueueBuiltinAction(queue_property_triggers_action, "queue_property_triggers");
while (true) {
// By default, sleep until something happens.
int epoll_timeout_ms = -1;
if (do_shutdown && !shutting_down) {
do_shutdown = false;
if (HandlePowerctlMessage(shutdown_command)) {
shutting_down = true;
}
}
}
system/core/init/reboot.cpp
bool HandlePowerctlMessage(const std::string& command) {
if (cmd_params.size() > 3) {
command_invalid = true;
} else if (cmd_params[0] == "shutdown") {
cmd = ANDROID_RB_POWEROFF;
if (cmd_params.size() == 2 && 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;
}
}
....
LOG(INFO) << "Clear action queue and start shutdown trigger";
ActionManager::GetInstance().ClearQueue();
// Queue shutdown trigger first
ActionManager::GetInstance().QueueEventTrigger("shutdown");
// Queue built-in shutdown_done
auto shutdown_handler = [cmd, command, reboot_target,
run_fsck](const std::vector
DoReboot(cmd, command, reboot_target, run_fsck);
return 0;
};
ActionManager::GetInstance().QueueBuiltinAction(shutdown_handler, "shutdown_done");
}
system/core/init/action.cpp
void ActionManager::ExecuteOneCommand() {
// Loop through the event queue until we have an action to execute
while (current_executing_actions_.empty() && !event_queue_.empty()) {
for (const auto& action : actions_) {
if (std::visit([&action](const auto& event) { return action->CheckEvent(event); },
event_queue_.front())) {
current_executing_actions_.emplace(action.get());
}
}
event_queue_.pop();
}
if (current_executing_actions_.empty()) {
return;
}
auto action = current_executing_actions_.front();
if (current_command_ == 0) {
std::string trigger_name = action->BuildTriggersString();
LOG(INFO) << "processing action (" << trigger_name << ") from (" << action->filename()
<< ":" << action->line() << ")";
}
action->ExecuteOneCommand(current_command_);
}
system/core/init/reboot.cpp
void DoReboot(unsigned int cmd, const std::string& reason, const std::string& rebootTarget,
bool runFsck) {
Timer t;
LOG(ERROR) << "Reboot start, reason: " << reason << ", rebootTarget: " << rebootTarget;
android::base::WriteStringToFile(StringPrintf("%s\n", reason.c_str()), LAST_REBOOT_REASON_FILE,
S_IRUSR | S_IWUSR, AID_SYSTEM, AID_SYSTEM);
bool is_thermal_shutdown = false;
if (cmd == ANDROID_RB_THERMOFF) {
is_thermal_shutdown = true;
runFsck = false;
}
auto shutdown_timeout = 0ms;
if (!SHUTDOWN_ZERO_TIMEOUT) {
if (is_thermal_shutdown) {
constexpr unsigned int thermal_shutdown_timeout = 1;
shutdown_timeout = std::chrono::seconds(thermal_shutdown_timeout);
} else {
constexpr unsigned int shutdown_timeout_default = 6;
auto shutdown_timeout_property = android::base::GetUintProperty(
"ro.build.shutdown_timeout", shutdown_timeout_default);
shutdown_timeout = std::chrono::seconds(shutdown_timeout_property);
}
}
LOG(INFO) << "Shutdown timeout: " << shutdown_timeout.count() << " ms";
// keep debugging tools until non critical ones are all gone.
const std::set
// watchdogd is a vendor specific component but should be alive to complete shutdown safely.
const std::set
ServiceManager::GetInstance().ForEachService([&kill_after_apps, &to_starts](Service* s) { //关闭服务
if (kill_after_apps.count(s->name())) {
s->SetShutdownCritical();
} else if (to_starts.count(s->name())) {
s->Start();
s->SetShutdownCritical();
} else if (s->IsShutdownCritical()) {
s->Start(); // start shutdown critical service if not started
}
});
Service* bootAnim = ServiceManager::GetInstance().FindServiceByName("bootanim");
Service* surfaceFlinger = ServiceManager::GetInstance().FindServiceByName("surfaceflinger");
if (bootAnim != nullptr && surfaceFlinger != nullptr && surfaceFlinger->IsRunning()) {
ServiceManager::GetInstance().ForEachServiceInClass("animation", [](Service* s) {
s->SetShutdownCritical(); // will not check animation class separately
});
}
// optional shutdown step
// 1. terminate all services except shutdown critical ones. wait for delay to finish
if (shutdown_timeout > 0ms) {
LOG(INFO) << "terminating init services";
// Ask all services to terminate except shutdown critical ones.
ServiceManager::GetInstance().ForEachService([](Service* s) {
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) {
ServiceManager::GetInstance().ReapAnyOutstandingChildren();
service_count = 0;
ServiceManager::GetInstance().ForEachService([&service_count](Service* s) {
// 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.
ServiceManager::GetInstance().ForEachService([](Service* s) {
if (!s->IsShutdownCritical()) s->Stop();
});
ServiceManager::GetInstance().ReapAnyOutstandingChildren();
// 3. send volume shutdown to vold
Service* voldService = ServiceManager::GetInstance().FindServiceByName("vold");
if (voldService != nullptr && voldService->IsRunning()) {
ShutdownVold();
voldService->Stop();
} else {
LOG(INFO) << "vold not running, skipping vold shutdown";
}
// logcat stopped here
ServiceManager::GetInstance().ForEachService([&kill_after_apps](Service* s) {
if (kill_after_apps.count(s->name())) s->Stop();
});
// 4. sync, try umount, and optionally run fsck for user shutdown
sync();
UmountStat stat = TryUmountAndFsck(runFsck, shutdown_timeout - t.duration()); //runFsck 会花时间
// Follow what linux shutdown is doing: one more sync with little bit delay
sync();
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();
}
开始关机
[ 139.622966] <1>.(1)[1:init]init: PropSet [sys.powerctl]=[shutdown,userrequested] Done
关机结束(LogShutdownTime 打印)
[ 149.290872] <0>.(0)[1:init]init: powerctl_shutdown_time_ms:9659:0
这个过程时间:
1、关闭服务
[ 143.696451] <2>.(2)[1:init]init: PropSet [init.svc.logd]=[stopping] Done
[ 143.696936] <2>.(1)[94:kworker/u8:1]Mali<2>: [+] MFG disable_clock
[ 143.698253] <2>.(2)[1:init]init: Sending signal 9 to service 'tombstoned' (pid 367) process group...
[ 143.705282] <2>.(2)[1:init]init: Successfully killed process cgroup uid 1058 pid 367 in 5ms
[ 143.707150] <2>.(2)[1:init]init: PropSet [init.svc.tombstoned]=[stopping] Done
2、runFsck 为true 的话
[ 144.467429] <1>.(1)[1:init]e2fsck: libc: /system/bin/e2fsck: malloc debug enabled
[ 144.467429] <1>
[ 144.468768] <1>.(1)[1:init]e2fsck: e2fsck 1.43.3 (04-Sep-2016)
system/core/init/reboot.cpp
static 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);
}
switch (cmd) {
case ANDROID_RB_POWEROFF:
reboot(RB_POWER_OFF);
break;
case ANDROID_RB_RESTART2:
syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
LINUX_REBOOT_CMD_RESTART2, rebootTarget.c_str());
break;
case ANDROID_RB_THERMOFF:
reboot(RB_POWER_OFF);
break;
}
// In normal case, reboot should not return.
PLOG(FATAL) << "reboot call returned";
abort();
}
#define RB_POWER_OFF LINUX_REBOOT_CMD_POWER_OFF
4.4/kernel/reboot.c
case LINUX_REBOOT_CMD_POWER_OFF:
break;
}
[ 139.622966]<1>.(1)[1:init]init: PropSet [sys.powerctl]=[shutdown,userrequested] Done
[ 139.635121]<1>.(1)[1:init]init: Sending signal 9 to service 'healthd' (pid 272)process group...
[ 143.698253]<2>.(2)[1:init]init: Sending signal 9 to service 'tombstoned' (pid 367)process group...
关闭服务花时间 4s
[ 143.753199]<2>.(2)[1:init]init: umounted/dev/block/platform/mtk-msdc.0/11120000.msdc0/by-name/persist:/vendor/persistopts rw,seclabel,nosuid,nodev,noatime,nodelalloc,noauto_da_alloc,commit=1,data=ordered
[ 144.217226]<2>.(2)[1:init]init: umounted/dev/block/platform/mtk-msdc.0/11120000.msdc0/by-name/userdata:/data optsrw,lazytime,seclabel,nosuid,nodev,noatime,background_gc=on,discard,no_heap,user_xattr,inline_xattr,acl,inline_data,inline_dentry,extent_cache,mode=adaptive,active_logs=6
卸载分区化时间 0.5s
[ 144.467429]<1>.(1)[1:init]e2fsck: libc: /system/bin/e2fsck: malloc debug enabled
[ 145.019986]<1>.(1)[1:init]e2fsck: cache: 14/7168 files (0.0% non-contiguous),1490/28672 blocks
[ 149.146942]<1>.(1)[1:init]fsck.f2fs: libc: /system/bin/fsck.f2fs: malloc debugenabled
[ 149.189094]<0>.(0)[1:init]fsck.f2fs: Done.
e2fsck 跟 fsck 花时间 4.7s
[ 149.290872]<0>.(0)[1:init]init: powerctl_shutdown_time_ms:9659:0
[ 149.291735]<0>.(0)[1:init]init: Reboot ending, jumping to kernel
这里看能不能把 e2fsck 跟 fsck 花时间 4.7s 优化
实测6580平台,关机时间确实较6739平台长;关机时间长 9~10S;
https://www.2cto.com/kf/201501/367859.html