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