init: add wait_for_prop builtin command
There are many use cases from vendors to exec service in background and then use a shell scriprt to wait for the command done. This CL is to add a wait_for_prop command to suppor those use cases. Bug: 34746108 Test: on marlin Change-Id: Ia81290b0928f9d375710d2daa546714f0cd65b72
This commit is contained in:
parent
afe25958b6
commit
132ac31b47
4 changed files with 62 additions and 2 deletions
|
@ -298,7 +298,8 @@ Commands
|
|||
> Fork and execute command with the given arguments. The command starts
|
||||
after "--" so that an optional security context, user, and supplementary
|
||||
groups can be provided. No other commands will be run until this one
|
||||
finishes. _seclabel_ can be a - to denote default.
|
||||
finishes. _seclabel_ can be a - to denote default. Properties are expanded
|
||||
within _argument_.
|
||||
|
||||
`export <name> <value>`
|
||||
> Set the environment variable _name_ equal to _value_ in the
|
||||
|
@ -412,6 +413,11 @@ Commands
|
|||
or the timeout has been reached. If timeout is not specified it
|
||||
currently defaults to five seconds.
|
||||
|
||||
`wait_for_prop <name> <value>`
|
||||
> Wait for system property _name_ to be _value_. Properties are expanded
|
||||
within _value_. If property _name_ is already set to _value_, continue
|
||||
immediately.
|
||||
|
||||
`write <path> <content>`
|
||||
> Open the file at _path_ and write a string to it with write(2).
|
||||
If the file does not exist, it will be created. If it does exist,
|
||||
|
|
|
@ -1003,6 +1003,29 @@ static int do_wait(const std::vector<std::string>& args) {
|
|||
return -1;
|
||||
}
|
||||
|
||||
static int do_wait_for_prop(const std::vector<std::string>& args) {
|
||||
const char* name = args[1].c_str();
|
||||
const char* value = args[2].c_str();
|
||||
size_t value_len = strlen(value);
|
||||
|
||||
if (!is_legal_property_name(name)) {
|
||||
LOG(ERROR) << "do_wait_for_prop(\"" << name << "\", \"" << value
|
||||
<< "\") failed: bad name";
|
||||
return -1;
|
||||
}
|
||||
if (value_len >= PROP_VALUE_MAX) {
|
||||
LOG(ERROR) << "do_wait_for_prop(\"" << name << "\", \"" << value
|
||||
<< "\") failed: value too long";
|
||||
return -1;
|
||||
}
|
||||
if (!wait_property(name, value)) {
|
||||
LOG(ERROR) << "do_wait_for_prop(\"" << name << "\", \"" << value
|
||||
<< "\") failed: init already in waiting";
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback to make a directory from the ext4 code
|
||||
*/
|
||||
|
@ -1074,6 +1097,7 @@ BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const {
|
|||
{"verity_load_state", {0, 0, do_verity_load_state}},
|
||||
{"verity_update_state", {0, 0, do_verity_update_state}},
|
||||
{"wait", {1, 2, do_wait}},
|
||||
{"wait_for_prop", {2, 2, do_wait_for_prop}},
|
||||
{"write", {2, 2, do_write}},
|
||||
};
|
||||
return builtin_functions;
|
||||
|
|
|
@ -87,6 +87,10 @@ bool waiting_for_exec = false;
|
|||
|
||||
static int epoll_fd = -1;
|
||||
|
||||
static std::unique_ptr<Timer> waiting_for_prop(nullptr);
|
||||
static std::string wait_prop_name;
|
||||
static std::string wait_prop_value;
|
||||
|
||||
void register_epoll_handler(int fd, void (*fn)()) {
|
||||
epoll_event ev;
|
||||
ev.events = EPOLLIN;
|
||||
|
@ -128,10 +132,34 @@ int add_environment(const char *key, const char *val)
|
|||
return -1;
|
||||
}
|
||||
|
||||
bool wait_property(const char *name, const char *value)
|
||||
{
|
||||
if (waiting_for_prop) {
|
||||
return false;
|
||||
}
|
||||
if (property_get(name) != value) {
|
||||
// Current property value is not equal to expected value
|
||||
wait_prop_name = name;
|
||||
wait_prop_value = value;
|
||||
waiting_for_prop.reset(new Timer());
|
||||
} else {
|
||||
LOG(INFO) << "wait_property(\"" << name << "\", \"" << value << "\"): already set";
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void property_changed(const char *name, const char *value)
|
||||
{
|
||||
if (property_triggers_enabled)
|
||||
ActionManager::GetInstance().QueuePropertyTrigger(name, value);
|
||||
if (waiting_for_prop) {
|
||||
if (wait_prop_name == name && wait_prop_value == value) {
|
||||
wait_prop_name.clear();
|
||||
wait_prop_value.clear();
|
||||
LOG(INFO) << "Wait for property took " << *waiting_for_prop;
|
||||
waiting_for_prop.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void restart_processes()
|
||||
|
@ -876,7 +904,7 @@ int main(int argc, char** argv) {
|
|||
am.QueueBuiltinAction(queue_property_triggers_action, "queue_property_triggers");
|
||||
|
||||
while (true) {
|
||||
if (!waiting_for_exec) {
|
||||
if (!(waiting_for_exec || waiting_for_prop)) {
|
||||
am.ExecuteOneCommand();
|
||||
restart_processes();
|
||||
}
|
||||
|
|
|
@ -36,4 +36,6 @@ void register_epoll_handler(int fd, void (*fn)());
|
|||
|
||||
int add_environment(const char* key, const char* val);
|
||||
|
||||
bool wait_property(const char *name, const char *value);
|
||||
|
||||
#endif /* _INIT_INIT_H */
|
||||
|
|
Loading…
Reference in a new issue