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