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