Move all Action parsing into ActionParser

Bug: 36970783
Test: Build
Change-Id: Iea2d97fb45c3e88bc83fb72d6fa67049be42cfa9
This commit is contained in:
Tom Cherry 2018-02-13 16:24:51 -08:00
parent 7fd3bc27ec
commit 9cbf57048c
5 changed files with 107 additions and 100 deletions

View file

@ -21,11 +21,9 @@
#include <android-base/properties.h>
#include <android-base/strings.h>
#include "stable_properties.h"
#include "util.h"
using android::base::Join;
using android::base::StartsWith;
namespace android {
namespace init {
@ -70,8 +68,15 @@ std::string Command::BuildCommandString() const {
return Join(args_, ' ');
}
Action::Action(bool oneshot, Subcontext* subcontext, const std::string& filename, int line)
: oneshot_(oneshot), subcontext_(subcontext), filename_(filename), line_(line) {}
Action::Action(bool oneshot, Subcontext* subcontext, const std::string& filename, int line,
const std::string& event_trigger,
const std::map<std::string, std::string>& property_triggers)
: property_triggers_(property_triggers),
event_trigger_(event_trigger),
oneshot_(oneshot),
subcontext_(subcontext),
filename_(filename),
line_(line) {}
const KeywordFunctionMap* Action::function_map_ = nullptr;
@ -135,85 +140,6 @@ void Action::ExecuteCommand(const Command& command) const {
}
}
static bool IsActionableProperty(Subcontext* subcontext, const std::string& prop_name) {
static bool enabled =
android::base::GetBoolProperty("ro.actionable_compatible_property.enabled", false);
if (subcontext == nullptr || !enabled) {
return true;
}
if (kExportedActionableProperties.count(prop_name) == 1) {
return true;
}
for (const auto& prefix : kPartnerPrefixes) {
if (android::base::StartsWith(prop_name, prefix)) {
return true;
}
}
return false;
}
Result<Success> Action::ParsePropertyTrigger(const std::string& trigger) {
const static std::string prop_str("property:");
std::string prop_name(trigger.substr(prop_str.length()));
size_t equal_pos = prop_name.find('=');
if (equal_pos == std::string::npos) {
return Error() << "property trigger found without matching '='";
}
std::string prop_value(prop_name.substr(equal_pos + 1));
prop_name.erase(equal_pos);
if (!IsActionableProperty(subcontext_, prop_name)) {
return Error() << "unexported property tigger found: " << prop_name;
}
if (auto [it, inserted] = property_triggers_.emplace(prop_name, prop_value); !inserted) {
return Error() << "multiple property triggers found for same property";
}
return Success();
}
Result<Success> Action::InitTriggers(const std::vector<std::string>& args) {
const static std::string prop_str("property:");
for (std::size_t i = 0; i < args.size(); ++i) {
if (args[i].empty()) {
return Error() << "empty trigger is not valid";
}
if (i % 2) {
if (args[i] != "&&") {
return Error() << "&& is the only symbol allowed to concatenate actions";
} else {
continue;
}
}
if (!args[i].compare(0, prop_str.length(), prop_str)) {
if (auto result = ParsePropertyTrigger(args[i]); !result) {
return result;
}
} else {
if (!event_trigger_.empty()) {
return Error() << "multiple event triggers are not allowed";
}
event_trigger_ = args[i];
}
}
return Success();
}
Result<Success> Action::InitSingleTrigger(const std::string& trigger) {
std::vector<std::string> name_vector{trigger};
if (auto result = InitTriggers(name_vector); !result) {
return Error() << "InitTriggers() failed: " << result.error();
}
return Success();
}
// This function checks that all property triggers are satisfied, that is
// for each (name, value) in property_triggers_, check that the current
// value of the property 'name' == value.

View file

@ -57,12 +57,12 @@ using BuiltinAction = class Action*;
class Action {
public:
Action(bool oneshot, Subcontext* subcontext, const std::string& filename, int line);
Action(bool oneshot, Subcontext* subcontext, const std::string& filename, int line,
const std::string& event_trigger,
const std::map<std::string, std::string>& property_triggers);
Result<Success> AddCommand(const std::vector<std::string>& args, int line);
void AddCommand(BuiltinFunction f, const std::vector<std::string>& args, int line);
Result<Success> InitTriggers(const std::vector<std::string>& args);
Result<Success> InitSingleTrigger(const std::string& trigger);
std::size_t NumCommands() const;
void ExecuteOneCommand(std::size_t command) const;
void ExecuteAllCommands() const;
@ -83,7 +83,6 @@ class Action {
void ExecuteCommand(const Command& command) const;
bool CheckPropertyTriggers(const std::string& name = "",
const std::string& value = "") const;
Result<Success> ParsePropertyTrigger(const std::string& trigger);
std::map<std::string, std::string> property_triggers_;
std::string event_trigger_;

View file

@ -45,14 +45,10 @@ void ActionManager::QueueAllPropertyActions() {
}
void ActionManager::QueueBuiltinAction(BuiltinFunction func, const std::string& name) {
auto action = std::make_unique<Action>(true, nullptr, "<Builtin Action>", 0);
auto action = std::make_unique<Action>(true, nullptr, "<Builtin Action>", 0, name,
std::map<std::string, std::string>{});
std::vector<std::string> name_vector{name};
if (auto result = action->InitSingleTrigger(name); !result) {
LOG(ERROR) << "Cannot queue BuiltinAction for " << name << ": " << result.error();
return;
}
action->AddCommand(func, name_vector, 0);
event_queue_.emplace(action.get());

View file

@ -16,13 +16,95 @@
#include "action_parser.h"
#include <android-base/properties.h>
#include <android-base/strings.h>
#include "stable_properties.h"
using android::base::GetBoolProperty;
using android::base::StartsWith;
namespace android {
namespace init {
namespace {
bool IsActionableProperty(Subcontext* subcontext, const std::string& prop_name) {
static bool enabled = GetBoolProperty("ro.actionable_compatible_property.enabled", false);
if (subcontext == nullptr || !enabled) {
return true;
}
if (kExportedActionableProperties.count(prop_name) == 1) {
return true;
}
for (const auto& prefix : kPartnerPrefixes) {
if (android::base::StartsWith(prop_name, prefix)) {
return true;
}
}
return false;
}
Result<Success> ParsePropertyTrigger(const std::string& trigger, Subcontext* subcontext,
std::map<std::string, std::string>* property_triggers) {
const static std::string prop_str("property:");
std::string prop_name(trigger.substr(prop_str.length()));
size_t equal_pos = prop_name.find('=');
if (equal_pos == std::string::npos) {
return Error() << "property trigger found without matching '='";
}
std::string prop_value(prop_name.substr(equal_pos + 1));
prop_name.erase(equal_pos);
if (!IsActionableProperty(subcontext, prop_name)) {
return Error() << "unexported property tigger found: " << prop_name;
}
if (auto [it, inserted] = property_triggers->emplace(prop_name, prop_value); !inserted) {
return Error() << "multiple property triggers found for same property";
}
return Success();
}
Result<Success> ParseTriggers(const std::vector<std::string>& args, Subcontext* subcontext,
std::string* event_trigger,
std::map<std::string, std::string>* property_triggers) {
const static std::string prop_str("property:");
for (std::size_t i = 0; i < args.size(); ++i) {
if (args[i].empty()) {
return Error() << "empty trigger is not valid";
}
if (i % 2) {
if (args[i] != "&&") {
return Error() << "&& is the only symbol allowed to concatenate actions";
} else {
continue;
}
}
if (!args[i].compare(0, prop_str.length(), prop_str)) {
if (auto result = ParsePropertyTrigger(args[i], subcontext, property_triggers);
!result) {
return result;
}
} else {
if (!event_trigger->empty()) {
return Error() << "multiple event triggers are not allowed";
}
*event_trigger = args[i];
}
}
return Success();
}
} // namespace
Result<Success> ActionParser::ParseSection(std::vector<std::string>&& args,
const std::string& filename, int line) {
std::vector<std::string> triggers(args.begin() + 1, args.end());
@ -40,12 +122,17 @@ Result<Success> ActionParser::ParseSection(std::vector<std::string>&& args,
}
}
auto action = std::make_unique<Action>(false, action_subcontext, filename, line);
std::string event_trigger;
std::map<std::string, std::string> property_triggers;
if (auto result = action->InitTriggers(triggers); !result) {
return Error() << "InitTriggers() failed: " << result.error();
if (auto result = ParseTriggers(triggers, action_subcontext, &event_trigger, &property_triggers);
!result) {
return Error() << "ParseTriggers() failed: " << result.error();
}
auto action = std::make_unique<Action>(false, action_subcontext, filename, line, event_trigger,
property_triggers);
action_ = std::move(action);
return Success();
}

View file

@ -189,7 +189,8 @@ Service::Service(const std::string& name, unsigned flags, uid_t uid, gid_t gid,
capabilities_(capabilities),
namespace_flags_(namespace_flags),
seclabel_(seclabel),
onrestart_(false, subcontext_for_restart_commands, "<Service '" + name + "' onrestart>", 0),
onrestart_(false, subcontext_for_restart_commands, "<Service '" + name + "' onrestart>", 0,
"onrestart", {}),
keychord_id_(0),
ioprio_class_(IoSchedClass_NONE),
ioprio_pri_(0),
@ -199,9 +200,7 @@ Service::Service(const std::string& name, unsigned flags, uid_t uid, gid_t gid,
soft_limit_in_bytes_(-1),
limit_in_bytes_(-1),
start_order_(0),
args_(args) {
onrestart_.InitSingleTrigger("onrestart");
}
args_(args) {}
void Service::NotifyStateChange(const std::string& new_state) const {
if ((flags_ & SVC_TEMPORARY) != 0) {