init: Create classes for Action and Command
This creates the concept of 'event_trigger' vs 'property_trigger'
Previously these were merged into one, such that 'on property:a=b &&
property:b=c' is triggered when properties a=b and b=c as expected,
however combinations such as 'on early-boot && boot' would trigger
during both early-boot and boot. Similarly, 'on early-boot &&
property:a=b' would trigger on both early-boot and again when property
a equals b.
The event trigger distinction ensures that the first example fails to
parse and the second example only triggers on early-boot if
property a equals b.
This coalesces Actions with the same triggers into a single Action object
Change-Id: I8f661d96e8a2d40236f252301bfe10979d663ea6
diff --git a/init/init.cpp b/init/init.cpp
index 4be16ea..66143bf 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -53,6 +53,7 @@
#include <memory>
+#include "action.h"
#include "devices.h"
#include "init.h"
#include "log.h"
@@ -72,9 +73,6 @@
static char qemu[32];
-static struct action *cur_action = NULL;
-static struct command *cur_command = NULL;
-
static int have_console;
static std::string console_name = "/dev/console";
static time_t process_needs_restart;
@@ -453,7 +451,7 @@
void property_changed(const char *name, const char *value)
{
if (property_triggers_enabled)
- queue_property_triggers(name, value);
+ ActionManager::GetInstance().QueuePropertyTrigger(name, value);
}
static void restart_service_if_needed(struct service *svc)
@@ -542,114 +540,6 @@
}
}
-static struct command *get_first_command(struct action *act)
-{
- struct listnode *node;
- node = list_head(&act->commands);
- if (!node || list_empty(&act->commands))
- return NULL;
-
- return node_to_item(node, struct command, clist);
-}
-
-static struct command *get_next_command(struct action *act, struct command *cmd)
-{
- struct listnode *node;
- node = cmd->clist.next;
- if (!node)
- return NULL;
- if (node == &act->commands)
- return NULL;
-
- return node_to_item(node, struct command, clist);
-}
-
-static int is_last_command(struct action *act, struct command *cmd)
-{
- return (list_tail(&act->commands) == &cmd->clist);
-}
-
-
-std::string build_triggers_string(struct action *cur_action) {
- std::string result;
- struct listnode *node;
- struct trigger *cur_trigger;
-
- list_for_each(node, &cur_action->triggers) {
- cur_trigger = node_to_item(node, struct trigger, nlist);
- if (node != cur_action->triggers.next) {
- result.push_back(' ');
- }
- result += cur_trigger->name;
- }
- return result;
-}
-
-bool expand_command_arguments(int nargs, char** args, std::vector<std::string>* expanded_args) {
- std::vector<std::string>& strs = *expanded_args;
- strs.resize(nargs);
- strs[0] = args[0];
- for (int i = 1; i < nargs; ++i) {
- if (expand_props(args[i], &strs[i]) == -1) {
- ERROR("%s: cannot expand '%s'\n", args[0], args[i]);
- return false;
- }
- }
- return true;
-}
-
-void execute_one_command() {
- Timer t;
-
- if (!cur_action || !cur_command || is_last_command(cur_action, cur_command)) {
- cur_action = action_remove_queue_head();
- cur_command = NULL;
- if (!cur_action) {
- return;
- }
-
- std::string trigger_name = build_triggers_string(cur_action);
- INFO("processing action %p (%s)\n", cur_action, trigger_name.c_str());
- cur_command = get_first_command(cur_action);
- } else {
- cur_command = get_next_command(cur_action, cur_command);
- }
-
- if (!cur_command) {
- return;
- }
- int result = 0;
- std::vector<std::string> arg_strs;
- if (!expand_command_arguments(cur_command->nargs, cur_command->args, &arg_strs)) {
- result = -EINVAL;
- }
- if (result == 0) {
- std::vector<char*> args;
- for (auto& s : arg_strs) {
- args.push_back(&s[0]);
- }
- result = cur_command->func(args.size(), &args[0]);
- }
- if (klog_get_level() >= KLOG_INFO_LEVEL) {
- std::string cmd_str;
- for (int i = 0; i < cur_command->nargs; ++i) {
- if (i > 0) {
- cmd_str.push_back(' ');
- }
- cmd_str += cur_command->args[i];
- }
- std::string trigger_name = build_triggers_string(cur_action);
-
- std::string source;
- if (cur_command->filename) {
- source = android::base::StringPrintf(" (%s:%d)", cur_command->filename, cur_command->line);
- }
-
- INFO("Command '%s' action=%s%s returned %d took %.2fs\n",
- cmd_str.c_str(), trigger_name.c_str(), source.c_str(), result, t.duration());
- }
-}
-
static int wait_for_coldboot_done_action(int nargs, char **args) {
Timer t;
@@ -865,7 +755,7 @@
static int queue_property_triggers_action(int nargs, char **args)
{
- queue_all_property_triggers();
+ ActionManager::GetInstance().QueueAllPropertyTriggers();
/* enable property triggers */
property_triggers_enabled = 1;
return 0;
@@ -1059,36 +949,38 @@
init_parse_config("/init.rc");
- action_for_each_trigger("early-init", action_add_queue_tail);
+ ActionManager& am = ActionManager::GetInstance();
+
+ am.QueueEventTrigger("early-init");
// Queue an action that waits for coldboot done so we know ueventd has set up all of /dev...
- queue_builtin_action(wait_for_coldboot_done_action, "wait_for_coldboot_done");
+ am.QueueBuiltinAction(wait_for_coldboot_done_action, "wait_for_coldboot_done");
// ... so that we can start queuing up actions that require stuff from /dev.
- queue_builtin_action(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
- queue_builtin_action(keychord_init_action, "keychord_init");
- queue_builtin_action(console_init_action, "console_init");
+ am.QueueBuiltinAction(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
+ am.QueueBuiltinAction(keychord_init_action, "keychord_init");
+ am.QueueBuiltinAction(console_init_action, "console_init");
// Trigger all the boot actions to get us started.
- action_for_each_trigger("init", action_add_queue_tail);
+ am.QueueEventTrigger("init");
// Repeat mix_hwrng_into_linux_rng in case /dev/hw_random or /dev/random
// wasn't ready immediately after wait_for_coldboot_done
- queue_builtin_action(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
+ 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");
if (bootmode == "charger") {
- action_for_each_trigger("charger", action_add_queue_tail);
+ am.QueueEventTrigger("charger");
} else {
- action_for_each_trigger("late-init", action_add_queue_tail);
+ am.QueueEventTrigger("late-init");
}
// Run all property triggers based on current state of the properties.
- queue_builtin_action(queue_property_triggers_action, "queue_property_triggers");
+ am.QueueBuiltinAction(queue_property_triggers_action, "queue_property_triggers");
while (true) {
if (!waiting_for_exec) {
- execute_one_command();
+ am.ExecuteOneCommand();
restart_processes();
}
@@ -1099,7 +991,7 @@
timeout = 0;
}
- if (!action_queue_empty() || cur_action) {
+ if (am.HasMoreCommands()) {
timeout = 0;
}