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