int do_powerctl(int nargs, char **args) { char command[PROP_VALUE_MAX]; int res; int len = 0; int cmd = 0; const char *reboot_target; void (*callback_on_ro_remount)(const struct mntent*) = NULL; 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) { if (property_get_bool("init.shutdown_to_charging", false)) { return android_reboot(ANDROID_RB_RESTART2, 0, "charging"); } cmd = ANDROID_RB_POWEROFF; len = 8; callback_on_ro_remount = unmount_and_fsck; } 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] == ',') { char prop_value[PROP_VALUE_MAX] = {0}; reboot_target = &command[len + 1]; if ((property_get("init.svc.recovery", prop_value) == 0) && (strncmp(reboot_target, "keys", 4) == 0)) { ERROR("powerctl: permission denied\n"); return -EINVAL; } } else if (command[len] == '\0') { reboot_target = ""; } else { ERROR("powerctl: unrecognized reboot target '%s'\n", &command[len]); return -EINVAL; } return android_reboot_with_callback(cmd, 0, reboot_target, callback_on_ro_remount); }
static int do_powerctl(const std::vector<std::string>& args) { const char* command = args[1].c_str(); int len = 0; unsigned int cmd = 0; const char *reboot_target = ""; void (*callback_on_ro_remount)(const struct mntent*) = NULL; 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] == ',') { if (cmd == ANDROID_RB_POWEROFF && !strcmp(&command[len + 1], "userrequested")) { // The shutdown reason is PowerManager.SHUTDOWN_USER_REQUESTED. // Run fsck once the file system is remounted in read-only mode. callback_on_ro_remount = unmount_and_fsck; } else if (cmd == ANDROID_RB_RESTART2) { reboot_target = &command[len + 1]; } } else if (command[len] != '\0') { ERROR("powerctl: unrecognized reboot target '%s'\n", &command[len]); return -EINVAL; } std::string timeout = property_get("ro.build.shutdown_timeout"); unsigned int delay = 0; if (android::base::ParseUint(timeout.c_str(), &delay) && delay > 0) { Timer t; // Ask all services to terminate. ServiceManager::GetInstance().ForEachService( [] (Service* s) { s->Terminate(); }); while (t.duration() < delay) { ServiceManager::GetInstance().ReapAnyOutstandingChildren(); int service_count = 0; ServiceManager::GetInstance().ForEachService( [&service_count] (Service* s) { // Count the number of services running. // 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->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. usleep(kTerminateServiceDelayMicroSeconds); } NOTICE("Terminating running services took %.02f seconds", t.duration()); } return android_reboot_with_callback(cmd, 0, reboot_target, callback_on_ro_remount); }