/* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ART_ODREFRESH_ODR_CONFIG_H_ #define ART_ODREFRESH_ODR_CONFIG_H_ #include #include #include #include #include #include #include "android-base/file.h" #include "android-base/no_destructor.h" #include "android-base/strings.h" #include "arch/instruction_set.h" #include "base/file_utils.h" #include "base/globals.h" #include "log/log.h" #include "odr_common.h" #include "odrefresh/odrefresh.h" #include "tools/system_properties.h" namespace art { namespace odrefresh { // The prefixes of system properties that odrefresh keeps track of. Odrefresh will recompile // everything if any property matching a prefix changes. constexpr const char* kCheckedSystemPropertyPrefixes[]{"dalvik.vm.", "ro.dalvik.vm."}; // System property for the phenotype flag to override the device or default-configured // system server compiler filter setting. static constexpr char kSystemPropertySystemServerCompilerFilterOverride[] = "persist.device_config.runtime_native_boot.systemservercompilerfilter_override"; // The list of system properties that odrefresh ignores. They don't affect compilation results. const std::unordered_set kIgnoredSystemProperties{ "dalvik.vm.dex2oat-cpu-set", "dalvik.vm.dex2oat-threads", "dalvik.vm.boot-dex2oat-cpu-set", "dalvik.vm.boot-dex2oat-threads", "dalvik.vm.restore-dex2oat-cpu-set", "dalvik.vm.restore-dex2oat-threads", "dalvik.vm.background-dex2oat-cpu-set", "dalvik.vm.background-dex2oat-threads"}; struct SystemPropertyConfig { const char* name; const char* default_value; }; // The system properties that odrefresh keeps track of, in addition to the ones matching the // prefixes in `kCheckedSystemPropertyPrefixes`. Odrefresh will recompile everything if any property // changes. // All phenotype flags under the `runtime_native_boot` namespace that affects the compiler's // behavior must be explicitly listed below. We cannot use a prefix to match all phenotype flags // because a default value is required for each flag. Changing the flag value from empty to the // default value should not trigger re-compilation. This is to comply with the phenotype flag // requirement (go/platform-experiments-flags#pre-requisites). const android::base::NoDestructor> kSystemProperties{ {SystemPropertyConfig{.name = "persist.device_config.runtime_native_boot.enable_uffd_gc_2", .default_value = "false"}, SystemPropertyConfig{.name = "persist.device_config.runtime_native_boot.force_disable_uffd_gc", .default_value = "false"}, SystemPropertyConfig{.name = kSystemPropertySystemServerCompilerFilterOverride, .default_value = ""}, // For testing only (cf. odsign_e2e_tests_full). SystemPropertyConfig{.name = "persist.device_config.runtime_native_boot.odrefresh_test_toggle", .default_value = "false"}}}; // An enumeration of the possible zygote configurations on Android. enum class ZygoteKind : uint8_t { // 32-bit primary zygote, no secondary zygote. kZygote32 = 0, // 32-bit primary zygote, 64-bit secondary zygote. kZygote32_64 = 1, // 64-bit primary zygote, 32-bit secondary zygote. kZygote64_32 = 2, // 64-bit primary zygote, no secondary zygote. kZygote64 = 3 }; class OdrSystemProperties : public tools::SystemProperties { public: explicit OdrSystemProperties( const std::unordered_map* system_properties) : system_properties_(system_properties) {} // For supporting foreach loops. auto begin() const { return system_properties_->begin(); } auto end() const { return system_properties_->end(); } protected: std::string GetProperty(const std::string& key) const override { auto it = system_properties_->find(key); return it != system_properties_->end() ? it->second : ""; } private: const std::unordered_map* system_properties_; }; // Configuration class for odrefresh. Exists to enable abstracting environment variables and // system properties into a configuration class for development and testing purposes. class OdrConfig final { private: std::string apex_info_list_file_; std::string art_bin_dir_; std::string dex2oat_; std::string dex2oat_boot_classpath_; bool dry_run_; std::optional refresh_; std::optional partial_compilation_; InstructionSet isa_; std::string program_name_; std::string system_server_classpath_; std::string boot_image_compiler_filter_; std::string system_server_compiler_filter_; ZygoteKind zygote_kind_; std::string boot_classpath_; std::string artifact_dir_; std::string standalone_system_server_jars_; bool compilation_os_mode_ = false; bool minimal_ = false; bool only_boot_images_ = false; // The current values of system properties listed in `kSystemProperties`. std::unordered_map system_properties_; // A helper for reading from `system_properties_`. OdrSystemProperties odr_system_properties_; public: explicit OdrConfig(const char* program_name) : dry_run_(false), isa_(InstructionSet::kNone), program_name_(android::base::Basename(program_name)), artifact_dir_(GetApexDataDalvikCacheDirectory(InstructionSet::kNone)), odr_system_properties_(&system_properties_) {} const std::string& GetApexInfoListFile() const { return apex_info_list_file_; } std::vector GetBootClasspathIsas() const { const auto [isa32, isa64] = GetPotentialInstructionSets(); switch (zygote_kind_) { case ZygoteKind::kZygote32: CHECK_NE(isa32, art::InstructionSet::kNone); return {isa32}; case ZygoteKind::kZygote32_64: CHECK_NE(isa32, art::InstructionSet::kNone); CHECK_NE(isa64, art::InstructionSet::kNone); return {isa32, isa64}; case ZygoteKind::kZygote64_32: CHECK_NE(isa32, art::InstructionSet::kNone); CHECK_NE(isa64, art::InstructionSet::kNone); return {isa64, isa32}; case ZygoteKind::kZygote64: CHECK_NE(isa64, art::InstructionSet::kNone); return {isa64}; } } InstructionSet GetSystemServerIsa() const { const auto [isa32, isa64] = GetPotentialInstructionSets(); switch (zygote_kind_) { case ZygoteKind::kZygote32: case ZygoteKind::kZygote32_64: CHECK_NE(isa32, art::InstructionSet::kNone); return isa32; case ZygoteKind::kZygote64_32: case ZygoteKind::kZygote64: CHECK_NE(isa64, art::InstructionSet::kNone); return isa64; } } const std::string& GetDex2oatBootClasspath() const { return dex2oat_boot_classpath_; } const std::string& GetArtifactDirectory() const { return artifact_dir_; } std::string GetDex2Oat() const { const char* prefix = UseDebugBinaries() ? "dex2oatd" : "dex2oat"; const char* suffix = ""; if (kIsTargetBuild) { switch (zygote_kind_) { case ZygoteKind::kZygote32: suffix = "32"; break; case ZygoteKind::kZygote32_64: case ZygoteKind::kZygote64_32: case ZygoteKind::kZygote64: suffix = "64"; break; } } return art_bin_dir_ + '/' + prefix + suffix; } bool GetDryRun() const { return dry_run_; } bool HasPartialCompilation() const { return partial_compilation_.has_value(); } bool GetPartialCompilation() const { return partial_compilation_.value_or(true); } bool GetRefresh() const { return refresh_.value_or(true); } const std::string& GetSystemServerClasspath() const { return system_server_classpath_; } const std::string& GetBootImageCompilerFilter() const { return boot_image_compiler_filter_; } const std::string& GetSystemServerCompilerFilter() const { return system_server_compiler_filter_; } bool GetCompilationOsMode() const { return compilation_os_mode_; } bool GetMinimal() const { return minimal_; } bool GetOnlyBootImages() const { return only_boot_images_; } const OdrSystemProperties& GetSystemProperties() const { return odr_system_properties_; } void SetApexInfoListFile(const std::string& file_path) { apex_info_list_file_ = file_path; } void SetArtBinDir(const std::string& art_bin_dir) { art_bin_dir_ = art_bin_dir; } void SetDex2oatBootclasspath(const std::string& classpath) { dex2oat_boot_classpath_ = classpath; } void SetArtifactDirectory(const std::string& artifact_dir) { artifact_dir_ = artifact_dir; } void SetDryRun() { dry_run_ = true; } void SetPartialCompilation(bool value) { partial_compilation_ = value; } void SetRefresh(bool value) { refresh_ = value; } void SetIsa(const InstructionSet isa) { isa_ = isa; } void SetSystemServerClasspath(const std::string& classpath) { system_server_classpath_ = classpath; } void SetBootImageCompilerFilter(const std::string& filter) { boot_image_compiler_filter_ = filter; } void SetSystemServerCompilerFilter(const std::string& filter) { system_server_compiler_filter_ = filter; } void SetZygoteKind(ZygoteKind zygote_kind) { zygote_kind_ = zygote_kind; } const std::string& GetBootClasspath() const { return boot_classpath_; } void SetBootClasspath(const std::string& classpath) { boot_classpath_ = classpath; } const std::string& GetStandaloneSystemServerJars() const { return standalone_system_server_jars_; } void SetStandaloneSystemServerJars(const std::string& jars) { standalone_system_server_jars_ = jars; } void SetCompilationOsMode(bool value) { compilation_os_mode_ = value; } void SetMinimal(bool value) { minimal_ = value; } void SetOnlyBootImages(bool value) { only_boot_images_ = value; } std::unordered_map* MutableSystemProperties() { return &system_properties_; } private: // Returns a pair for the possible instruction sets for the configured instruction set // architecture. The first item is the 32-bit architecture and the second item is the 64-bit // architecture. The current `isa` is based on `kRuntimeISA` on target, odrefresh is compiled // 32-bit by default so this method returns all options which are finessed based on the // `ro.zygote` property. std::pair GetPotentialInstructionSets() const { switch (isa_) { case art::InstructionSet::kArm: case art::InstructionSet::kArm64: return std::make_pair(art::InstructionSet::kArm, art::InstructionSet::kArm64); case art::InstructionSet::kX86: case art::InstructionSet::kX86_64: return std::make_pair(art::InstructionSet::kX86, art::InstructionSet::kX86_64); case art::InstructionSet::kRiscv64: return std::make_pair(art::InstructionSet::kNone, art::InstructionSet::kRiscv64); case art::InstructionSet::kThumb2: case art::InstructionSet::kNone: LOG(FATAL) << "Invalid instruction set " << isa_; return std::make_pair(art::InstructionSet::kNone, art::InstructionSet::kNone); } } bool UseDebugBinaries() const { return program_name_ == "odrefreshd"; } OdrConfig() = delete; OdrConfig(const OdrConfig&) = delete; OdrConfig& operator=(const OdrConfig&) = delete; }; } // namespace odrefresh } // namespace art #endif // ART_ODREFRESH_ODR_CONFIG_H_