summaryrefslogtreecommitdiff
path: root/odrefresh/odr_config.h
blob: eb819ee29d6624c108628b7d973803883e723b2d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
/*
 * 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.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<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(); }

  // Return a given property's value if it exists in the map.
  std::optional<std::string> GetOrNull(const std::string& key) const {
    auto it = system_properties_->find(key);
    return it != system_properties_->end() ? std::make_optional(it->second) : std::nullopt;
  }

 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;
  bool only_boot_images_ = 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_;

 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_;
  }
  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<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_