| /* |
| * 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 <algorithm> |
| #include <optional> |
| #include <string> |
| #include <unordered_map> |
| #include <unordered_set> |
| #include <vector> |
| |
| #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<std::string> 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<std::vector<SystemPropertyConfig>> kSystemProperties{ |
| {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<std::string, std::string>* 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<std::string, std::string>* 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<bool> refresh_; |
| std::optional<bool> 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; |
| |
| // The current values of system properties listed in `kSystemProperties`. |
| std::unordered_map<std::string, std::string> system_properties_; |
| |
| // A helper for reading from `system_properties_`. |
| OdrSystemProperties odr_system_properties_; |
| |
| // Staging directory for artifacts. The directory must exist and will be automatically removed |
| // after compilation. If empty, use the default directory. |
| std::string staging_dir_; |
| |
| 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<InstructionSet> 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_; |
| } |
| const std::string& GetStagingDir() const { |
| return staging_dir_; |
| } |
| bool GetCompilationOsMode() const { return compilation_os_mode_; } |
| bool GetMinimal() const { return minimal_; } |
| 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; } |
| |
| void SetStagingDir(const std::string& staging_dir) { |
| staging_dir_ = staging_dir; |
| } |
| |
| 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; } |
| |
| std::unordered_map<std::string, std::string>* 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<InstructionSet, InstructionSet> 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_ |