1 /* 2 * Copyright (C) 2021 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 #ifndef ART_ODREFRESH_ODR_CONFIG_H_ 18 #define ART_ODREFRESH_ODR_CONFIG_H_ 19 20 #include <algorithm> 21 #include <optional> 22 #include <string> 23 #include <unordered_map> 24 #include <unordered_set> 25 #include <vector> 26 27 #include "android-base/file.h" 28 #include "android-base/no_destructor.h" 29 #include "android-base/strings.h" 30 #include "arch/instruction_set.h" 31 #include "base/file_utils.h" 32 #include "base/globals.h" 33 #include "log/log.h" 34 #include "odr_common.h" 35 #include "odrefresh/odrefresh.h" 36 #include "tools/system_properties.h" 37 38 namespace art { 39 namespace odrefresh { 40 41 // The prefixes of system properties that odrefresh keeps track of. Odrefresh will recompile 42 // everything if any property matching a prefix changes. 43 constexpr const char* kCheckedSystemPropertyPrefixes[]{"dalvik.vm.", "ro.dalvik.vm."}; 44 45 // System property for the phenotype flag to override the device or default-configured 46 // system server compiler filter setting. 47 static constexpr char kSystemPropertySystemServerCompilerFilterOverride[] = 48 "persist.device_config.runtime_native_boot.systemservercompilerfilter_override"; 49 50 // The list of system properties that odrefresh ignores. They don't affect compilation results. 51 const std::unordered_set<std::string> kIgnoredSystemProperties{ 52 "dalvik.vm.dex2oat-cpu-set", 53 "dalvik.vm.dex2oat-threads", 54 "dalvik.vm.boot-dex2oat-cpu-set", 55 "dalvik.vm.boot-dex2oat-threads", 56 "dalvik.vm.restore-dex2oat-cpu-set", 57 "dalvik.vm.restore-dex2oat-threads", 58 "dalvik.vm.background-dex2oat-cpu-set", 59 "dalvik.vm.background-dex2oat-threads"}; 60 61 struct SystemPropertyConfig { 62 const char* name; 63 const char* default_value; 64 }; 65 66 // The system properties that odrefresh keeps track of, in addition to the ones matching the 67 // prefixes in `kCheckedSystemPropertyPrefixes`. Odrefresh will recompile everything if any property 68 // changes. 69 // All phenotype flags under the `runtime_native_boot` namespace that affects the compiler's 70 // behavior must be explicitly listed below. We cannot use a prefix to match all phenotype flags 71 // because a default value is required for each flag. Changing the flag value from empty to the 72 // default value should not trigger re-compilation. This is to comply with the phenotype flag 73 // requirement (go/platform-experiments-flags#pre-requisites). 74 const android::base::NoDestructor<std::vector<SystemPropertyConfig>> kSystemProperties{ 75 {SystemPropertyConfig{.name = "persist.device_config.runtime_native_boot.enable_uffd_gc_2", 76 .default_value = "false"}, 77 SystemPropertyConfig{.name = "persist.device_config.runtime_native_boot.force_disable_uffd_gc", 78 .default_value = "false"}, 79 SystemPropertyConfig{.name = kSystemPropertySystemServerCompilerFilterOverride, 80 .default_value = ""}, 81 // For testing only (cf. odsign_e2e_tests_full). 82 SystemPropertyConfig{.name = "persist.device_config.runtime_native_boot.odrefresh_test_toggle", 83 .default_value = "false"}}}; 84 85 // An enumeration of the possible zygote configurations on Android. 86 enum class ZygoteKind : uint8_t { 87 // 32-bit primary zygote, no secondary zygote. 88 kZygote32 = 0, 89 // 32-bit primary zygote, 64-bit secondary zygote. 90 kZygote32_64 = 1, 91 // 64-bit primary zygote, 32-bit secondary zygote. 92 kZygote64_32 = 2, 93 // 64-bit primary zygote, no secondary zygote. 94 kZygote64 = 3 95 }; 96 97 class OdrSystemProperties : public tools::SystemProperties { 98 public: OdrSystemProperties(const std::unordered_map<std::string,std::string> * system_properties)99 explicit OdrSystemProperties( 100 const std::unordered_map<std::string, std::string>* system_properties) 101 : system_properties_(system_properties) {} 102 103 // For supporting foreach loops. begin()104 auto begin() const { return system_properties_->begin(); } end()105 auto end() const { return system_properties_->end(); } 106 107 protected: GetProperty(const std::string & key)108 std::string GetProperty(const std::string& key) const override { 109 auto it = system_properties_->find(key); 110 return it != system_properties_->end() ? it->second : ""; 111 } 112 113 private: 114 const std::unordered_map<std::string, std::string>* system_properties_; 115 }; 116 117 // Configuration class for odrefresh. Exists to enable abstracting environment variables and 118 // system properties into a configuration class for development and testing purposes. 119 class OdrConfig final { 120 private: 121 std::string apex_info_list_file_; 122 std::string art_bin_dir_; 123 std::string dex2oat_; 124 std::string dex2oat_boot_classpath_; 125 bool dry_run_; 126 std::optional<bool> refresh_; 127 std::optional<bool> partial_compilation_; 128 InstructionSet isa_; 129 std::string program_name_; 130 std::string system_server_classpath_; 131 std::string boot_image_compiler_filter_; 132 std::string system_server_compiler_filter_; 133 ZygoteKind zygote_kind_; 134 std::string boot_classpath_; 135 std::string artifact_dir_; 136 std::string standalone_system_server_jars_; 137 bool compilation_os_mode_ = false; 138 bool minimal_ = false; 139 bool only_boot_images_ = false; 140 141 // The current values of system properties listed in `kSystemProperties`. 142 std::unordered_map<std::string, std::string> system_properties_; 143 144 // A helper for reading from `system_properties_`. 145 OdrSystemProperties odr_system_properties_; 146 147 public: OdrConfig(const char * program_name)148 explicit OdrConfig(const char* program_name) 149 : dry_run_(false), 150 isa_(InstructionSet::kNone), 151 program_name_(android::base::Basename(program_name)), 152 artifact_dir_(GetApexDataDalvikCacheDirectory(InstructionSet::kNone)), 153 odr_system_properties_(&system_properties_) {} 154 GetApexInfoListFile()155 const std::string& GetApexInfoListFile() const { return apex_info_list_file_; } 156 GetBootClasspathIsas()157 std::vector<InstructionSet> GetBootClasspathIsas() const { 158 const auto [isa32, isa64] = GetPotentialInstructionSets(); 159 switch (zygote_kind_) { 160 case ZygoteKind::kZygote32: 161 CHECK_NE(isa32, art::InstructionSet::kNone); 162 return {isa32}; 163 case ZygoteKind::kZygote32_64: 164 CHECK_NE(isa32, art::InstructionSet::kNone); 165 CHECK_NE(isa64, art::InstructionSet::kNone); 166 return {isa32, isa64}; 167 case ZygoteKind::kZygote64_32: 168 CHECK_NE(isa32, art::InstructionSet::kNone); 169 CHECK_NE(isa64, art::InstructionSet::kNone); 170 return {isa64, isa32}; 171 case ZygoteKind::kZygote64: 172 CHECK_NE(isa64, art::InstructionSet::kNone); 173 return {isa64}; 174 } 175 } 176 GetSystemServerIsa()177 InstructionSet GetSystemServerIsa() const { 178 const auto [isa32, isa64] = GetPotentialInstructionSets(); 179 switch (zygote_kind_) { 180 case ZygoteKind::kZygote32: 181 case ZygoteKind::kZygote32_64: 182 CHECK_NE(isa32, art::InstructionSet::kNone); 183 return isa32; 184 case ZygoteKind::kZygote64_32: 185 case ZygoteKind::kZygote64: 186 CHECK_NE(isa64, art::InstructionSet::kNone); 187 return isa64; 188 } 189 } 190 GetDex2oatBootClasspath()191 const std::string& GetDex2oatBootClasspath() const { return dex2oat_boot_classpath_; } 192 GetArtifactDirectory()193 const std::string& GetArtifactDirectory() const { return artifact_dir_; } 194 GetDex2Oat()195 std::string GetDex2Oat() const { 196 const char* prefix = UseDebugBinaries() ? "dex2oatd" : "dex2oat"; 197 const char* suffix = ""; 198 if (kIsTargetBuild) { 199 switch (zygote_kind_) { 200 case ZygoteKind::kZygote32: 201 suffix = "32"; 202 break; 203 case ZygoteKind::kZygote32_64: 204 case ZygoteKind::kZygote64_32: 205 case ZygoteKind::kZygote64: 206 suffix = "64"; 207 break; 208 } 209 } 210 return art_bin_dir_ + '/' + prefix + suffix; 211 } 212 GetDryRun()213 bool GetDryRun() const { return dry_run_; } HasPartialCompilation()214 bool HasPartialCompilation() const { 215 return partial_compilation_.has_value(); 216 } GetPartialCompilation()217 bool GetPartialCompilation() const { 218 return partial_compilation_.value_or(true); 219 } GetRefresh()220 bool GetRefresh() const { 221 return refresh_.value_or(true); 222 } GetSystemServerClasspath()223 const std::string& GetSystemServerClasspath() const { 224 return system_server_classpath_; 225 } GetBootImageCompilerFilter()226 const std::string& GetBootImageCompilerFilter() const { 227 return boot_image_compiler_filter_; 228 } GetSystemServerCompilerFilter()229 const std::string& GetSystemServerCompilerFilter() const { 230 return system_server_compiler_filter_; 231 } GetCompilationOsMode()232 bool GetCompilationOsMode() const { return compilation_os_mode_; } GetMinimal()233 bool GetMinimal() const { return minimal_; } GetOnlyBootImages()234 bool GetOnlyBootImages() const { return only_boot_images_; } GetSystemProperties()235 const OdrSystemProperties& GetSystemProperties() const { return odr_system_properties_; } 236 SetApexInfoListFile(const std::string & file_path)237 void SetApexInfoListFile(const std::string& file_path) { apex_info_list_file_ = file_path; } SetArtBinDir(const std::string & art_bin_dir)238 void SetArtBinDir(const std::string& art_bin_dir) { art_bin_dir_ = art_bin_dir; } 239 SetDex2oatBootclasspath(const std::string & classpath)240 void SetDex2oatBootclasspath(const std::string& classpath) { 241 dex2oat_boot_classpath_ = classpath; 242 } 243 SetArtifactDirectory(const std::string & artifact_dir)244 void SetArtifactDirectory(const std::string& artifact_dir) { 245 artifact_dir_ = artifact_dir; 246 } 247 SetDryRun()248 void SetDryRun() { dry_run_ = true; } SetPartialCompilation(bool value)249 void SetPartialCompilation(bool value) { 250 partial_compilation_ = value; 251 } SetRefresh(bool value)252 void SetRefresh(bool value) { 253 refresh_ = value; 254 } SetIsa(const InstructionSet isa)255 void SetIsa(const InstructionSet isa) { isa_ = isa; } 256 SetSystemServerClasspath(const std::string & classpath)257 void SetSystemServerClasspath(const std::string& classpath) { 258 system_server_classpath_ = classpath; 259 } 260 SetBootImageCompilerFilter(const std::string & filter)261 void SetBootImageCompilerFilter(const std::string& filter) { 262 boot_image_compiler_filter_ = filter; 263 } SetSystemServerCompilerFilter(const std::string & filter)264 void SetSystemServerCompilerFilter(const std::string& filter) { 265 system_server_compiler_filter_ = filter; 266 } 267 SetZygoteKind(ZygoteKind zygote_kind)268 void SetZygoteKind(ZygoteKind zygote_kind) { zygote_kind_ = zygote_kind; } 269 GetBootClasspath()270 const std::string& GetBootClasspath() const { return boot_classpath_; } 271 SetBootClasspath(const std::string & classpath)272 void SetBootClasspath(const std::string& classpath) { boot_classpath_ = classpath; } 273 GetStandaloneSystemServerJars()274 const std::string& GetStandaloneSystemServerJars() const { 275 return standalone_system_server_jars_; 276 } 277 SetStandaloneSystemServerJars(const std::string & jars)278 void SetStandaloneSystemServerJars(const std::string& jars) { 279 standalone_system_server_jars_ = jars; 280 } 281 SetCompilationOsMode(bool value)282 void SetCompilationOsMode(bool value) { compilation_os_mode_ = value; } 283 SetMinimal(bool value)284 void SetMinimal(bool value) { minimal_ = value; } 285 SetOnlyBootImages(bool value)286 void SetOnlyBootImages(bool value) { only_boot_images_ = value; } 287 MutableSystemProperties()288 std::unordered_map<std::string, std::string>* MutableSystemProperties() { 289 return &system_properties_; 290 } 291 292 private: 293 // Returns a pair for the possible instruction sets for the configured instruction set 294 // architecture. The first item is the 32-bit architecture and the second item is the 64-bit 295 // architecture. The current `isa` is based on `kRuntimeISA` on target, odrefresh is compiled 296 // 32-bit by default so this method returns all options which are finessed based on the 297 // `ro.zygote` property. GetPotentialInstructionSets()298 std::pair<InstructionSet, InstructionSet> GetPotentialInstructionSets() const { 299 switch (isa_) { 300 case art::InstructionSet::kArm: 301 case art::InstructionSet::kArm64: 302 return std::make_pair(art::InstructionSet::kArm, art::InstructionSet::kArm64); 303 case art::InstructionSet::kX86: 304 case art::InstructionSet::kX86_64: 305 return std::make_pair(art::InstructionSet::kX86, art::InstructionSet::kX86_64); 306 case art::InstructionSet::kRiscv64: 307 return std::make_pair(art::InstructionSet::kNone, art::InstructionSet::kRiscv64); 308 case art::InstructionSet::kThumb2: 309 case art::InstructionSet::kNone: 310 LOG(FATAL) << "Invalid instruction set " << isa_; 311 return std::make_pair(art::InstructionSet::kNone, art::InstructionSet::kNone); 312 } 313 } 314 UseDebugBinaries()315 bool UseDebugBinaries() const { return program_name_ == "odrefreshd"; } 316 317 OdrConfig() = delete; 318 OdrConfig(const OdrConfig&) = delete; 319 OdrConfig& operator=(const OdrConfig&) = delete; 320 }; 321 322 } // namespace odrefresh 323 } // namespace art 324 325 #endif // ART_ODREFRESH_ODR_CONFIG_H_ 326