server_configurable_flags.cc 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  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 "server_configurable_flags/disaster_recovery.h"
  17. #include "server_configurable_flags/get_flags.h"
  18. #if defined(__BIONIC__)
  19. #include <cutils/properties.h>
  20. #endif // __BIONIC__
  21. #include <regex>
  22. #include <string>
  23. #include "android-base/file.h"
  24. #include "android-base/logging.h"
  25. #include "android-base/properties.h"
  26. #include "android-base/strings.h"
  27. #include "android-base/unique_fd.h"
  28. #define SYSTEM_PROPERTY_PREFIX "persist.device_config."
  29. #define ATTEMPTED_BOOT_COUNT_PROPERTY "persist.device_config.attempted_boot_count"
  30. #define RESET_PERFORMED_PROPERTY "device_config.reset_performed"
  31. #define RESET_FLAGS_FILE_PATH "/data/server_configurable_flags/reset_flags"
  32. #define ATTEMPTED_BOOT_COUNT_THRESHOLD 4
  33. namespace server_configurable_flags {
  34. static const std::regex NAME_VALID_CHARACTER_REGIX("^[\\w\\.\\-@:]*$");
  35. static std::string MakeSystemPropertyName(const std::string& experiment_category_name,
  36. const std::string& experiment_flag_name) {
  37. return SYSTEM_PROPERTY_PREFIX + experiment_category_name + "." + experiment_flag_name;
  38. }
  39. static bool ValidateExperimentSegment(const std::string& segment) {
  40. return std::regex_match(segment, NAME_VALID_CHARACTER_REGIX) && segment.find(".") != 0 &&
  41. segment.find(".") != segment.size() - 1;
  42. }
  43. #if defined(__BIONIC__)
  44. static void ResetFlag(const char* key, const char* value, void* cookie) {
  45. if (strcmp(ATTEMPTED_BOOT_COUNT_PROPERTY, key) &&
  46. android::base::StartsWith(key, SYSTEM_PROPERTY_PREFIX) && strlen(value) > 0 &&
  47. android::base::SetProperty(key, "")) {
  48. std::string* reset_flags = static_cast<std::string*>(cookie);
  49. if (reset_flags->length() > 0) {
  50. reset_flags->append(";");
  51. }
  52. reset_flags->append(key);
  53. android::base::SetProperty(RESET_PERFORMED_PROPERTY, "true");
  54. }
  55. }
  56. // Reset all system properties used as flags into empty value,
  57. // and record reset flags' names in /data/server_configurable_flags/reset_flags
  58. static void ResetAllFlags() {
  59. std::string reset_flags;
  60. property_list(ResetFlag, &reset_flags);
  61. if (reset_flags.length() > 0) {
  62. android::base::unique_fd fd(
  63. TEMP_FAILURE_RETRY(open(RESET_FLAGS_FILE_PATH, O_RDWR | O_CREAT | O_TRUNC, 0666)));
  64. if (fd == -1) {
  65. LOG(INFO) << __FUNCTION__ << " failed to open file " << RESET_FLAGS_FILE_PATH;
  66. } else if (!WriteStringToFd(reset_flags, fd)) {
  67. LOG(INFO) << __FUNCTION__ << " failed to write file " << RESET_FLAGS_FILE_PATH;
  68. } else {
  69. LOG(INFO) << __FUNCTION__ << " successfully write to file " << RESET_FLAGS_FILE_PATH;
  70. }
  71. }
  72. }
  73. #endif // __BIONIC__
  74. void ServerConfigurableFlagsReset(ResetMode reset_mode) {
  75. LOG(INFO) << __FUNCTION__ << " reset_mode value: " << reset_mode;
  76. #if defined(__BIONIC__)
  77. if (reset_mode == BOOT_FAILURE) {
  78. int fail_count = android::base::GetIntProperty(ATTEMPTED_BOOT_COUNT_PROPERTY, 0);
  79. if (fail_count < ATTEMPTED_BOOT_COUNT_THRESHOLD) {
  80. LOG(INFO) << __FUNCTION__ << " attempted boot count is under threshold, skipping reset.";
  81. // ATTEMPTED_BOOT_COUNT_PROPERTY will be reset to 0 when sys.boot_completed is set to 1.
  82. // The code lives in flags_health_check.rc.
  83. android::base::SetProperty(ATTEMPTED_BOOT_COUNT_PROPERTY, std::to_string(fail_count + 1));
  84. } else {
  85. LOG(INFO) << __FUNCTION__ << " attempted boot count reaches threshold, resetting flags.";
  86. ResetAllFlags();
  87. }
  88. } else if (reset_mode == UPDATABLE_CRASHING) {
  89. LOG(INFO) << __FUNCTION__ << " updatable crashing detected, resetting flags.";
  90. ResetAllFlags();
  91. } else {
  92. LOG(ERROR) << __FUNCTION__ << " invalid reset_mode, skipping reset.";
  93. }
  94. #else
  95. LOG(ERROR) << __FUNCTION__ << " ServerConfigurableFlagsReset is not available for this build.";
  96. #endif // __BIONIC__
  97. }
  98. std::string GetServerConfigurableFlag(const std::string& experiment_category_name,
  99. const std::string& experiment_flag_name,
  100. const std::string& default_value) {
  101. if (!ValidateExperimentSegment(experiment_category_name)) {
  102. LOG(ERROR) << __FUNCTION__ << " invalid category name " << experiment_category_name;
  103. return default_value;
  104. }
  105. if (!ValidateExperimentSegment(experiment_flag_name)) {
  106. LOG(ERROR) << __FUNCTION__ << " invalid flag name " << experiment_flag_name;
  107. return default_value;
  108. }
  109. return android::base::GetProperty(
  110. MakeSystemPropertyName(experiment_category_name, experiment_flag_name), default_value);
  111. }
  112. } // namespace server_configurable_flags