Victor Hsieh | c9821f1 | 2020-08-07 11:32:29 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2020 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 | #define LOG_TAG "installd" |
| 17 | |
| 18 | #include "run_dex2oat.h" |
| 19 | |
| 20 | #include <memory> |
| 21 | #include <string> |
| 22 | #include <vector> |
| 23 | |
| 24 | #include <android-base/file.h> |
| 25 | #include <android-base/logging.h> |
| 26 | #include <android-base/properties.h> |
| 27 | #include <android-base/scopeguard.h> |
| 28 | #include <android-base/stringprintf.h> |
| 29 | #include <android-base/strings.h> |
| 30 | #include <log/log.h> |
| 31 | #include <server_configurable_flags/get_flags.h> |
| 32 | |
Victor Hsieh | cb35a06 | 2020-08-13 16:11:13 -0700 | [diff] [blame] | 33 | #include "unique_file.h" |
| 34 | |
Victor Hsieh | c9821f1 | 2020-08-07 11:32:29 -0700 | [diff] [blame] | 35 | using android::base::Basename; |
| 36 | using android::base::StringPrintf; |
| 37 | |
| 38 | namespace android { |
| 39 | namespace installd { |
| 40 | |
| 41 | namespace { |
| 42 | |
| 43 | // Should minidebug info be included in compiled artifacts? Even if this value is |
| 44 | // "true," usage might still be conditional to other constraints, e.g., system |
| 45 | // property overrides. |
| 46 | static constexpr bool kEnableMinidebugInfo = true; |
| 47 | |
| 48 | static constexpr const char* kMinidebugInfoSystemProperty = "dalvik.vm.dex2oat-minidebuginfo"; |
| 49 | static constexpr bool kMinidebugInfoSystemPropertyDefault = false; |
| 50 | static constexpr const char* kMinidebugDex2oatFlag = "--generate-mini-debug-info"; |
| 51 | static constexpr const char* kDisableCompactDexFlag = "--compact-dex-level=none"; |
| 52 | |
| 53 | // Location of the JIT Zygote image. |
| 54 | static const char* kJitZygoteImage = |
| 55 | "boot.art:/nonx/boot-framework.art!/system/etc/boot-image.prof"; |
| 56 | |
| 57 | std::vector<std::string> SplitBySpaces(const std::string& str) { |
| 58 | if (str.empty()) { |
| 59 | return {}; |
| 60 | } |
| 61 | return android::base::Split(str, " "); |
| 62 | } |
| 63 | |
| 64 | } // namespace |
| 65 | |
| 66 | RunDex2Oat::RunDex2Oat(const char* dex2oat_bin, ExecVHelper* execv_helper) |
| 67 | : dex2oat_bin_(dex2oat_bin), execv_helper_(execv_helper) {} |
| 68 | |
Victor Hsieh | cb35a06 | 2020-08-13 16:11:13 -0700 | [diff] [blame] | 69 | void RunDex2Oat::Initialize(const UniqueFile& output_oat, |
| 70 | const UniqueFile& output_vdex, |
| 71 | const UniqueFile& output_image, |
| 72 | const UniqueFile& input_dex, |
| 73 | const UniqueFile& input_vdex, |
| 74 | const UniqueFile& dex_metadata, |
| 75 | const UniqueFile& profile, |
| 76 | const char* class_loader_context, |
| 77 | const std::string& class_loader_context_fds, |
Victor Hsieh | c9821f1 | 2020-08-07 11:32:29 -0700 | [diff] [blame] | 78 | int swap_fd, |
| 79 | const char* instruction_set, |
| 80 | const char* compiler_filter, |
| 81 | bool debuggable, |
| 82 | bool post_bootcomplete, |
| 83 | bool for_restore, |
Victor Hsieh | c9821f1 | 2020-08-07 11:32:29 -0700 | [diff] [blame] | 84 | int target_sdk_version, |
| 85 | bool enable_hidden_api_checks, |
| 86 | bool generate_compact_dex, |
Victor Hsieh | c9821f1 | 2020-08-07 11:32:29 -0700 | [diff] [blame] | 87 | bool use_jitzygote_image, |
| 88 | const char* compilation_reason) { |
Nicolas Geoffray | a69482e | 2021-03-29 10:53:55 +0100 | [diff] [blame] | 89 | PrepareBootImageFlags(use_jitzygote_image); |
Victor Hsieh | c9821f1 | 2020-08-07 11:32:29 -0700 | [diff] [blame] | 90 | |
Victor Hsieh | cb35a06 | 2020-08-13 16:11:13 -0700 | [diff] [blame] | 91 | PrepareInputFileFlags(output_oat, output_vdex, output_image, input_dex, input_vdex, |
| 92 | dex_metadata, profile, swap_fd, class_loader_context, |
| 93 | class_loader_context_fds); |
Victor Hsieh | c9821f1 | 2020-08-07 11:32:29 -0700 | [diff] [blame] | 94 | |
Victor Hsieh | cb35a06 | 2020-08-13 16:11:13 -0700 | [diff] [blame] | 95 | PrepareCompilerConfigFlags(input_vdex, output_vdex, instruction_set, compiler_filter, |
Victor Hsieh | b345940 | 2020-07-07 12:34:54 -0700 | [diff] [blame] | 96 | debuggable, target_sdk_version, enable_hidden_api_checks, |
| 97 | generate_compact_dex, compilation_reason); |
Victor Hsieh | c9821f1 | 2020-08-07 11:32:29 -0700 | [diff] [blame] | 98 | |
Victor Hsieh | b345940 | 2020-07-07 12:34:54 -0700 | [diff] [blame] | 99 | PrepareCompilerRuntimeAndPerfConfigFlags(post_bootcomplete, for_restore); |
Victor Hsieh | c9821f1 | 2020-08-07 11:32:29 -0700 | [diff] [blame] | 100 | |
| 101 | const std::string dex2oat_flags = GetProperty("dalvik.vm.dex2oat-flags", ""); |
| 102 | std::vector<std::string> dex2oat_flags_args = SplitBySpaces(dex2oat_flags); |
| 103 | ALOGV("dalvik.vm.dex2oat-flags=%s\n", dex2oat_flags.c_str()); |
| 104 | |
Victor Hsieh | c9821f1 | 2020-08-07 11:32:29 -0700 | [diff] [blame] | 105 | // Do not add args after dex2oat_flags, they should override others for debugging. |
| 106 | for (auto it = dex2oat_flags_args.begin(); it != dex2oat_flags_args.end(); ++it) { |
| 107 | AddArg(*it); |
| 108 | } |
| 109 | |
| 110 | execv_helper_->PrepareArgs(dex2oat_bin_); |
| 111 | } |
| 112 | |
| 113 | RunDex2Oat::~RunDex2Oat() {} |
| 114 | |
Nicolas Geoffray | a69482e | 2021-03-29 10:53:55 +0100 | [diff] [blame] | 115 | void RunDex2Oat::PrepareBootImageFlags(bool use_jitzygote_image) { |
Victor Hsieh | b345940 | 2020-07-07 12:34:54 -0700 | [diff] [blame] | 116 | std::string boot_image; |
| 117 | if (use_jitzygote_image) { |
| 118 | boot_image = StringPrintf("--boot-image=%s", kJitZygoteImage); |
| 119 | } else { |
| 120 | boot_image = MapPropertyToArg("dalvik.vm.boot-image", "--boot-image=%s"); |
| 121 | } |
| 122 | AddArg(boot_image); |
Victor Hsieh | b345940 | 2020-07-07 12:34:54 -0700 | [diff] [blame] | 123 | } |
| 124 | |
Victor Hsieh | cb35a06 | 2020-08-13 16:11:13 -0700 | [diff] [blame] | 125 | void RunDex2Oat::PrepareInputFileFlags(const UniqueFile& output_oat, |
| 126 | const UniqueFile& output_vdex, |
| 127 | const UniqueFile& output_image, |
| 128 | const UniqueFile& input_dex, |
| 129 | const UniqueFile& input_vdex, |
| 130 | const UniqueFile& dex_metadata, |
| 131 | const UniqueFile& profile, |
Victor Hsieh | b345940 | 2020-07-07 12:34:54 -0700 | [diff] [blame] | 132 | int swap_fd, |
| 133 | const char* class_loader_context, |
| 134 | const std::string& class_loader_context_fds) { |
Victor Hsieh | cb35a06 | 2020-08-13 16:11:13 -0700 | [diff] [blame] | 135 | std::string input_basename = Basename(input_dex.path()); |
| 136 | LOG(VERBOSE) << "Running " << dex2oat_bin_ << " in=" << input_basename << " out=" |
| 137 | << output_oat.path(); |
Victor Hsieh | b345940 | 2020-07-07 12:34:54 -0700 | [diff] [blame] | 138 | |
Victor Hsieh | cb35a06 | 2020-08-13 16:11:13 -0700 | [diff] [blame] | 139 | AddArg(StringPrintf("--zip-fd=%d", input_dex.fd())); |
Victor Hsieh | b345940 | 2020-07-07 12:34:54 -0700 | [diff] [blame] | 140 | AddArg(StringPrintf("--zip-location=%s", input_basename.c_str())); |
Victor Hsieh | cb35a06 | 2020-08-13 16:11:13 -0700 | [diff] [blame] | 141 | AddArg(StringPrintf("--oat-fd=%d", output_oat.fd())); |
| 142 | AddArg(StringPrintf("--oat-location=%s", output_oat.path().c_str())); |
| 143 | AddArg(StringPrintf("--input-vdex-fd=%d", input_vdex.fd())); |
| 144 | AddArg(StringPrintf("--output-vdex-fd=%d", output_vdex.fd())); |
Victor Hsieh | b345940 | 2020-07-07 12:34:54 -0700 | [diff] [blame] | 145 | |
Victor Hsieh | cb35a06 | 2020-08-13 16:11:13 -0700 | [diff] [blame] | 146 | if (output_image.fd() >= 0) { |
| 147 | AddArg(StringPrintf("--app-image-fd=%d", output_image.fd())); |
Victor Hsieh | b345940 | 2020-07-07 12:34:54 -0700 | [diff] [blame] | 148 | AddArg(MapPropertyToArg("dalvik.vm.appimageformat", "--image-format=%s")); |
| 149 | } |
Victor Hsieh | cb35a06 | 2020-08-13 16:11:13 -0700 | [diff] [blame] | 150 | if (dex_metadata.fd() > -1) { |
| 151 | AddArg("--dm-fd=" + std::to_string(dex_metadata.fd())); |
Victor Hsieh | b345940 | 2020-07-07 12:34:54 -0700 | [diff] [blame] | 152 | } |
Victor Hsieh | cb35a06 | 2020-08-13 16:11:13 -0700 | [diff] [blame] | 153 | if (profile.fd() != -1) { |
| 154 | AddArg(StringPrintf("--profile-file-fd=%d", profile.fd())); |
Victor Hsieh | b345940 | 2020-07-07 12:34:54 -0700 | [diff] [blame] | 155 | } |
| 156 | if (swap_fd >= 0) { |
| 157 | AddArg(StringPrintf("--swap-fd=%d", swap_fd)); |
| 158 | } |
| 159 | |
| 160 | // Get the directory of the apk to pass as a base classpath directory. |
| 161 | { |
Victor Hsieh | cb35a06 | 2020-08-13 16:11:13 -0700 | [diff] [blame] | 162 | std::string apk_dir(input_dex.path()); |
Victor Hsieh | b345940 | 2020-07-07 12:34:54 -0700 | [diff] [blame] | 163 | size_t dir_index = apk_dir.rfind('/'); |
| 164 | if (dir_index != std::string::npos) { |
| 165 | apk_dir = apk_dir.substr(0, dir_index); |
| 166 | AddArg(StringPrintf("--classpath-dir=%s", apk_dir.c_str())); |
| 167 | } |
| 168 | } |
| 169 | |
| 170 | if (class_loader_context != nullptr) { |
| 171 | AddArg(StringPrintf("--class-loader-context=%s", class_loader_context)); |
| 172 | if (!class_loader_context_fds.empty()) { |
| 173 | AddArg(StringPrintf("--class-loader-context-fds=%s", |
| 174 | class_loader_context_fds.c_str())); |
| 175 | } |
| 176 | } |
| 177 | } |
| 178 | |
Victor Hsieh | cb35a06 | 2020-08-13 16:11:13 -0700 | [diff] [blame] | 179 | void RunDex2Oat::PrepareCompilerConfigFlags(const UniqueFile& input_vdex, |
| 180 | const UniqueFile& output_vdex, |
Victor Hsieh | b345940 | 2020-07-07 12:34:54 -0700 | [diff] [blame] | 181 | const char* instruction_set, |
| 182 | const char* compiler_filter, |
| 183 | bool debuggable, |
| 184 | int target_sdk_version, |
| 185 | bool enable_hidden_api_checks, |
| 186 | bool generate_compact_dex, |
| 187 | const char* compilation_reason) { |
| 188 | // Disable cdex if update input vdex is true since this combination of options is not |
| 189 | // supported. |
Victor Hsieh | cb35a06 | 2020-08-13 16:11:13 -0700 | [diff] [blame] | 190 | const bool disable_cdex = !generate_compact_dex || (input_vdex.fd() == output_vdex.fd()); |
Victor Hsieh | b345940 | 2020-07-07 12:34:54 -0700 | [diff] [blame] | 191 | if (disable_cdex) { |
| 192 | AddArg(kDisableCompactDexFlag); |
| 193 | } |
Victor Hsieh | cb35a06 | 2020-08-13 16:11:13 -0700 | [diff] [blame] | 194 | |
Victor Hsieh | b345940 | 2020-07-07 12:34:54 -0700 | [diff] [blame] | 195 | // ISA related |
| 196 | { |
| 197 | AddArg(StringPrintf("--instruction-set=%s", instruction_set)); |
| 198 | |
| 199 | const std::string dex2oat_isa_features_key = |
| 200 | StringPrintf("dalvik.vm.isa.%s.features", instruction_set); |
| 201 | std::string instruction_set_features_arg = |
| 202 | MapPropertyToArg(dex2oat_isa_features_key, "--instruction-set-features=%s"); |
| 203 | AddArg(instruction_set_features_arg); |
| 204 | |
| 205 | const std::string dex2oat_isa_variant_key = |
| 206 | StringPrintf("dalvik.vm.isa.%s.variant", instruction_set); |
| 207 | std::string instruction_set_variant_arg = |
| 208 | MapPropertyToArg(dex2oat_isa_variant_key, "--instruction-set-variant=%s"); |
| 209 | AddArg(instruction_set_variant_arg); |
| 210 | } |
| 211 | |
| 212 | // Compute compiler filter. |
| 213 | { |
| 214 | std::string dex2oat_compiler_filter_arg; |
| 215 | { |
| 216 | // If we are booting without the real /data, don't spend time compiling. |
| 217 | std::string vold_decrypt = GetProperty("vold.decrypt", ""); |
| 218 | bool skip_compilation = vold_decrypt == "trigger_restart_min_framework" || |
| 219 | vold_decrypt == "1"; |
| 220 | |
| 221 | bool have_dex2oat_relocation_skip_flag = false; |
| 222 | if (skip_compilation) { |
| 223 | dex2oat_compiler_filter_arg = "--compiler-filter=extract"; |
| 224 | have_dex2oat_relocation_skip_flag = true; |
| 225 | } else if (compiler_filter != nullptr) { |
| 226 | dex2oat_compiler_filter_arg = StringPrintf("--compiler-filter=%s", |
| 227 | compiler_filter); |
| 228 | } |
| 229 | if (have_dex2oat_relocation_skip_flag) { |
| 230 | AddRuntimeArg("-Xnorelocate"); |
| 231 | } |
| 232 | } |
| 233 | |
| 234 | if (dex2oat_compiler_filter_arg.empty()) { |
| 235 | dex2oat_compiler_filter_arg = MapPropertyToArg("dalvik.vm.dex2oat-filter", |
| 236 | "--compiler-filter=%s"); |
| 237 | } |
| 238 | AddArg(dex2oat_compiler_filter_arg); |
| 239 | |
| 240 | if (compilation_reason != nullptr) { |
| 241 | AddArg(std::string("--compilation-reason=") + compilation_reason); |
| 242 | } |
| 243 | } |
| 244 | |
| 245 | AddArg(MapPropertyToArg("dalvik.vm.dex2oat-max-image-block-size", |
| 246 | "--max-image-block-size=%s")); |
| 247 | |
| 248 | AddArg(MapPropertyToArg("dalvik.vm.dex2oat-very-large", |
| 249 | "--very-large-app-threshold=%s")); |
| 250 | |
| 251 | std::string resolve_startup_string_arg = MapPropertyToArg( |
| 252 | "persist.device_config.runtime.dex2oat_resolve_startup_strings", |
| 253 | "--resolve-startup-const-strings=%s"); |
| 254 | if (resolve_startup_string_arg.empty()) { |
| 255 | // If empty, fall back to system property. |
| 256 | resolve_startup_string_arg = |
| 257 | MapPropertyToArg("dalvik.vm.dex2oat-resolve-startup-strings", |
| 258 | "--resolve-startup-const-strings=%s"); |
| 259 | } |
| 260 | AddArg(resolve_startup_string_arg); |
| 261 | |
| 262 | // Debug related |
| 263 | { |
| 264 | // Check whether all apps should be compiled debuggable. |
| 265 | if (!debuggable) { |
| 266 | debuggable = GetProperty("dalvik.vm.always_debuggable", "") == "1"; |
| 267 | } |
| 268 | if (debuggable) { |
| 269 | AddArg("--debuggable"); |
| 270 | } |
| 271 | |
| 272 | const bool generate_debug_info = GetBoolProperty("debug.generate-debug-info", false); |
| 273 | if (generate_debug_info) { |
| 274 | AddArg("--generate-debug-info"); |
| 275 | } |
| 276 | { |
| 277 | bool generate_minidebug_info = kEnableMinidebugInfo && |
| 278 | GetBoolProperty(kMinidebugInfoSystemProperty, |
| 279 | kMinidebugInfoSystemPropertyDefault); |
| 280 | if (generate_minidebug_info) { |
| 281 | AddArg(kMinidebugDex2oatFlag); |
| 282 | } |
| 283 | } |
| 284 | } |
| 285 | |
| 286 | if (target_sdk_version != 0) { |
| 287 | AddRuntimeArg(StringPrintf("-Xtarget-sdk-version:%d", target_sdk_version)); |
| 288 | } |
| 289 | |
| 290 | if (enable_hidden_api_checks) { |
| 291 | AddRuntimeArg("-Xhidden-api-policy:enabled"); |
| 292 | } |
| 293 | } |
| 294 | |
| 295 | void RunDex2Oat::PrepareCompilerRuntimeAndPerfConfigFlags(bool post_bootcomplete, |
| 296 | bool for_restore) { |
| 297 | // CPU set |
| 298 | { |
| 299 | std::string cpu_set_format = "--cpu-set=%s"; |
| 300 | std::string dex2oat_cpu_set_arg = post_bootcomplete |
| 301 | ? (for_restore |
| 302 | ? MapPropertyToArgWithBackup( |
| 303 | "dalvik.vm.restore-dex2oat-cpu-set", |
| 304 | "dalvik.vm.dex2oat-cpu-set", |
| 305 | cpu_set_format) |
| 306 | : MapPropertyToArg("dalvik.vm.dex2oat-cpu-set", cpu_set_format)) |
| 307 | : MapPropertyToArg("dalvik.vm.boot-dex2oat-cpu-set", cpu_set_format); |
| 308 | AddArg(dex2oat_cpu_set_arg); |
| 309 | } |
| 310 | |
| 311 | // Number of threads |
| 312 | { |
| 313 | std::string threads_format = "-j%s"; |
| 314 | std::string dex2oat_threads_arg = post_bootcomplete |
| 315 | ? (for_restore |
| 316 | ? MapPropertyToArgWithBackup( |
| 317 | "dalvik.vm.restore-dex2oat-threads", |
| 318 | "dalvik.vm.dex2oat-threads", |
| 319 | threads_format) |
| 320 | : MapPropertyToArg("dalvik.vm.dex2oat-threads", threads_format)) |
| 321 | : MapPropertyToArg("dalvik.vm.boot-dex2oat-threads", threads_format); |
| 322 | AddArg(dex2oat_threads_arg); |
| 323 | } |
| 324 | |
| 325 | AddRuntimeArg(MapPropertyToArg("dalvik.vm.dex2oat-Xms", "-Xms%s")); |
| 326 | AddRuntimeArg(MapPropertyToArg("dalvik.vm.dex2oat-Xmx", "-Xmx%s")); |
Calin Juravle | 380fff7 | 2021-06-17 15:37:08 -0700 | [diff] [blame^] | 327 | |
| 328 | // Enable compiling dex files in isolation on low ram devices. |
| 329 | // It takes longer but reduces the memory footprint. |
| 330 | if (GetBoolProperty("ro.config.low_ram", false)) { |
| 331 | AddArg("--compile-individually"); |
| 332 | } |
Victor Hsieh | b345940 | 2020-07-07 12:34:54 -0700 | [diff] [blame] | 333 | } |
| 334 | |
Victor Hsieh | c9821f1 | 2020-08-07 11:32:29 -0700 | [diff] [blame] | 335 | void RunDex2Oat::Exec(int exit_code) { |
Victor Hsieh | c9821f1 | 2020-08-07 11:32:29 -0700 | [diff] [blame] | 336 | execv_helper_->Exec(exit_code); |
| 337 | } |
| 338 | |
| 339 | void RunDex2Oat::AddArg(const std::string& arg) { |
| 340 | execv_helper_->AddArg(arg); |
| 341 | } |
| 342 | |
| 343 | void RunDex2Oat::AddRuntimeArg(const std::string& arg) { |
| 344 | execv_helper_->AddRuntimeArg(arg); |
| 345 | } |
| 346 | |
| 347 | std::string RunDex2Oat::GetProperty(const std::string& key, |
| 348 | const std::string& default_value) { |
| 349 | return android::base::GetProperty(key, default_value); |
| 350 | } |
| 351 | |
| 352 | bool RunDex2Oat::GetBoolProperty(const std::string& key, bool default_value) { |
| 353 | return android::base::GetBoolProperty(key, default_value); |
| 354 | } |
| 355 | |
| 356 | std::string RunDex2Oat::MapPropertyToArg(const std::string& property, |
| 357 | const std::string& format, |
| 358 | const std::string& default_value) { |
| 359 | std::string prop = GetProperty(property, default_value); |
| 360 | if (!prop.empty()) { |
| 361 | return StringPrintf(format.c_str(), prop.c_str()); |
| 362 | } |
| 363 | return ""; |
| 364 | } |
| 365 | |
| 366 | std::string RunDex2Oat::MapPropertyToArgWithBackup( |
| 367 | const std::string& property, |
| 368 | const std::string& backupProperty, |
| 369 | const std::string& format, |
| 370 | const std::string& default_value) { |
| 371 | std::string value = GetProperty(property, default_value); |
| 372 | if (!value.empty()) { |
| 373 | return StringPrintf(format.c_str(), value.c_str()); |
| 374 | } |
| 375 | return MapPropertyToArg(backupProperty, format, default_value); |
| 376 | } |
| 377 | |
| 378 | } // namespace installd |
| 379 | } // namespace android |