action.cpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. /*
  2. * Copyright (C) 2015 The Android Open Source Project
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include "action.h"
  17. #include <android-base/chrono_utils.h>
  18. #include <android-base/logging.h>
  19. #include <android-base/properties.h>
  20. #include <android-base/strings.h>
  21. #include "util.h"
  22. using android::base::Join;
  23. namespace android {
  24. namespace init {
  25. Result<Success> RunBuiltinFunction(const BuiltinFunction& function,
  26. const std::vector<std::string>& args,
  27. const std::string& context) {
  28. auto builtin_arguments = BuiltinArguments(context);
  29. builtin_arguments.args.resize(args.size());
  30. builtin_arguments.args[0] = args[0];
  31. for (std::size_t i = 1; i < args.size(); ++i) {
  32. if (!expand_props(args[i], &builtin_arguments.args[i])) {
  33. return Error() << "cannot expand '" << args[i] << "'";
  34. }
  35. }
  36. return function(builtin_arguments);
  37. }
  38. Command::Command(BuiltinFunction f, bool execute_in_subcontext, std::vector<std::string>&& args,
  39. int line)
  40. : func_(std::move(f)),
  41. execute_in_subcontext_(execute_in_subcontext),
  42. args_(std::move(args)),
  43. line_(line) {}
  44. Result<Success> Command::InvokeFunc(Subcontext* subcontext) const {
  45. if (subcontext) {
  46. if (execute_in_subcontext_) {
  47. return subcontext->Execute(args_);
  48. }
  49. auto expanded_args = subcontext->ExpandArgs(args_);
  50. if (!expanded_args) {
  51. return expanded_args.error();
  52. }
  53. return RunBuiltinFunction(func_, *expanded_args, subcontext->context());
  54. }
  55. return RunBuiltinFunction(func_, args_, kInitContext);
  56. }
  57. std::string Command::BuildCommandString() const {
  58. return Join(args_, ' ');
  59. }
  60. Action::Action(bool oneshot, Subcontext* subcontext, const std::string& filename, int line,
  61. const std::string& event_trigger,
  62. const std::map<std::string, std::string>& property_triggers)
  63. : property_triggers_(property_triggers),
  64. event_trigger_(event_trigger),
  65. oneshot_(oneshot),
  66. subcontext_(subcontext),
  67. filename_(filename),
  68. line_(line) {}
  69. const KeywordFunctionMap* Action::function_map_ = nullptr;
  70. Result<Success> Action::AddCommand(std::vector<std::string>&& args, int line) {
  71. if (!function_map_) {
  72. return Error() << "no function map available";
  73. }
  74. auto function = function_map_->FindFunction(args);
  75. if (!function) return Error() << function.error();
  76. commands_.emplace_back(function->second, function->first, std::move(args), line);
  77. return Success();
  78. }
  79. void Action::AddCommand(BuiltinFunction f, std::vector<std::string>&& args, int line) {
  80. commands_.emplace_back(f, false, std::move(args), line);
  81. }
  82. std::size_t Action::NumCommands() const {
  83. return commands_.size();
  84. }
  85. void Action::ExecuteOneCommand(std::size_t command) const {
  86. // We need a copy here since some Command execution may result in
  87. // changing commands_ vector by importing .rc files through parser
  88. Command cmd = commands_[command];
  89. ExecuteCommand(cmd);
  90. }
  91. void Action::ExecuteAllCommands() const {
  92. for (const auto& c : commands_) {
  93. ExecuteCommand(c);
  94. }
  95. }
  96. void Action::ExecuteCommand(const Command& command) const {
  97. android::base::Timer t;
  98. auto result = command.InvokeFunc(subcontext_);
  99. auto duration = t.duration();
  100. // There are many legacy paths in rootdir/init.rc that will virtually never exist on a new
  101. // device, such as '/sys/class/leds/jogball-backlight/brightness'. As of this writing, there
  102. // are 198 such failures on bullhead. Instead of spamming the log reporting them, we do not
  103. // report such failures unless we're running at the DEBUG log level.
  104. bool report_failure = !result.has_value();
  105. if (report_failure && android::base::GetMinimumLogSeverity() > android::base::DEBUG &&
  106. result.error_errno() == ENOENT) {
  107. report_failure = false;
  108. }
  109. // Any action longer than 50ms will be warned to user as slow operation
  110. if (report_failure || duration > 50ms ||
  111. android::base::GetMinimumLogSeverity() <= android::base::DEBUG) {
  112. std::string trigger_name = BuildTriggersString();
  113. std::string cmd_str = command.BuildCommandString();
  114. LOG(INFO) << "Command '" << cmd_str << "' action=" << trigger_name << " (" << filename_
  115. << ":" << command.line() << ") took " << duration.count() << "ms and "
  116. << (result ? "succeeded" : "failed: " + result.error_string());
  117. }
  118. }
  119. // This function checks that all property triggers are satisfied, that is
  120. // for each (name, value) in property_triggers_, check that the current
  121. // value of the property 'name' == value.
  122. //
  123. // It takes an optional (name, value) pair, which if provided must
  124. // be present in property_triggers_; it skips the check of the current
  125. // property value for this pair.
  126. bool Action::CheckPropertyTriggers(const std::string& name,
  127. const std::string& value) const {
  128. if (property_triggers_.empty()) {
  129. return true;
  130. }
  131. bool found = name.empty();
  132. for (const auto& [trigger_name, trigger_value] : property_triggers_) {
  133. if (trigger_name == name) {
  134. if (trigger_value != "*" && trigger_value != value) {
  135. return false;
  136. } else {
  137. found = true;
  138. }
  139. } else {
  140. std::string prop_val = android::base::GetProperty(trigger_name, "");
  141. if (prop_val.empty() || (trigger_value != "*" && trigger_value != prop_val)) {
  142. return false;
  143. }
  144. }
  145. }
  146. return found;
  147. }
  148. bool Action::CheckEvent(const EventTrigger& event_trigger) const {
  149. return event_trigger == event_trigger_ && CheckPropertyTriggers();
  150. }
  151. bool Action::CheckEvent(const PropertyChange& property_change) const {
  152. const auto& [name, value] = property_change;
  153. return event_trigger_.empty() && CheckPropertyTriggers(name, value);
  154. }
  155. bool Action::CheckEvent(const BuiltinAction& builtin_action) const {
  156. return this == builtin_action;
  157. }
  158. std::string Action::BuildTriggersString() const {
  159. std::vector<std::string> triggers;
  160. for (const auto& [trigger_name, trigger_value] : property_triggers_) {
  161. triggers.emplace_back(trigger_name + '=' + trigger_value);
  162. }
  163. if (!event_trigger_.empty()) {
  164. triggers.emplace_back(event_trigger_);
  165. }
  166. return Join(triggers, " && ");
  167. }
  168. void Action::DumpState() const {
  169. std::string trigger_name = BuildTriggersString();
  170. LOG(INFO) << "on " << trigger_name;
  171. for (const auto& c : commands_) {
  172. std::string cmd_str = c.BuildCommandString();
  173. LOG(INFO) << " " << cmd_str;
  174. }
  175. }
  176. } // namespace init
  177. } // namespace android