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 19ede0d538501dfc78c741fb3b0645406636d1d1fdTom Cherry#include <android-base/chrono_utils.h> 203f5eaae526413a29de899270714469c76dc91ec8Tom Cherry#include <android-base/logging.h> 21ccf23537eeacfa47e5f18dd3b75089886d177c1bTom Cherry#include <android-base/properties.h> 22ccf23537eeacfa47e5f18dd3b75089886d177c1bTom Cherry#include <android-base/strings.h> 23fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 24fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry#include "util.h" 25fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 26b7349902a945903f9e36a569051f5131beb0bc24Tom Cherryusing android::base::Join; 27fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 2881f5d3ebef2c3789737bf718fc2a2cdd7b9e8b33Tom Cherrynamespace android { 2981f5d3ebef2c3789737bf718fc2a2cdd7b9e8b33Tom Cherrynamespace init { 3081f5d3ebef2c3789737bf718fc2a2cdd7b9e8b33Tom Cherry 31012c573e267b8dd70de14237cb470bd7301ee8eaTom CherryCommand::Command(BuiltinFunction f, const std::vector<std::string>& args, int line) 32012c573e267b8dd70de14237cb470bd7301ee8eaTom Cherry : func_(f), args_(args), line_(line) {} 33fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 34b7349902a945903f9e36a569051f5131beb0bc24Tom Cherryint Command::InvokeFunc() const { 3596f67316a22bc9236aed70b198e91a5406389e5bTom Cherry std::vector<std::string> expanded_args; 3696f67316a22bc9236aed70b198e91a5406389e5bTom Cherry expanded_args.resize(args_.size()); 3796f67316a22bc9236aed70b198e91a5406389e5bTom Cherry expanded_args[0] = args_[0]; 38fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry for (std::size_t i = 1; i < args_.size(); ++i) { 39b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry if (!expand_props(args_[i], &expanded_args[i])) { 40f86b5a6b90619e02d1d034ef7b0adc3b439f4abbElliott Hughes LOG(ERROR) << args_[0] << ": cannot expand '" << args_[i] << "'"; 41fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry return -EINVAL; 42fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry } 43fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry } 44fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 4596f67316a22bc9236aed70b198e91a5406389e5bTom Cherry return func_(expanded_args); 46fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry} 47fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 48b7349902a945903f9e36a569051f5131beb0bc24Tom Cherrystd::string Command::BuildCommandString() const { 49b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry return Join(args_, ' '); 50fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry} 51fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 52012c573e267b8dd70de14237cb470bd7301ee8eaTom CherryAction::Action(bool oneshot, const std::string& filename, int line) 53012c573e267b8dd70de14237cb470bd7301ee8eaTom Cherry : oneshot_(oneshot), filename_(filename), line_(line) {} 54fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 55b7349902a945903f9e36a569051f5131beb0bc24Tom Cherryconst KeywordMap<BuiltinFunction>* Action::function_map_ = nullptr; 56b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry 57012c573e267b8dd70de14237cb470bd7301ee8eaTom Cherrybool Action::AddCommand(const std::vector<std::string>& args, int line, std::string* err) { 58b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry if (!function_map_) { 59b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry *err = "no function map available"; 60b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry return false; 61b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry } 62b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry 63fe062055cb11fcb1a6178b046173fc0361ad5b96Tom Cherry auto function = function_map_->FindFunction(args, err); 64b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry if (!function) { 65b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry return false; 66b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry } 67b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry 68012c573e267b8dd70de14237cb470bd7301ee8eaTom Cherry AddCommand(function, args, line); 69b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry return true; 70b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry} 71b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry 72012c573e267b8dd70de14237cb470bd7301ee8eaTom Cherryvoid Action::AddCommand(BuiltinFunction f, const std::vector<std::string>& args, int line) { 73012c573e267b8dd70de14237cb470bd7301ee8eaTom Cherry commands_.emplace_back(f, args, line); 74fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry} 75fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 76b7349902a945903f9e36a569051f5131beb0bc24Tom Cherrystd::size_t Action::NumCommands() const { 77fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry return commands_.size(); 78fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry} 79fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 80b7349902a945903f9e36a569051f5131beb0bc24Tom Cherryvoid Action::ExecuteOneCommand(std::size_t command) const { 81d67a4abc647d5ed7235ff7ee1695b31340e63a1cWei Wang // We need a copy here since some Command execution may result in 82d67a4abc647d5ed7235ff7ee1695b31340e63a1cWei Wang // changing commands_ vector by importing .rc files through parser 83d67a4abc647d5ed7235ff7ee1695b31340e63a1cWei Wang Command cmd = commands_[command]; 84d67a4abc647d5ed7235ff7ee1695b31340e63a1cWei Wang ExecuteCommand(cmd); 85fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry} 86fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 87b7349902a945903f9e36a569051f5131beb0bc24Tom Cherryvoid Action::ExecuteAllCommands() const { 88fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry for (const auto& c : commands_) { 89b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry ExecuteCommand(c); 90fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry } 91fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry} 92fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 93b7349902a945903f9e36a569051f5131beb0bc24Tom Cherryvoid Action::ExecuteCommand(const Command& command) const { 94ede0d538501dfc78c741fb3b0645406636d1d1fdTom Cherry android::base::Timer t; 95fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry int result = command.InvokeFunc(); 96fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 97ede0d538501dfc78c741fb3b0645406636d1d1fdTom Cherry auto duration = t.duration(); 988b1d526a72c1e6705b03f4b3267ee02fe84ce765Wei Wang // Any action longer than 50ms will be warned to user as slow operation 99ede0d538501dfc78c741fb3b0645406636d1d1fdTom Cherry if (duration > 50ms || android::base::GetMinimumLogSeverity() <= android::base::DEBUG) { 100fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry std::string trigger_name = BuildTriggersString(); 101fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry std::string cmd_str = command.BuildCommandString(); 102fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 1031c3a53f03ca3c2c647f83cd8b8ae7e18c5c7bc69Tom Cherry LOG(INFO) << "Command '" << cmd_str << "' action=" << trigger_name << " (" << filename_ 104ede0d538501dfc78c741fb3b0645406636d1d1fdTom Cherry << ":" << command.line() << ") returned " << result << " took " 105ede0d538501dfc78c741fb3b0645406636d1d1fdTom Cherry << duration.count() << "ms."; 106fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry } 107fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry} 108fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 109b7349902a945903f9e36a569051f5131beb0bc24Tom Cherrybool Action::ParsePropertyTrigger(const std::string& trigger, std::string* err) { 110fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry const static std::string prop_str("property:"); 111fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry std::string prop_name(trigger.substr(prop_str.length())); 112fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry size_t equal_pos = prop_name.find('='); 113fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry if (equal_pos == std::string::npos) { 114fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry *err = "property trigger found without matching '='"; 115fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry return false; 116fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry } 117fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 118fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry std::string prop_value(prop_name.substr(equal_pos + 1)); 119fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry prop_name.erase(equal_pos); 120fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 1212bc00140be22f08964102068a736358fe8dde5daTom Cherry if (auto [it, inserted] = property_triggers_.emplace(prop_name, prop_value); !inserted) { 122fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry *err = "multiple property triggers found for same property"; 123fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry return false; 124fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry } 125fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry return true; 126fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry} 127fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 128b7349902a945903f9e36a569051f5131beb0bc24Tom Cherrybool Action::InitTriggers(const std::vector<std::string>& args, std::string* err) { 129fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry const static std::string prop_str("property:"); 130fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry for (std::size_t i = 0; i < args.size(); ++i) { 13193df4e18a255262595acb862ab870e9fed721fb8Wei Wang if (args[i].empty()) { 13293df4e18a255262595acb862ab870e9fed721fb8Wei Wang *err = "empty trigger is not valid"; 13393df4e18a255262595acb862ab870e9fed721fb8Wei Wang return false; 13493df4e18a255262595acb862ab870e9fed721fb8Wei Wang } 13593df4e18a255262595acb862ab870e9fed721fb8Wei Wang 136fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry if (i % 2) { 137cb716f976b078dff72aa3a61f9435d45e4beb9f5Tom Cherry if (args[i] != "&&") { 138fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry *err = "&& is the only symbol allowed to concatenate actions"; 139fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry return false; 140fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry } else { 141fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry continue; 142fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry } 143fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry } 144fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 145fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry if (!args[i].compare(0, prop_str.length(), prop_str)) { 146fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry if (!ParsePropertyTrigger(args[i], err)) { 147fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry return false; 148fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry } 149fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry } else { 150fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry if (!event_trigger_.empty()) { 151fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry *err = "multiple event triggers are not allowed"; 152fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry return false; 153fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry } 154fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 155fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry event_trigger_ = args[i]; 156fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry } 157fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry } 158fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 159fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry return true; 160fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry} 161fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 162b7349902a945903f9e36a569051f5131beb0bc24Tom Cherrybool Action::InitSingleTrigger(const std::string& trigger) { 163fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry std::vector<std::string> name_vector{trigger}; 164fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry std::string err; 16593df4e18a255262595acb862ab870e9fed721fb8Wei Wang bool ret = InitTriggers(name_vector, &err); 16693df4e18a255262595acb862ab870e9fed721fb8Wei Wang if (!ret) { 16793df4e18a255262595acb862ab870e9fed721fb8Wei Wang LOG(ERROR) << "InitSingleTrigger failed due to: " << err; 16893df4e18a255262595acb862ab870e9fed721fb8Wei Wang } 16993df4e18a255262595acb862ab870e9fed721fb8Wei Wang return ret; 170fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry} 171fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 172b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry// This function checks that all property triggers are satisfied, that is 173b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry// for each (name, value) in property_triggers_, check that the current 174b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry// value of the property 'name' == value. 175b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry// 176b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry// It takes an optional (name, value) pair, which if provided must 177b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry// be present in property_triggers_; it skips the check of the current 178b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry// property value for this pair. 179fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherrybool Action::CheckPropertyTriggers(const std::string& name, 180b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry const std::string& value) const { 181fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry if (property_triggers_.empty()) { 182fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry return true; 183fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry } 184fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 185b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry bool found = name.empty(); 1862bc00140be22f08964102068a736358fe8dde5daTom Cherry for (const auto& [trigger_name, trigger_value] : property_triggers_) { 187cb716f976b078dff72aa3a61f9435d45e4beb9f5Tom Cherry if (trigger_name == name) { 188cb716f976b078dff72aa3a61f9435d45e4beb9f5Tom Cherry if (trigger_value != "*" && trigger_value != value) { 189fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry return false; 190fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry } else { 191fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry found = true; 192fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry } 193fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry } else { 194ccf23537eeacfa47e5f18dd3b75089886d177c1bTom Cherry std::string prop_val = android::base::GetProperty(trigger_name, ""); 195ccf23537eeacfa47e5f18dd3b75089886d177c1bTom Cherry if (prop_val.empty() || (trigger_value != "*" && trigger_value != prop_val)) { 196fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry return false; 197fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry } 198fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry } 199fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry } 200fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry return found; 201fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry} 202fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 20326ed9cb7062c852749b18cd4b5873d07a3389d00Tom Cherrybool Action::CheckEvent(const EventTrigger& event_trigger) const { 20426ed9cb7062c852749b18cd4b5873d07a3389d00Tom Cherry return event_trigger == event_trigger_ && CheckPropertyTriggers(); 205fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry} 206fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 20726ed9cb7062c852749b18cd4b5873d07a3389d00Tom Cherrybool Action::CheckEvent(const PropertyChange& property_change) const { 20826ed9cb7062c852749b18cd4b5873d07a3389d00Tom Cherry const auto& [name, value] = property_change; 209fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry return event_trigger_.empty() && CheckPropertyTriggers(name, value); 210fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry} 211fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 21226ed9cb7062c852749b18cd4b5873d07a3389d00Tom Cherrybool Action::CheckEvent(const BuiltinAction& builtin_action) const { 21326ed9cb7062c852749b18cd4b5873d07a3389d00Tom Cherry return this == builtin_action; 21426ed9cb7062c852749b18cd4b5873d07a3389d00Tom Cherry} 21526ed9cb7062c852749b18cd4b5873d07a3389d00Tom Cherry 216b7349902a945903f9e36a569051f5131beb0bc24Tom Cherrystd::string Action::BuildTriggersString() const { 217d8a7257b14086a9070aa521b41118570ee4f4aaaTom Cherry std::vector<std::string> triggers; 218fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 2192bc00140be22f08964102068a736358fe8dde5daTom Cherry for (const auto& [trigger_name, trigger_value] : property_triggers_) { 220d8a7257b14086a9070aa521b41118570ee4f4aaaTom Cherry triggers.emplace_back(trigger_name + '=' + trigger_value); 221fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry } 222fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry if (!event_trigger_.empty()) { 223d8a7257b14086a9070aa521b41118570ee4f4aaaTom Cherry triggers.emplace_back(event_trigger_); 224fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry } 225d8a7257b14086a9070aa521b41118570ee4f4aaaTom Cherry 226d8a7257b14086a9070aa521b41118570ee4f4aaaTom Cherry return Join(triggers, " && "); 227fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry} 228fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 229b7349902a945903f9e36a569051f5131beb0bc24Tom Cherryvoid Action::DumpState() const { 230fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry std::string trigger_name = BuildTriggersString(); 231f86b5a6b90619e02d1d034ef7b0adc3b439f4abbElliott Hughes LOG(INFO) << "on " << trigger_name; 232fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 233fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry for (const auto& c : commands_) { 234b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry std::string cmd_str = c.BuildCommandString(); 235d8a7257b14086a9070aa521b41118570ee4f4aaaTom Cherry LOG(INFO) << " " << cmd_str; 236fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry } 237fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry} 238fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 239b7349902a945903f9e36a569051f5131beb0bc24Tom CherryActionManager::ActionManager() : current_command_(0) { 240fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry} 241fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 242fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom CherryActionManager& ActionManager::GetInstance() { 243fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry static ActionManager instance; 244fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry return instance; 245fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry} 246fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 247b7349902a945903f9e36a569051f5131beb0bc24Tom Cherryvoid ActionManager::AddAction(std::unique_ptr<Action> action) { 248012c573e267b8dd70de14237cb470bd7301ee8eaTom Cherry actions_.emplace_back(std::move(action)); 249b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry} 250b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry 251b7349902a945903f9e36a569051f5131beb0bc24Tom Cherryvoid ActionManager::QueueEventTrigger(const std::string& trigger) { 25226ed9cb7062c852749b18cd4b5873d07a3389d00Tom Cherry event_queue_.emplace(trigger); 253fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry} 254fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 25526ed9cb7062c852749b18cd4b5873d07a3389d00Tom Cherryvoid ActionManager::QueuePropertyChange(const std::string& name, const std::string& value) { 25626ed9cb7062c852749b18cd4b5873d07a3389d00Tom Cherry event_queue_.emplace(std::make_pair(name, value)); 257fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry} 258fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 25926ed9cb7062c852749b18cd4b5873d07a3389d00Tom Cherryvoid ActionManager::QueueAllPropertyActions() { 26026ed9cb7062c852749b18cd4b5873d07a3389d00Tom Cherry QueuePropertyChange("", ""); 261fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry} 262fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 263012c573e267b8dd70de14237cb470bd7301ee8eaTom Cherryvoid ActionManager::QueueBuiltinAction(BuiltinFunction func, const std::string& name) { 264012c573e267b8dd70de14237cb470bd7301ee8eaTom Cherry auto action = std::make_unique<Action>(true, "<Builtin Action>", 0); 265fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry std::vector<std::string> name_vector{name}; 266fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 267b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry if (!action->InitSingleTrigger(name)) { 268fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry return; 269fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry } 270fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 271012c573e267b8dd70de14237cb470bd7301ee8eaTom Cherry action->AddCommand(func, name_vector, 0); 272fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 27326ed9cb7062c852749b18cd4b5873d07a3389d00Tom Cherry event_queue_.emplace(action.get()); 274b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry actions_.emplace_back(std::move(action)); 275fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry} 276fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 277fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherryvoid ActionManager::ExecuteOneCommand() { 27826ed9cb7062c852749b18cd4b5873d07a3389d00Tom Cherry // Loop through the event queue until we have an action to execute 27926ed9cb7062c852749b18cd4b5873d07a3389d00Tom Cherry while (current_executing_actions_.empty() && !event_queue_.empty()) { 280b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry for (const auto& action : actions_) { 28126ed9cb7062c852749b18cd4b5873d07a3389d00Tom Cherry if (std::visit([&action](const auto& event) { return action->CheckEvent(event); }, 28226ed9cb7062c852749b18cd4b5873d07a3389d00Tom Cherry event_queue_.front())) { 283b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry current_executing_actions_.emplace(action.get()); 284b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry } 285b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry } 28626ed9cb7062c852749b18cd4b5873d07a3389d00Tom Cherry event_queue_.pop(); 287cb716f976b078dff72aa3a61f9435d45e4beb9f5Tom Cherry } 288cb716f976b078dff72aa3a61f9435d45e4beb9f5Tom Cherry 289cb716f976b078dff72aa3a61f9435d45e4beb9f5Tom Cherry if (current_executing_actions_.empty()) { 290fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry return; 291fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry } 292fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 293b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry auto action = current_executing_actions_.front(); 294fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 295cb716f976b078dff72aa3a61f9435d45e4beb9f5Tom Cherry if (current_command_ == 0) { 296fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry std::string trigger_name = action->BuildTriggersString(); 297012c573e267b8dd70de14237cb470bd7301ee8eaTom Cherry LOG(INFO) << "processing action (" << trigger_name << ") from (" << action->filename() 298012c573e267b8dd70de14237cb470bd7301ee8eaTom Cherry << ":" << action->line() << ")"; 299fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry } 300fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 301b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry action->ExecuteOneCommand(current_command_); 302b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry 303b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry // If this was the last command in the current action, then remove 304b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry // the action from the executing list. 305b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry // If this action was oneshot, then also remove it from actions_. 306b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry ++current_command_; 307cb716f976b078dff72aa3a61f9435d45e4beb9f5Tom Cherry if (current_command_ == action->NumCommands()) { 308b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry current_executing_actions_.pop(); 309cb716f976b078dff72aa3a61f9435d45e4beb9f5Tom Cherry current_command_ = 0; 310b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry if (action->oneshot()) { 311b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry auto eraser = [&action] (std::unique_ptr<Action>& a) { 312b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry return a.get() == action; 313b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry }; 314b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry actions_.erase(std::remove_if(actions_.begin(), actions_.end(), eraser)); 315b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry } 316fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry } 317fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry} 318fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 319b7349902a945903f9e36a569051f5131beb0bc24Tom Cherrybool ActionManager::HasMoreCommands() const { 32026ed9cb7062c852749b18cd4b5873d07a3389d00Tom Cherry return !current_executing_actions_.empty() || !event_queue_.empty(); 321fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry} 322fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 323b7349902a945903f9e36a569051f5131beb0bc24Tom Cherryvoid ActionManager::DumpState() const { 324b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry for (const auto& a : actions_) { 325b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry a->DumpState(); 326fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry } 327b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry} 328fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 329eeab491efd8f456324f88e444f228b1016712e45Wei Wangvoid ActionManager::ClearQueue() { 330eeab491efd8f456324f88e444f228b1016712e45Wei Wang // We are shutting down so don't claim the oneshot builtin actions back 331eeab491efd8f456324f88e444f228b1016712e45Wei Wang current_executing_actions_ = {}; 332eeab491efd8f456324f88e444f228b1016712e45Wei Wang event_queue_ = {}; 333eeab491efd8f456324f88e444f228b1016712e45Wei Wang current_command_ = 0; 334eeab491efd8f456324f88e444f228b1016712e45Wei Wang} 335eeab491efd8f456324f88e444f228b1016712e45Wei Wang 33630a6f276fd8850b0a78689d7bff3cb06a18cb286Tom Cherrybool ActionParser::ParseSection(std::vector<std::string>&& args, const std::string& filename, 337012c573e267b8dd70de14237cb470bd7301ee8eaTom Cherry int line, std::string* err) { 338b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry std::vector<std::string> triggers(args.begin() + 1, args.end()); 339b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry if (triggers.size() < 1) { 340b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry *err = "actions must have a trigger"; 341b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry return false; 342fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry } 343fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 344012c573e267b8dd70de14237cb470bd7301ee8eaTom Cherry auto action = std::make_unique<Action>(false, filename, line); 345b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry if (!action->InitTriggers(triggers, err)) { 346b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry return false; 347fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry } 348fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 349b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry action_ = std::move(action); 350b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry return true; 351fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry} 352fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry 35330a6f276fd8850b0a78689d7bff3cb06a18cb286Tom Cherrybool ActionParser::ParseLineSection(std::vector<std::string>&& args, int line, std::string* err) { 35430a6f276fd8850b0a78689d7bff3cb06a18cb286Tom Cherry return action_ ? action_->AddCommand(std::move(args), line, err) : false; 355b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry} 356b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry 357b7349902a945903f9e36a569051f5131beb0bc24Tom Cherryvoid ActionParser::EndSection() { 358b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry if (action_ && action_->NumCommands() > 0) { 35930a6f276fd8850b0a78689d7bff3cb06a18cb286Tom Cherry action_manager_->AddAction(std::move(action_)); 360fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry } 361fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry} 36281f5d3ebef2c3789737bf718fc2a2cdd7b9e8b33Tom Cherry 36381f5d3ebef2c3789737bf718fc2a2cdd7b9e8b33Tom Cherry} // namespace init 36481f5d3ebef2c3789737bf718fc2a2cdd7b9e8b33Tom Cherry} // namespace android 365