action_parser.cpp 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. /*
  2. * Copyright (C) 2018 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_parser.h"
  17. #include <android-base/properties.h>
  18. #include <android-base/strings.h>
  19. #if defined(__ANDROID__)
  20. #include "property_service.h"
  21. #else
  22. #include "host_init_stubs.h"
  23. #endif
  24. using android::base::GetBoolProperty;
  25. using android::base::StartsWith;
  26. namespace android {
  27. namespace init {
  28. namespace {
  29. bool IsActionableProperty(Subcontext* subcontext, const std::string& prop_name) {
  30. static bool enabled = GetBoolProperty("ro.actionable_compatible_property.enabled", false);
  31. if (subcontext == nullptr || !enabled) {
  32. return true;
  33. }
  34. static constexpr const char* kPartnerPrefixes[] = {
  35. "init.svc.vendor.", "ro.vendor.", "persist.vendor.",
  36. "vendor.", "init.svc.odm.", "ro.odm.",
  37. "persist.odm.", "odm.", "ro.boot.",
  38. };
  39. for (const auto& prefix : kPartnerPrefixes) {
  40. if (android::base::StartsWith(prop_name, prefix)) {
  41. return true;
  42. }
  43. }
  44. return CanReadProperty(subcontext->context(), prop_name);
  45. }
  46. Result<Success> ParsePropertyTrigger(const std::string& trigger, Subcontext* subcontext,
  47. std::map<std::string, std::string>* property_triggers) {
  48. const static std::string prop_str("property:");
  49. std::string prop_name(trigger.substr(prop_str.length()));
  50. size_t equal_pos = prop_name.find('=');
  51. if (equal_pos == std::string::npos) {
  52. return Error() << "property trigger found without matching '='";
  53. }
  54. std::string prop_value(prop_name.substr(equal_pos + 1));
  55. prop_name.erase(equal_pos);
  56. if (!IsActionableProperty(subcontext, prop_name)) {
  57. return Error() << "unexported property trigger found: " << prop_name;
  58. }
  59. if (auto [it, inserted] = property_triggers->emplace(prop_name, prop_value); !inserted) {
  60. return Error() << "multiple property triggers found for same property";
  61. }
  62. return Success();
  63. }
  64. Result<Success> ParseTriggers(const std::vector<std::string>& args, Subcontext* subcontext,
  65. std::string* event_trigger,
  66. std::map<std::string, std::string>* property_triggers) {
  67. const static std::string prop_str("property:");
  68. for (std::size_t i = 0; i < args.size(); ++i) {
  69. if (args[i].empty()) {
  70. return Error() << "empty trigger is not valid";
  71. }
  72. if (i % 2) {
  73. if (args[i] != "&&") {
  74. return Error() << "&& is the only symbol allowed to concatenate actions";
  75. } else {
  76. continue;
  77. }
  78. }
  79. if (!args[i].compare(0, prop_str.length(), prop_str)) {
  80. if (auto result = ParsePropertyTrigger(args[i], subcontext, property_triggers);
  81. !result) {
  82. return result;
  83. }
  84. } else {
  85. if (!event_trigger->empty()) {
  86. return Error() << "multiple event triggers are not allowed";
  87. }
  88. *event_trigger = args[i];
  89. }
  90. }
  91. return Success();
  92. }
  93. } // namespace
  94. Result<Success> ActionParser::ParseSection(std::vector<std::string>&& args,
  95. const std::string& filename, int line) {
  96. std::vector<std::string> triggers(args.begin() + 1, args.end());
  97. if (triggers.size() < 1) {
  98. return Error() << "Actions must have a trigger";
  99. }
  100. Subcontext* action_subcontext = nullptr;
  101. if (subcontexts_) {
  102. for (auto& subcontext : *subcontexts_) {
  103. if (StartsWith(filename, subcontext.path_prefix())) {
  104. action_subcontext = &subcontext;
  105. break;
  106. }
  107. }
  108. }
  109. std::string event_trigger;
  110. std::map<std::string, std::string> property_triggers;
  111. if (auto result = ParseTriggers(triggers, action_subcontext, &event_trigger, &property_triggers);
  112. !result) {
  113. return Error() << "ParseTriggers() failed: " << result.error();
  114. }
  115. auto action = std::make_unique<Action>(false, action_subcontext, filename, line, event_trigger,
  116. property_triggers);
  117. action_ = std::move(action);
  118. return Success();
  119. }
  120. Result<Success> ActionParser::ParseLineSection(std::vector<std::string>&& args, int line) {
  121. return action_ ? action_->AddCommand(std::move(args), line) : Success();
  122. }
  123. Result<Success> ActionParser::EndSection() {
  124. if (action_ && action_->NumCommands() > 0) {
  125. action_manager_->AddAction(std::move(action_));
  126. }
  127. return Success();
  128. }
  129. } // namespace init
  130. } // namespace android