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