• 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