diff --git a/init/README.md b/init/README.md index 024d5591b..0d8f4954c 100644 --- a/init/README.md +++ b/init/README.md @@ -311,6 +311,12 @@ Commands groups can be provided. No other commands will be run until this one finishes. _seclabel_ can be a - to denote default. Properties are expanded within _argument_. + Init halts executing commands until the forked process exits. + +`exec_start ` +> Start service a given service and halt processing of additional init commands + until it returns. It functions similarly to the `exec` command, but uses an + existing service definition instead of providing them as arguments. `export ` > Set the environment variable _name_ equal to _value_ in the diff --git a/init/action.cpp b/init/action.cpp index 1bba0f262..2ccf0bc53 100644 --- a/init/action.cpp +++ b/init/action.cpp @@ -18,14 +18,14 @@ #include -#include +#include #include +#include #include "builtins.h" #include "error.h" #include "init_parser.h" #include "log.h" -#include "property_service.h" #include "util.h" using android::base::Join; @@ -219,9 +219,8 @@ bool Action::CheckPropertyTriggers(const std::string& name, found = true; } } else { - std::string prop_val = property_get(trigger_name.c_str()); - if (prop_val.empty() || (trigger_value != "*" && - trigger_value != prop_val)) { + std::string prop_val = android::base::GetProperty(trigger_name, ""); + if (prop_val.empty() || (trigger_value != "*" && trigger_value != prop_val)) { return false; } } diff --git a/init/bootchart.cpp b/init/bootchart.cpp index 4a9c32e2c..beabea144 100644 --- a/init/bootchart.cpp +++ b/init/bootchart.cpp @@ -16,8 +16,6 @@ #include "bootchart.h" -#include "property_service.h" - #include #include #include @@ -39,6 +37,7 @@ #include #include +#include #include using android::base::StringPrintf; @@ -72,7 +71,7 @@ static void log_header() { utsname uts; if (uname(&uts) == -1) return; - std::string fingerprint = property_get("ro.build.fingerprint"); + std::string fingerprint = android::base::GetProperty("ro.build.fingerprint", ""); if (fingerprint.empty()) return; std::string kernel_cmdline; diff --git a/init/builtins.cpp b/init/builtins.cpp index 95f1aa0f8..02e314f64 100644 --- a/init/builtins.cpp +++ b/init/builtins.cpp @@ -45,16 +45,16 @@ #include #include -#include #include #include -#include +#include #include +#include #include -#include #include #include #include +#include #include #include "action.h" @@ -167,19 +167,11 @@ static int do_enable(const std::vector& args) { } static int do_exec(const std::vector& args) { - Service* svc = ServiceManager::GetInstance().MakeExecOneshotService(args); - if (!svc) { - return -1; - } - if (!start_waiting_for_exec()) { - return -1; - } - if (!svc->Start()) { - stop_waiting_for_exec(); - ServiceManager::GetInstance().RemoveService(*svc); - return -1; - } - return 0; + return ServiceManager::GetInstance().Exec(args) ? 0 : -1; +} + +static int do_exec_start(const std::vector& args) { + return ServiceManager::GetInstance().ExecStart(args[1]) ? 0 : -1; } static int do_export(const std::vector& args) { @@ -880,8 +872,7 @@ static int do_installkeys_ensure_dir_exists(const char* dir) { } static bool is_file_crypto() { - std::string value = property_get("ro.crypto.type"); - return value == "file"; + return android::base::GetProperty("ro.crypto.type", "") == "file"; } static int do_installkey(const std::vector& args) { @@ -898,6 +889,7 @@ static int do_init_user0(const std::vector& args) { BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const { constexpr std::size_t kMax = std::numeric_limits::max(); + // clang-format off static const Map builtin_functions = { {"bootchart", {1, 1, do_bootchart}}, {"chmod", {2, 2, do_chmod}}, @@ -910,6 +902,7 @@ BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const { {"domainname", {1, 1, do_domainname}}, {"enable", {1, 1, do_enable}}, {"exec", {1, kMax, do_exec}}, + {"exec_start", {1, 1, do_exec_start}}, {"export", {2, 2, do_export}}, {"hostname", {1, 1, do_hostname}}, {"ifup", {1, 1, do_ifup}}, @@ -943,5 +936,6 @@ BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const { {"wait_for_prop", {2, 2, do_wait_for_prop}}, {"write", {2, 2, do_write}}, }; + // clang-format on return builtin_functions; } diff --git a/init/init.cpp b/init/init.cpp index 34de279d3..a1d9f1b39 100644 --- a/init/init.cpp +++ b/init/init.cpp @@ -41,13 +41,10 @@ #include #include +#include #include #include #include -#include -#include -#include -#include #include #include @@ -72,6 +69,7 @@ #include "util.h" #include "watchdogd.h" +using android::base::GetProperty; using android::base::StringPrintf; struct selabel_handle *sehandle; @@ -86,8 +84,6 @@ static time_t process_needs_restart_at; const char *ENV[32]; -static std::unique_ptr waiting_for_exec(nullptr); - static int epoll_fd = -1; static std::unique_ptr waiting_for_prop(nullptr); @@ -135,29 +131,12 @@ int add_environment(const char *key, const char *val) return -1; } -bool start_waiting_for_exec() -{ - if (waiting_for_exec) { - return false; - } - waiting_for_exec.reset(new Timer()); - return true; -} - -void stop_waiting_for_exec() -{ - if (waiting_for_exec) { - LOG(INFO) << "Wait for exec took " << *waiting_for_exec; - waiting_for_exec.reset(); - } -} - bool start_waiting_for_property(const char *name, const char *value) { if (waiting_for_prop) { return false; } - if (property_get(name) != value) { + if (GetProperty(name, "") != value) { // Current property value is not equal to expected value wait_prop_name = name; wait_prop_value = value; @@ -445,7 +424,7 @@ static int keychord_init_action(const std::vector& args) static int console_init_action(const std::vector& args) { - std::string console = property_get("ro.boot.console"); + std::string console = GetProperty("ro.boot.console", ""); if (!console.empty()) { default_console = "/dev/" + console; } @@ -469,11 +448,11 @@ static void import_kernel_nv(const std::string& key, const std::string& value, b } static void export_oem_lock_status() { - if (property_get("ro.oem_unlock_supported") != "1") { + if (!android::base::GetBoolProperty("ro.oem_unlock_supported", false)) { return; } - std::string value = property_get("ro.boot.verifiedbootstate"); + std::string value = GetProperty("ro.boot.verifiedbootstate", ""); if (!value.empty()) { property_set("ro.boot.flash.locked", value == "orange" ? "0" : "1"); @@ -494,7 +473,7 @@ static void export_kernel_boot_props() { { "ro.boot.revision", "ro.revision", "0", }, }; for (size_t i = 0; i < arraysize(prop_map); i++) { - std::string value = property_get(prop_map[i].src_prop); + std::string value = GetProperty(prop_map[i].src_prop, ""); property_set(prop_map[i].dst_prop, (!value.empty()) ? value.c_str() : prop_map[i].default_value); } } @@ -1284,7 +1263,7 @@ int main(int argc, char** argv) { parser.AddSectionParser("service",std::make_unique()); parser.AddSectionParser("on", std::make_unique()); parser.AddSectionParser("import", std::make_unique()); - std::string bootscript = property_get("ro.boot.init_rc"); + std::string bootscript = GetProperty("ro.boot.init_rc", ""); if (bootscript.empty()) { parser.ParseConfig("/init.rc"); parser.set_is_system_etc_init_loaded( @@ -1324,7 +1303,7 @@ int main(int argc, char** argv) { am.QueueBuiltinAction(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng"); // Don't mount filesystems or start core system services in charger mode. - std::string bootmode = property_get("ro.bootmode"); + std::string bootmode = GetProperty("ro.bootmode", ""); if (bootmode == "charger") { am.QueueEventTrigger("charger"); } else { @@ -1338,10 +1317,10 @@ int main(int argc, char** argv) { // By default, sleep until something happens. int epoll_timeout_ms = -1; - if (!(waiting_for_exec || waiting_for_prop)) { + if (!(waiting_for_prop || ServiceManager::GetInstance().IsWaitingForExec())) { am.ExecuteOneCommand(); } - if (!(waiting_for_exec || waiting_for_prop)) { + if (!(waiting_for_prop || ServiceManager::GetInstance().IsWaitingForExec())) { restart_processes(); // If there's a process that needs restarting, wake up in time for that. diff --git a/init/init.h b/init/init.h index b4d25fb0b..fe850efd7 100644 --- a/init/init.h +++ b/init/init.h @@ -32,10 +32,6 @@ void register_epoll_handler(int fd, void (*fn)()); int add_environment(const char* key, const char* val); -bool start_waiting_for_exec(); - -void stop_waiting_for_exec(); - bool start_waiting_for_property(const char *name, const char *value); #endif /* _INIT_INIT_H */ diff --git a/init/keychords.cpp b/init/keychords.cpp index 3dbb2f0d0..5801ea88f 100644 --- a/init/keychords.cpp +++ b/init/keychords.cpp @@ -23,9 +23,10 @@ #include #include +#include + #include "init.h" #include "log.h" -#include "property_service.h" #include "service.h" static struct input_keychord *keychords = 0; @@ -74,7 +75,7 @@ static void handle_keychord() { } // Only handle keychords if adb is enabled. - std::string adb_enabled = property_get("init.svc.adbd"); + std::string adb_enabled = android::base::GetProperty("init.svc.adbd", ""); if (adb_enabled == "running") { Service* svc = ServiceManager::GetInstance().FindServiceByKeychord(id); if (svc) { diff --git a/init/property_service.cpp b/init/property_service.cpp index 983e6846b..a4d8b5fd1 100644 --- a/init/property_service.cpp +++ b/init/property_service.cpp @@ -30,10 +30,6 @@ #include #include -#include -#include -#include - #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_ #include @@ -118,12 +114,6 @@ static int check_control_mac_perms(const char *name, char *sctx, struct ucred *c return check_mac_perms(ctl_name, sctx, cr); } -std::string property_get(const char* name) { - char value[PROP_VALUE_MAX] = {0}; - __system_property_get(name, value); - return value; -} - static void write_persistent_property(const char *name, const char *value) { char tempPath[PATH_MAX]; @@ -592,10 +582,7 @@ void property_load_boot_defaults() { static void load_override_properties() { if (ALLOW_LOCAL_PROP_OVERRIDE) { - std::string debuggable = property_get("ro.debuggable"); - if (debuggable == "1") { - load_properties_from_file("/data/local.prop", NULL); - } + load_properties_from_file("/data/local.prop", NULL); } } diff --git a/init/property_service.h b/init/property_service.h index 5d5947325..994da63da 100644 --- a/init/property_service.h +++ b/init/property_service.h @@ -32,7 +32,6 @@ void property_load_boot_defaults(void); void load_persist_props(void); void load_system_props(void); void start_property_service(void); -std::string property_get(const char* name); uint32_t property_set(const std::string& name, const std::string& value); bool is_legal_property_name(const std::string& name); diff --git a/init/reboot.cpp b/init/reboot.cpp index 261a437dd..2844d78bb 100644 --- a/init/reboot.cpp +++ b/init/reboot.cpp @@ -32,17 +32,15 @@ #include #include -#include +#include #include #include #include #include -#include #include #include #include "log.h" -#include "property_service.h" #include "reboot.h" #include "service.h" #include "util.h" @@ -342,12 +340,9 @@ void DoReboot(unsigned int cmd, const std::string& reason, const std::string& re abort(); } - std::string timeout = property_get("ro.build.shutdown_timeout"); /* TODO update default waiting time based on usage data */ - unsigned int shutdownTimeout = 10; // default value - if (android::base::ParseUint(timeout, &shutdownTimeout)) { - LOG(INFO) << "ro.build.shutdown_timeout set:" << shutdownTimeout; - } + unsigned int shutdownTimeout = android::base::GetUintProperty("ro.build.shutdown_timeout", 10u); + LOG(INFO) << "Shutdown timeout: " << shutdownTimeout; static const constexpr char* shutdown_critical_services[] = {"vold", "watchdogd"}; for (const char* name : shutdown_critical_services) { diff --git a/init/service.cpp b/init/service.cpp index c6ef83889..ede63640d 100644 --- a/init/service.cpp +++ b/init/service.cpp @@ -34,6 +34,7 @@ #include #include +#include #include #include #include @@ -191,8 +192,8 @@ Service::Service(const std::string& name, unsigned flags, uid_t uid, gid_t gid, } void Service::NotifyStateChange(const std::string& new_state) const { - if ((flags_ & SVC_EXEC) != 0) { - // 'exec' commands don't have properties tracking their state. + if ((flags_ & SVC_TEMPORARY) != 0) { + // Services created by 'exec' are temporary and don't have properties tracking their state. return; } @@ -259,7 +260,7 @@ void Service::SetProcessAttributes() { } } -bool Service::Reap() { +void Service::Reap() { if (!(flags_ & SVC_ONESHOT) || (flags_ & SVC_RESTART)) { KillProcessGroup(SIGKILL); } @@ -270,7 +271,10 @@ bool Service::Reap() { if (flags_ & SVC_EXEC) { LOG(INFO) << "SVC_EXEC pid " << pid_ << " finished..."; - return true; + } + + if (flags_ & SVC_TEMPORARY) { + return; } pid_ = 0; @@ -285,7 +289,7 @@ bool Service::Reap() { // Disabled and reset processes do not get restarted automatically. if (flags_ & (SVC_DISABLED | SVC_RESET)) { NotifyStateChange("stopped"); - return false; + return; } // If we crash > 4 times in 4 minutes, reboot into recovery. @@ -309,7 +313,7 @@ bool Service::Reap() { onrestart_.ExecuteAllCommands(); NotifyStateChange("restarting"); - return false; + return; } void Service::DumpState() const { @@ -577,6 +581,18 @@ bool Service::ParseLine(const std::vector& args, std::string* err) return (this->*parser)(args, err); } +bool Service::ExecStart(std::unique_ptr* exec_waiter) { + flags_ |= SVC_EXEC | SVC_ONESHOT; + + exec_waiter->reset(new Timer); + + if (!Start()) { + exec_waiter->reset(); + return false; + } + return true; +} + bool Service::Start() { // Starting a service removes it from the disabled or reset state and // immediately takes it out of the restarting state if it was in there. @@ -657,7 +673,7 @@ bool Service::Start() { if (iter == writepid_files_.end()) { // There were no "writepid" instructions for cpusets, check if the system default // cpuset is specified to be used for the process. - std::string default_cpuset = property_get("ro.cpuset.default"); + std::string default_cpuset = android::base::GetProperty("ro.cpuset.default", ""); if (!default_cpuset.empty()) { // Make sure the cpuset name starts and ends with '/'. // A single '/' means the 'root' cpuset. @@ -863,6 +879,35 @@ void ServiceManager::AddService(std::unique_ptr service) { services_.emplace_back(std::move(service)); } +bool ServiceManager::Exec(const std::vector& args) { + Service* svc = MakeExecOneshotService(args); + if (!svc) { + LOG(ERROR) << "Could not create exec service"; + return false; + } + if (!svc->ExecStart(&exec_waiter_)) { + LOG(ERROR) << "Could not start exec service"; + ServiceManager::GetInstance().RemoveService(*svc); + return false; + } + return true; +} + +bool ServiceManager::ExecStart(const std::string& name) { + Service* svc = FindServiceByName(name); + if (!svc) { + LOG(ERROR) << "ExecStart(" << name << "): Service not found"; + return false; + } + if (!svc->ExecStart(&exec_waiter_)) { + LOG(ERROR) << "ExecStart(" << name << "): Could not start Service"; + return false; + } + return true; +} + +bool ServiceManager::IsWaitingForExec() const { return exec_waiter_ != nullptr; } + Service* ServiceManager::MakeExecOneshotService(const std::vector& args) { // Parse the arguments: exec [SECLABEL [UID [GID]*] --] COMMAND ARGS... // SECLABEL can be a - to denote default @@ -886,7 +931,7 @@ Service* ServiceManager::MakeExecOneshotService(const std::vector& exec_count_++; std::string name = StringPrintf("exec %d (%s)", exec_count_, str_args[0].c_str()); - unsigned flags = SVC_EXEC | SVC_ONESHOT; + unsigned flags = SVC_EXEC | SVC_ONESHOT | SVC_TEMPORARY; CapSet no_capabilities; unsigned namespace_flags = 0; @@ -1026,8 +1071,13 @@ bool ServiceManager::ReapOneProcess() { return true; } - if (svc->Reap()) { - stop_waiting_for_exec(); + svc->Reap(); + + if (svc->flags() & SVC_EXEC) { + LOG(INFO) << "Wait for exec took " << *exec_waiter_; + exec_waiter_.reset(); + } + if (svc->flags() & SVC_TEMPORARY) { RemoveService(*svc); } diff --git a/init/service.h b/init/service.h index 9a9046b9e..f08a03f9a 100644 --- a/init/service.h +++ b/init/service.h @@ -44,10 +44,13 @@ #define SVC_RC_DISABLED 0x080 // Remember if the disabled flag was set in the rc script. #define SVC_RESTART 0x100 // Use to safely restart (stop, wait, start) a service. #define SVC_DISABLED_START 0x200 // A start was requested but it was disabled at the time. -#define SVC_EXEC 0x400 // This synthetic service corresponds to an 'exec'. +#define SVC_EXEC 0x400 // This service was started by either 'exec' or 'exec_start' and stops + // init from processing more commands until it completes #define SVC_SHUTDOWN_CRITICAL 0x800 // This service is critical for shutdown and // should not be killed during shutdown +#define SVC_TEMPORARY 0x1000 // This service was started by 'exec' and should be removed from the + // service list once it is reaped. #define NR_SVC_SUPP_GIDS 12 // twelve supplementary groups @@ -72,6 +75,7 @@ class Service { bool IsRunning() { return (flags_ & SVC_RUNNING) != 0; } bool ParseLine(const std::vector& args, std::string* err); + bool ExecStart(std::unique_ptr* exec_waiter); bool Start(); bool StartIfNotDisabled(); bool Enable(); @@ -80,7 +84,7 @@ class Service { void Terminate(); void Restart(); void RestartIfNeeded(time_t* process_needs_restart_at); - bool Reap(); + void Reap(); void DumpState() const; void SetShutdownCritical() { flags_ |= SVC_SHUTDOWN_CRITICAL; } bool IsShutdownCritical() const { return (flags_ & SVC_SHUTDOWN_CRITICAL) != 0; } @@ -178,6 +182,9 @@ public: void AddService(std::unique_ptr service); Service* MakeExecOneshotService(const std::vector& args); + bool Exec(const std::vector& args); + bool ExecStart(const std::string& name); + bool IsWaitingForExec() const; Service* FindServiceByName(const std::string& name) const; Service* FindServiceByPid(pid_t pid) const; Service* FindServiceByKeychord(int keychord_id) const; @@ -198,6 +205,8 @@ private: bool ReapOneProcess(); static int exec_count_; // Every service needs a unique name. + std::unique_ptr exec_waiter_; + std::vector> services_; }; diff --git a/init/signal_handler.cpp b/init/signal_handler.cpp index 1041b82d0..5e3acac09 100644 --- a/init/signal_handler.cpp +++ b/init/signal_handler.cpp @@ -24,8 +24,6 @@ #include #include -#include -#include #include "action.h" #include "init.h" diff --git a/init/ueventd.cpp b/init/ueventd.cpp index 915afbdfb..f27be6479 100644 --- a/init/ueventd.cpp +++ b/init/ueventd.cpp @@ -26,6 +26,7 @@ #include +#include #include #include @@ -34,7 +35,6 @@ #include "util.h" #include "devices.h" #include "ueventd_parser.h" -#include "property_service.h" int ueventd_main(int argc, char **argv) { @@ -71,7 +71,7 @@ int ueventd_main(int argc, char **argv) * TODO: cleanup platform ueventd.rc to remove vendor specific * device node entries (b/34968103) */ - std::string hardware = property_get("ro.hardware"); + std::string hardware = android::base::GetProperty("ro.hardware", ""); ueventd_parse_config_file(android::base::StringPrintf("/ueventd.%s.rc", hardware.c_str()).c_str()); device_init(); diff --git a/init/util.cpp b/init/util.cpp index 0ba98003f..8a1993987 100644 --- a/init/util.cpp +++ b/init/util.cpp @@ -38,6 +38,7 @@ #include #include +#include #include #include #include @@ -48,7 +49,6 @@ #include "init.h" #include "log.h" -#include "property_service.h" #include "reboot.h" #include "util.h" @@ -395,7 +395,7 @@ bool expand_props(const std::string& src, std::string* dst) { return false; } - std::string prop_val = property_get(prop_name.c_str()); + std::string prop_val = android::base::GetProperty(prop_name, ""); if (prop_val.empty()) { if (def_val.empty()) { LOG(ERROR) << "property '" << prop_name << "' doesn't exist while expanding '" << src << "'"; diff --git a/rootdir/init.rc b/rootdir/init.rc index 77b173d07..28406c80b 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -599,7 +599,7 @@ on boot on nonencrypted # A/B update verifier that marks a successful boot. - exec - root cache -- /system/bin/update_verifier nonencrypted + exec_start update_verifier_nonencrypted class_start main class_start late_start @@ -622,12 +622,12 @@ on property:vold.decrypt=trigger_post_fs_data on property:vold.decrypt=trigger_restart_min_framework # A/B update verifier that marks a successful boot. - exec - root cache -- /system/bin/update_verifier trigger_restart_min_framework + exec_start update_verifier class_start main on property:vold.decrypt=trigger_restart_framework # A/B update verifier that marks a successful boot. - exec - root cache -- /system/bin/update_verifier trigger_restart_framework + exec_start update_verifier class_start main class_start late_start