Merge changes from topic 'exec-start-update-verifier'

* changes:
  init.rc: launch update_verifier with exec_start
  init: add exec_start command
This commit is contained in:
Treehugger Robot 2017-03-29 18:39:30 +00:00 committed by Gerrit Code Review
commit 8772b3686e
7 changed files with 88 additions and 52 deletions

View file

@ -311,6 +311,12 @@ Commands
groups can be provided. No other commands will be run until this one groups can be provided. No other commands will be run until this one
finishes. _seclabel_ can be a - to denote default. Properties are expanded finishes. _seclabel_ can be a - to denote default. Properties are expanded
within _argument_. within _argument_.
Init halts executing commands until the forked process exits.
`exec_start <service>`
> 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 <name> <value>` `export <name> <value>`
> Set the environment variable _name_ equal to _value_ in the > Set the environment variable _name_ equal to _value_ in the

View file

@ -167,19 +167,11 @@ static int do_enable(const std::vector<std::string>& args) {
} }
static int do_exec(const std::vector<std::string>& args) { static int do_exec(const std::vector<std::string>& args) {
Service* svc = ServiceManager::GetInstance().MakeExecOneshotService(args); return ServiceManager::GetInstance().Exec(args) ? 0 : -1;
if (!svc) { }
return -1;
} static int do_exec_start(const std::vector<std::string>& args) {
if (!start_waiting_for_exec()) { return ServiceManager::GetInstance().ExecStart(args[1]) ? 0 : -1;
return -1;
}
if (!svc->Start()) {
stop_waiting_for_exec();
ServiceManager::GetInstance().RemoveService(*svc);
return -1;
}
return 0;
} }
static int do_export(const std::vector<std::string>& args) { static int do_export(const std::vector<std::string>& args) {
@ -897,6 +889,7 @@ static int do_init_user0(const std::vector<std::string>& args) {
BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const { BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const {
constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max(); constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max();
// clang-format off
static const Map builtin_functions = { static const Map builtin_functions = {
{"bootchart", {1, 1, do_bootchart}}, {"bootchart", {1, 1, do_bootchart}},
{"chmod", {2, 2, do_chmod}}, {"chmod", {2, 2, do_chmod}},
@ -909,6 +902,7 @@ BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const {
{"domainname", {1, 1, do_domainname}}, {"domainname", {1, 1, do_domainname}},
{"enable", {1, 1, do_enable}}, {"enable", {1, 1, do_enable}},
{"exec", {1, kMax, do_exec}}, {"exec", {1, kMax, do_exec}},
{"exec_start", {1, 1, do_exec_start}},
{"export", {2, 2, do_export}}, {"export", {2, 2, do_export}},
{"hostname", {1, 1, do_hostname}}, {"hostname", {1, 1, do_hostname}},
{"ifup", {1, 1, do_ifup}}, {"ifup", {1, 1, do_ifup}},
@ -942,5 +936,6 @@ BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const {
{"wait_for_prop", {2, 2, do_wait_for_prop}}, {"wait_for_prop", {2, 2, do_wait_for_prop}},
{"write", {2, 2, do_write}}, {"write", {2, 2, do_write}},
}; };
// clang-format on
return builtin_functions; return builtin_functions;
} }

View file

@ -84,8 +84,6 @@ static time_t process_needs_restart_at;
const char *ENV[32]; const char *ENV[32];
static std::unique_ptr<Timer> waiting_for_exec(nullptr);
static int epoll_fd = -1; static int epoll_fd = -1;
static std::unique_ptr<Timer> waiting_for_prop(nullptr); static std::unique_ptr<Timer> waiting_for_prop(nullptr);
@ -133,23 +131,6 @@ int add_environment(const char *key, const char *val)
return -1; 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) bool start_waiting_for_property(const char *name, const char *value)
{ {
if (waiting_for_prop) { if (waiting_for_prop) {
@ -1323,10 +1304,10 @@ int main(int argc, char** argv) {
// By default, sleep until something happens. // By default, sleep until something happens.
int epoll_timeout_ms = -1; int epoll_timeout_ms = -1;
if (!(waiting_for_exec || waiting_for_prop)) { if (!(waiting_for_prop || ServiceManager::GetInstance().IsWaitingForExec())) {
am.ExecuteOneCommand(); am.ExecuteOneCommand();
} }
if (!(waiting_for_exec || waiting_for_prop)) { if (!(waiting_for_prop || ServiceManager::GetInstance().IsWaitingForExec())) {
restart_processes(); restart_processes();
// If there's a process that needs restarting, wake up in time for that. // If there's a process that needs restarting, wake up in time for that.

View file

@ -32,10 +32,6 @@ void register_epoll_handler(int fd, void (*fn)());
int add_environment(const char* key, const char* val); 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); bool start_waiting_for_property(const char *name, const char *value);
#endif /* _INIT_INIT_H */ #endif /* _INIT_INIT_H */

View file

@ -192,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 { void Service::NotifyStateChange(const std::string& new_state) const {
if ((flags_ & SVC_EXEC) != 0) { if ((flags_ & SVC_TEMPORARY) != 0) {
// 'exec' commands don't have properties tracking their state. // Services created by 'exec' are temporary and don't have properties tracking their state.
return; return;
} }
@ -260,7 +260,7 @@ void Service::SetProcessAttributes() {
} }
} }
bool Service::Reap() { void Service::Reap() {
if (!(flags_ & SVC_ONESHOT) || (flags_ & SVC_RESTART)) { if (!(flags_ & SVC_ONESHOT) || (flags_ & SVC_RESTART)) {
KillProcessGroup(SIGKILL); KillProcessGroup(SIGKILL);
} }
@ -271,7 +271,10 @@ bool Service::Reap() {
if (flags_ & SVC_EXEC) { if (flags_ & SVC_EXEC) {
LOG(INFO) << "SVC_EXEC pid " << pid_ << " finished..."; LOG(INFO) << "SVC_EXEC pid " << pid_ << " finished...";
return true; }
if (flags_ & SVC_TEMPORARY) {
return;
} }
pid_ = 0; pid_ = 0;
@ -286,7 +289,7 @@ bool Service::Reap() {
// Disabled and reset processes do not get restarted automatically. // Disabled and reset processes do not get restarted automatically.
if (flags_ & (SVC_DISABLED | SVC_RESET)) { if (flags_ & (SVC_DISABLED | SVC_RESET)) {
NotifyStateChange("stopped"); NotifyStateChange("stopped");
return false; return;
} }
// If we crash > 4 times in 4 minutes, reboot into recovery. // If we crash > 4 times in 4 minutes, reboot into recovery.
@ -310,7 +313,7 @@ bool Service::Reap() {
onrestart_.ExecuteAllCommands(); onrestart_.ExecuteAllCommands();
NotifyStateChange("restarting"); NotifyStateChange("restarting");
return false; return;
} }
void Service::DumpState() const { void Service::DumpState() const {
@ -578,6 +581,18 @@ bool Service::ParseLine(const std::vector<std::string>& args, std::string* err)
return (this->*parser)(args, err); return (this->*parser)(args, err);
} }
bool Service::ExecStart(std::unique_ptr<Timer>* exec_waiter) {
flags_ |= SVC_EXEC | SVC_ONESHOT;
exec_waiter->reset(new Timer);
if (!Start()) {
exec_waiter->reset();
return false;
}
return true;
}
bool Service::Start() { bool Service::Start() {
// Starting a service removes it from the disabled or reset state and // 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. // immediately takes it out of the restarting state if it was in there.
@ -864,6 +879,35 @@ void ServiceManager::AddService(std::unique_ptr<Service> service) {
services_.emplace_back(std::move(service)); services_.emplace_back(std::move(service));
} }
bool ServiceManager::Exec(const std::vector<std::string>& 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<std::string>& args) { Service* ServiceManager::MakeExecOneshotService(const std::vector<std::string>& args) {
// Parse the arguments: exec [SECLABEL [UID [GID]*] --] COMMAND ARGS... // Parse the arguments: exec [SECLABEL [UID [GID]*] --] COMMAND ARGS...
// SECLABEL can be a - to denote default // SECLABEL can be a - to denote default
@ -887,7 +931,7 @@ Service* ServiceManager::MakeExecOneshotService(const std::vector<std::string>&
exec_count_++; exec_count_++;
std::string name = StringPrintf("exec %d (%s)", exec_count_, str_args[0].c_str()); 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; CapSet no_capabilities;
unsigned namespace_flags = 0; unsigned namespace_flags = 0;
@ -1027,8 +1071,13 @@ bool ServiceManager::ReapOneProcess() {
return true; return true;
} }
if (svc->Reap()) { svc->Reap();
stop_waiting_for_exec();
if (svc->flags() & SVC_EXEC) {
LOG(INFO) << "Wait for exec took " << *exec_waiter_;
exec_waiter_.reset();
}
if (svc->flags() & SVC_TEMPORARY) {
RemoveService(*svc); RemoveService(*svc);
} }

View file

@ -44,10 +44,13 @@
#define SVC_RC_DISABLED 0x080 // Remember if the disabled flag was set in the rc script. #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_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_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 #define SVC_SHUTDOWN_CRITICAL 0x800 // This service is critical for shutdown and
// should not be killed during shutdown // 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 #define NR_SVC_SUPP_GIDS 12 // twelve supplementary groups
@ -72,6 +75,7 @@ class Service {
bool IsRunning() { return (flags_ & SVC_RUNNING) != 0; } bool IsRunning() { return (flags_ & SVC_RUNNING) != 0; }
bool ParseLine(const std::vector<std::string>& args, std::string* err); bool ParseLine(const std::vector<std::string>& args, std::string* err);
bool ExecStart(std::unique_ptr<Timer>* exec_waiter);
bool Start(); bool Start();
bool StartIfNotDisabled(); bool StartIfNotDisabled();
bool Enable(); bool Enable();
@ -80,7 +84,7 @@ class Service {
void Terminate(); void Terminate();
void Restart(); void Restart();
void RestartIfNeeded(time_t* process_needs_restart_at); void RestartIfNeeded(time_t* process_needs_restart_at);
bool Reap(); void Reap();
void DumpState() const; void DumpState() const;
void SetShutdownCritical() { flags_ |= SVC_SHUTDOWN_CRITICAL; } void SetShutdownCritical() { flags_ |= SVC_SHUTDOWN_CRITICAL; }
bool IsShutdownCritical() const { return (flags_ & SVC_SHUTDOWN_CRITICAL) != 0; } bool IsShutdownCritical() const { return (flags_ & SVC_SHUTDOWN_CRITICAL) != 0; }
@ -178,6 +182,9 @@ public:
void AddService(std::unique_ptr<Service> service); void AddService(std::unique_ptr<Service> service);
Service* MakeExecOneshotService(const std::vector<std::string>& args); Service* MakeExecOneshotService(const std::vector<std::string>& args);
bool Exec(const std::vector<std::string>& args);
bool ExecStart(const std::string& name);
bool IsWaitingForExec() const;
Service* FindServiceByName(const std::string& name) const; Service* FindServiceByName(const std::string& name) const;
Service* FindServiceByPid(pid_t pid) const; Service* FindServiceByPid(pid_t pid) const;
Service* FindServiceByKeychord(int keychord_id) const; Service* FindServiceByKeychord(int keychord_id) const;
@ -198,6 +205,8 @@ private:
bool ReapOneProcess(); bool ReapOneProcess();
static int exec_count_; // Every service needs a unique name. static int exec_count_; // Every service needs a unique name.
std::unique_ptr<Timer> exec_waiter_;
std::vector<std::unique_ptr<Service>> services_; std::vector<std::unique_ptr<Service>> services_;
}; };

View file

@ -598,7 +598,7 @@ on boot
on nonencrypted on nonencrypted
# A/B update verifier that marks a successful boot. # 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 main
class_start late_start class_start late_start
@ -621,12 +621,12 @@ on property:vold.decrypt=trigger_post_fs_data
on property:vold.decrypt=trigger_restart_min_framework on property:vold.decrypt=trigger_restart_min_framework
# A/B update verifier that marks a successful boot. # 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 class_start main
on property:vold.decrypt=trigger_restart_framework on property:vold.decrypt=trigger_restart_framework
# A/B update verifier that marks a successful boot. # 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 main
class_start late_start class_start late_start