action.cpp revision ccf23537eeacfa47e5f18dd3b75089886d177c1b
1fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry/* 2fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry * Copyright (C) 2015 The Android Open Source Project 3fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry * 4fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry * Licensed under the Apache License, Version 2.0 (the "License"); 5fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry * you may not use this file except in compliance with the License. 6fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry * You may obtain a copy of the License at 7fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry * 8fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry * http://www.apache.org/licenses/LICENSE-2.0 9fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry * 10fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry * Unless required by applicable law or agreed to in writing, software 11fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry * distributed under the License is distributed on an "AS IS" BASIS, 12fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry * See the License for the specific language governing permissions and 14fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry * limitations under the License. 15fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry */ 16fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 17fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry#include "action.h" 18fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 19fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry#include <errno.h> 20fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 21ccf23537eeacfa47e5f18dd3b75089886d177c1bTom Cherry#include <android-base/properties.h> 224f71319df011d796a60a43fc1bc68e16fbf7d321Elliott Hughes#include <android-base/stringprintf.h> 23ccf23537eeacfa47e5f18dd3b75089886d177c1bTom Cherry#include <android-base/strings.h> 24fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 25b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry#include "builtins.h" 26fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry#include "error.h" 27fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry#include "init_parser.h" 28fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry#include "log.h" 29fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry#include "util.h" 30fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 31b7349902a945903f9e36a569051f5131beb0bc24Tom Cherryusing android::base::Join; 32b7349902a945903f9e36a569051f5131beb0bc24Tom Cherryusing android::base::StringPrintf; 33fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 34b7349902a945903f9e36a569051f5131beb0bc24Tom CherryCommand::Command(BuiltinFunction f, const std::vector<std::string>& args, 35b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry const std::string& filename, int line) 36b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry : func_(f), args_(args), filename_(filename), line_(line) { 37fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry} 38fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 39b7349902a945903f9e36a569051f5131beb0bc24Tom Cherryint Command::InvokeFunc() const { 4096f67316a22bc9236aed70b198e91a5406389e5bTom Cherry std::vector<std::string> expanded_args; 4196f67316a22bc9236aed70b198e91a5406389e5bTom Cherry expanded_args.resize(args_.size()); 4296f67316a22bc9236aed70b198e91a5406389e5bTom Cherry expanded_args[0] = args_[0]; 43fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry for (std::size_t i = 1; i < args_.size(); ++i) { 44b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry if (!expand_props(args_[i], &expanded_args[i])) { 45f86b5a6b90619e02d1d034ef7b0adc3b439f4abbElliott Hughes LOG(ERROR) << args_[0] << ": cannot expand '" << args_[i] << "'"; 46fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry return -EINVAL; 47fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry } 48fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry } 49fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 5096f67316a22bc9236aed70b198e91a5406389e5bTom Cherry return func_(expanded_args); 51fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry} 52fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 53b7349902a945903f9e36a569051f5131beb0bc24Tom Cherrystd::string Command::BuildCommandString() const { 54b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry return Join(args_, ' '); 55fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry} 56fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 57b7349902a945903f9e36a569051f5131beb0bc24Tom Cherrystd::string Command::BuildSourceString() const { 58fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry if (!filename_.empty()) { 59b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry return StringPrintf(" (%s:%d)", filename_.c_str(), line_); 60fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry } else { 61fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry return std::string(); 62fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry } 63fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry} 64fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 65b7349902a945903f9e36a569051f5131beb0bc24Tom CherryAction::Action(bool oneshot) : oneshot_(oneshot) { 66fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry} 67fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 68b7349902a945903f9e36a569051f5131beb0bc24Tom Cherryconst KeywordMap<BuiltinFunction>* Action::function_map_ = nullptr; 69b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry 70b7349902a945903f9e36a569051f5131beb0bc24Tom Cherrybool Action::AddCommand(const std::vector<std::string>& args, 71b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry const std::string& filename, int line, std::string* err) { 72b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry if (!function_map_) { 73b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry *err = "no function map available"; 74b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry return false; 75b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry } 76b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry 77b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry if (args.empty()) { 78b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry *err = "command needed, but not provided"; 79b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry return false; 80b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry } 81b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry 82b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry auto function = function_map_->FindFunction(args[0], args.size() - 1, err); 83b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry if (!function) { 84b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry return false; 85b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry } 86b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry 87b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry AddCommand(function, args, filename, line); 88b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry return true; 89b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry} 90b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry 91b7349902a945903f9e36a569051f5131beb0bc24Tom Cherryvoid Action::AddCommand(BuiltinFunction f, 92fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry const std::vector<std::string>& args, 93b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry const std::string& filename, int line) { 94b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry commands_.emplace_back(f, args, filename, line); 95b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry} 96b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry 97b7349902a945903f9e36a569051f5131beb0bc24Tom Cherryvoid Action::CombineAction(const Action& action) { 98b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry for (const auto& c : action.commands_) { 99b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry commands_.emplace_back(c); 100b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry } 101fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry} 102fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 103b7349902a945903f9e36a569051f5131beb0bc24Tom Cherrystd::size_t Action::NumCommands() const { 104fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry return commands_.size(); 105fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry} 106fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 107b7349902a945903f9e36a569051f5131beb0bc24Tom Cherryvoid Action::ExecuteOneCommand(std::size_t command) const { 108d67a4abc647d5ed7235ff7ee1695b31340e63a1cWei Wang // We need a copy here since some Command execution may result in 109d67a4abc647d5ed7235ff7ee1695b31340e63a1cWei Wang // changing commands_ vector by importing .rc files through parser 110d67a4abc647d5ed7235ff7ee1695b31340e63a1cWei Wang Command cmd = commands_[command]; 111d67a4abc647d5ed7235ff7ee1695b31340e63a1cWei Wang ExecuteCommand(cmd); 112fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry} 113fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 114b7349902a945903f9e36a569051f5131beb0bc24Tom Cherryvoid Action::ExecuteAllCommands() const { 115fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry for (const auto& c : commands_) { 116b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry ExecuteCommand(c); 117fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry } 118fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry} 119fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 120b7349902a945903f9e36a569051f5131beb0bc24Tom Cherryvoid Action::ExecuteCommand(const Command& command) const { 121fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry Timer t; 122fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry int result = command.InvokeFunc(); 123fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 124331cf2fb7c16b5b25064f8d2f00284105a9b413fElliott Hughes double duration_ms = t.duration_s() * 1000; 1258b1d526a72c1e6705b03f4b3267ee02fe84ce765Wei Wang // Any action longer than 50ms will be warned to user as slow operation 1268b1d526a72c1e6705b03f4b3267ee02fe84ce765Wei Wang if (duration_ms > 50.0 || 1278b1d526a72c1e6705b03f4b3267ee02fe84ce765Wei Wang android::base::GetMinimumLogSeverity() <= android::base::DEBUG) { 128fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry std::string trigger_name = BuildTriggersString(); 129fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry std::string cmd_str = command.BuildCommandString(); 130fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry std::string source = command.BuildSourceString(); 131fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 132f86b5a6b90619e02d1d034ef7b0adc3b439f4abbElliott Hughes LOG(INFO) << "Command '" << cmd_str << "' action=" << trigger_name << source 1338b1d526a72c1e6705b03f4b3267ee02fe84ce765Wei Wang << " returned " << result << " took " << duration_ms << "ms."; 134fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry } 135fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry} 136fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 137b7349902a945903f9e36a569051f5131beb0bc24Tom Cherrybool Action::ParsePropertyTrigger(const std::string& trigger, std::string* err) { 138fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry const static std::string prop_str("property:"); 139fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry std::string prop_name(trigger.substr(prop_str.length())); 140fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry size_t equal_pos = prop_name.find('='); 141fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry if (equal_pos == std::string::npos) { 142fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry *err = "property trigger found without matching '='"; 143fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry return false; 144fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry } 145fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 146fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry std::string prop_value(prop_name.substr(equal_pos + 1)); 147fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry prop_name.erase(equal_pos); 148fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 1492bc00140be22f08964102068a736358fe8dde5daTom Cherry if (auto [it, inserted] = property_triggers_.emplace(prop_name, prop_value); !inserted) { 150fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry *err = "multiple property triggers found for same property"; 151fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry return false; 152fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry } 153fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry return true; 154fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry} 155fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 156b7349902a945903f9e36a569051f5131beb0bc24Tom Cherrybool Action::InitTriggers(const std::vector<std::string>& args, std::string* err) { 157fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry const static std::string prop_str("property:"); 158fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry for (std::size_t i = 0; i < args.size(); ++i) { 15993df4e18a255262595acb862ab870e9fed721fb8Wei Wang if (args[i].empty()) { 16093df4e18a255262595acb862ab870e9fed721fb8Wei Wang *err = "empty trigger is not valid"; 16193df4e18a255262595acb862ab870e9fed721fb8Wei Wang return false; 16293df4e18a255262595acb862ab870e9fed721fb8Wei Wang } 16393df4e18a255262595acb862ab870e9fed721fb8Wei Wang 164fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry if (i % 2) { 165cb716f976b078dff72aa3a61f9435d45e4beb9f5Tom Cherry if (args[i] != "&&") { 166fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry *err = "&& is the only symbol allowed to concatenate actions"; 167fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry return false; 168fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry } else { 169fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry continue; 170fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry } 171fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry } 172fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 173fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry if (!args[i].compare(0, prop_str.length(), prop_str)) { 174fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry if (!ParsePropertyTrigger(args[i], err)) { 175fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry return false; 176fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry } 177fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry } else { 178fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry if (!event_trigger_.empty()) { 179fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry *err = "multiple event triggers are not allowed"; 180fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry return false; 181fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry } 182fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 183fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry event_trigger_ = args[i]; 184fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry } 185fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry } 186fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 187fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry return true; 188fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry} 189fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 190b7349902a945903f9e36a569051f5131beb0bc24Tom Cherrybool Action::InitSingleTrigger(const std::string& trigger) { 191fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry std::vector<std::string> name_vector{trigger}; 192fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry std::string err; 19393df4e18a255262595acb862ab870e9fed721fb8Wei Wang bool ret = InitTriggers(name_vector, &err); 19493df4e18a255262595acb862ab870e9fed721fb8Wei Wang if (!ret) { 19593df4e18a255262595acb862ab870e9fed721fb8Wei Wang LOG(ERROR) << "InitSingleTrigger failed due to: " << err; 19693df4e18a255262595acb862ab870e9fed721fb8Wei Wang } 19793df4e18a255262595acb862ab870e9fed721fb8Wei Wang return ret; 198fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry} 199fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 200b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry// This function checks that all property triggers are satisfied, that is 201b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry// for each (name, value) in property_triggers_, check that the current 202b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry// value of the property 'name' == value. 203b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry// 204b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry// It takes an optional (name, value) pair, which if provided must 205b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry// be present in property_triggers_; it skips the check of the current 206b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry// property value for this pair. 207fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherrybool Action::CheckPropertyTriggers(const std::string& name, 208b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry const std::string& value) const { 209fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry if (property_triggers_.empty()) { 210fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry return true; 211fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry } 212fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 213b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry bool found = name.empty(); 2142bc00140be22f08964102068a736358fe8dde5daTom Cherry for (const auto& [trigger_name, trigger_value] : property_triggers_) { 215cb716f976b078dff72aa3a61f9435d45e4beb9f5Tom Cherry if (trigger_name == name) { 216cb716f976b078dff72aa3a61f9435d45e4beb9f5Tom Cherry if (trigger_value != "*" && trigger_value != value) { 217fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry return false; 218fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry } else { 219fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry found = true; 220fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry } 221fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry } else { 222ccf23537eeacfa47e5f18dd3b75089886d177c1bTom Cherry std::string prop_val = android::base::GetProperty(trigger_name, ""); 223ccf23537eeacfa47e5f18dd3b75089886d177c1bTom Cherry if (prop_val.empty() || (trigger_value != "*" && trigger_value != prop_val)) { 224fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry return false; 225fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry } 226fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry } 227fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry } 228fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry return found; 229fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry} 230fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 231b7349902a945903f9e36a569051f5131beb0bc24Tom Cherrybool Action::CheckEventTrigger(const std::string& trigger) const { 232fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry return !event_trigger_.empty() && 233cb716f976b078dff72aa3a61f9435d45e4beb9f5Tom Cherry trigger == event_trigger_ && 234fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry CheckPropertyTriggers(); 235fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry} 236fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 237fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherrybool Action::CheckPropertyTrigger(const std::string& name, 238b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry const std::string& value) const { 239fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry return event_trigger_.empty() && CheckPropertyTriggers(name, value); 240fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry} 241fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 242b7349902a945903f9e36a569051f5131beb0bc24Tom Cherrybool Action::TriggersEqual(const Action& other) const { 243cb716f976b078dff72aa3a61f9435d45e4beb9f5Tom Cherry return property_triggers_ == other.property_triggers_ && 244cb716f976b078dff72aa3a61f9435d45e4beb9f5Tom Cherry event_trigger_ == other.event_trigger_; 245fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry} 246fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 247b7349902a945903f9e36a569051f5131beb0bc24Tom Cherrystd::string Action::BuildTriggersString() const { 248d8a7257b14086a9070aa521b41118570ee4f4aaaTom Cherry std::vector<std::string> triggers; 249fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 2502bc00140be22f08964102068a736358fe8dde5daTom Cherry for (const auto& [trigger_name, trigger_value] : property_triggers_) { 251d8a7257b14086a9070aa521b41118570ee4f4aaaTom Cherry triggers.emplace_back(trigger_name + '=' + trigger_value); 252fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry } 253fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry if (!event_trigger_.empty()) { 254d8a7257b14086a9070aa521b41118570ee4f4aaaTom Cherry triggers.emplace_back(event_trigger_); 255fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry } 256d8a7257b14086a9070aa521b41118570ee4f4aaaTom Cherry 257d8a7257b14086a9070aa521b41118570ee4f4aaaTom Cherry return Join(triggers, " && "); 258fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry} 259fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 260b7349902a945903f9e36a569051f5131beb0bc24Tom Cherryvoid Action::DumpState() const { 261fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry std::string trigger_name = BuildTriggersString(); 262f86b5a6b90619e02d1d034ef7b0adc3b439f4abbElliott Hughes LOG(INFO) << "on " << trigger_name; 263fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 264fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry for (const auto& c : commands_) { 265b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry std::string cmd_str = c.BuildCommandString(); 266d8a7257b14086a9070aa521b41118570ee4f4aaaTom Cherry LOG(INFO) << " " << cmd_str; 267fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry } 268fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry} 269fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 270cb716f976b078dff72aa3a61f9435d45e4beb9f5Tom Cherryclass EventTrigger : public Trigger { 271cb716f976b078dff72aa3a61f9435d45e4beb9f5Tom Cherrypublic: 2721c563d96f000876d77b2d33fbfb03c241bc503e1Chih-Hung Hsieh explicit EventTrigger(const std::string& trigger) : trigger_(trigger) { 273cb716f976b078dff72aa3a61f9435d45e4beb9f5Tom Cherry } 274b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry bool CheckTriggers(const Action& action) const override { 275b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry return action.CheckEventTrigger(trigger_); 276cb716f976b078dff72aa3a61f9435d45e4beb9f5Tom Cherry } 277cb716f976b078dff72aa3a61f9435d45e4beb9f5Tom Cherryprivate: 278b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry const std::string trigger_; 279cb716f976b078dff72aa3a61f9435d45e4beb9f5Tom Cherry}; 280cb716f976b078dff72aa3a61f9435d45e4beb9f5Tom Cherry 281cb716f976b078dff72aa3a61f9435d45e4beb9f5Tom Cherryclass PropertyTrigger : public Trigger { 282cb716f976b078dff72aa3a61f9435d45e4beb9f5Tom Cherrypublic: 283cb716f976b078dff72aa3a61f9435d45e4beb9f5Tom Cherry PropertyTrigger(const std::string& name, const std::string& value) 284cb716f976b078dff72aa3a61f9435d45e4beb9f5Tom Cherry : name_(name), value_(value) { 285cb716f976b078dff72aa3a61f9435d45e4beb9f5Tom Cherry } 286b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry bool CheckTriggers(const Action& action) const override { 287b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry return action.CheckPropertyTrigger(name_, value_); 288cb716f976b078dff72aa3a61f9435d45e4beb9f5Tom Cherry } 289cb716f976b078dff72aa3a61f9435d45e4beb9f5Tom Cherryprivate: 290b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry const std::string name_; 291b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry const std::string value_; 292cb716f976b078dff72aa3a61f9435d45e4beb9f5Tom Cherry}; 293cb716f976b078dff72aa3a61f9435d45e4beb9f5Tom Cherry 294cb716f976b078dff72aa3a61f9435d45e4beb9f5Tom Cherryclass BuiltinTrigger : public Trigger { 295cb716f976b078dff72aa3a61f9435d45e4beb9f5Tom Cherrypublic: 2961c563d96f000876d77b2d33fbfb03c241bc503e1Chih-Hung Hsieh explicit BuiltinTrigger(Action* action) : action_(action) { 297cb716f976b078dff72aa3a61f9435d45e4beb9f5Tom Cherry } 298b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry bool CheckTriggers(const Action& action) const override { 299b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry return action_ == &action; 300cb716f976b078dff72aa3a61f9435d45e4beb9f5Tom Cherry } 301cb716f976b078dff72aa3a61f9435d45e4beb9f5Tom Cherryprivate: 302b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry const Action* action_; 303cb716f976b078dff72aa3a61f9435d45e4beb9f5Tom Cherry}; 304cb716f976b078dff72aa3a61f9435d45e4beb9f5Tom Cherry 305b7349902a945903f9e36a569051f5131beb0bc24Tom CherryActionManager::ActionManager() : current_command_(0) { 306fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry} 307fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 308fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom CherryActionManager& ActionManager::GetInstance() { 309fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry static ActionManager instance; 310fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry return instance; 311fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry} 312fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 313b7349902a945903f9e36a569051f5131beb0bc24Tom Cherryvoid ActionManager::AddAction(std::unique_ptr<Action> action) { 314b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry auto old_action_it = 315b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry std::find_if(actions_.begin(), actions_.end(), 316b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry [&action] (std::unique_ptr<Action>& a) { 317b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry return action->TriggersEqual(*a); 318b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry }); 319b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry 320b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry if (old_action_it != actions_.end()) { 321b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry (*old_action_it)->CombineAction(*action); 322b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry } else { 323b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry actions_.emplace_back(std::move(action)); 324b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry } 325b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry} 326b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry 327b7349902a945903f9e36a569051f5131beb0bc24Tom Cherryvoid ActionManager::QueueEventTrigger(const std::string& trigger) { 328cb716f976b078dff72aa3a61f9435d45e4beb9f5Tom Cherry trigger_queue_.push(std::make_unique<EventTrigger>(trigger)); 329fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry} 330fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 331fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherryvoid ActionManager::QueuePropertyTrigger(const std::string& name, 332b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry const std::string& value) { 333cb716f976b078dff72aa3a61f9435d45e4beb9f5Tom Cherry trigger_queue_.push(std::make_unique<PropertyTrigger>(name, value)); 334fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry} 335fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 336b7349902a945903f9e36a569051f5131beb0bc24Tom Cherryvoid ActionManager::QueueAllPropertyTriggers() { 337fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry QueuePropertyTrigger("", ""); 338fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry} 339fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 340b7349902a945903f9e36a569051f5131beb0bc24Tom Cherryvoid ActionManager::QueueBuiltinAction(BuiltinFunction func, 341b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry const std::string& name) { 342b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry auto action = std::make_unique<Action>(true); 343fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry std::vector<std::string> name_vector{name}; 344fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 345b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry if (!action->InitSingleTrigger(name)) { 346fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry return; 347fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry } 348fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 349b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry action->AddCommand(func, name_vector); 350fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 351b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry trigger_queue_.push(std::make_unique<BuiltinTrigger>(action.get())); 352b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry actions_.emplace_back(std::move(action)); 353fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry} 354fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 355fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherryvoid ActionManager::ExecuteOneCommand() { 356b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry // Loop through the trigger queue until we have an action to execute 357cb716f976b078dff72aa3a61f9435d45e4beb9f5Tom Cherry while (current_executing_actions_.empty() && !trigger_queue_.empty()) { 358b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry for (const auto& action : actions_) { 359b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry if (trigger_queue_.front()->CheckTriggers(*action)) { 360b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry current_executing_actions_.emplace(action.get()); 361b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry } 362b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry } 363cb716f976b078dff72aa3a61f9435d45e4beb9f5Tom Cherry trigger_queue_.pop(); 364cb716f976b078dff72aa3a61f9435d45e4beb9f5Tom Cherry } 365cb716f976b078dff72aa3a61f9435d45e4beb9f5Tom Cherry 366cb716f976b078dff72aa3a61f9435d45e4beb9f5Tom Cherry if (current_executing_actions_.empty()) { 367fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry return; 368fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry } 369fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 370b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry auto action = current_executing_actions_.front(); 371fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 372cb716f976b078dff72aa3a61f9435d45e4beb9f5Tom Cherry if (current_command_ == 0) { 373fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry std::string trigger_name = action->BuildTriggersString(); 374f86b5a6b90619e02d1d034ef7b0adc3b439f4abbElliott Hughes LOG(INFO) << "processing action (" << trigger_name << ")"; 375fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry } 376fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 377b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry action->ExecuteOneCommand(current_command_); 378b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry 379b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry // If this was the last command in the current action, then remove 380b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry // the action from the executing list. 381b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry // If this action was oneshot, then also remove it from actions_. 382b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry ++current_command_; 383cb716f976b078dff72aa3a61f9435d45e4beb9f5Tom Cherry if (current_command_ == action->NumCommands()) { 384b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry current_executing_actions_.pop(); 385cb716f976b078dff72aa3a61f9435d45e4beb9f5Tom Cherry current_command_ = 0; 386b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry if (action->oneshot()) { 387b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry auto eraser = [&action] (std::unique_ptr<Action>& a) { 388b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry return a.get() == action; 389b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry }; 390b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry actions_.erase(std::remove_if(actions_.begin(), actions_.end(), eraser)); 391b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry } 392fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry } 393fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry} 394fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 395b7349902a945903f9e36a569051f5131beb0bc24Tom Cherrybool ActionManager::HasMoreCommands() const { 396cb716f976b078dff72aa3a61f9435d45e4beb9f5Tom Cherry return !current_executing_actions_.empty() || !trigger_queue_.empty(); 397fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry} 398fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 399b7349902a945903f9e36a569051f5131beb0bc24Tom Cherryvoid ActionManager::DumpState() const { 400b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry for (const auto& a : actions_) { 401b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry a->DumpState(); 402fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry } 403b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry} 404fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 405b7349902a945903f9e36a569051f5131beb0bc24Tom Cherrybool ActionParser::ParseSection(const std::vector<std::string>& args, 406b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry std::string* err) { 407b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry std::vector<std::string> triggers(args.begin() + 1, args.end()); 408b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry if (triggers.size() < 1) { 409b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry *err = "actions must have a trigger"; 410b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry return false; 411fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry } 412fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 413b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry auto action = std::make_unique<Action>(false); 414b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry if (!action->InitTriggers(triggers, err)) { 415b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry return false; 416fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry } 417fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 418b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry action_ = std::move(action); 419b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry return true; 420fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry} 421fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 422b7349902a945903f9e36a569051f5131beb0bc24Tom Cherrybool ActionParser::ParseLineSection(const std::vector<std::string>& args, 423b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry const std::string& filename, int line, 424b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry std::string* err) const { 425b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry return action_ ? action_->AddCommand(args, filename, line, err) : false; 426b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry} 427b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry 428b7349902a945903f9e36a569051f5131beb0bc24Tom Cherryvoid ActionParser::EndSection() { 429b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry if (action_ && action_->NumCommands() > 0) { 430b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry ActionManager::GetInstance().AddAction(std::move(action_)); 431fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry } 432fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry} 433