blob: 8cac58f91f338f9745da1e924231b3311cb5c9c0 [file] [log] [blame]
Victor Hsiehc9821f12020-08-07 11:32:29 -07001/*
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
33using android::base::Basename;
34using android::base::StringPrintf;
35
36namespace android {
37namespace installd {
38
39namespace {
40
41// Should minidebug info be included in compiled artifacts? Even if this value is
42// "true," usage might still be conditional to other constraints, e.g., system
43// property overrides.
44static constexpr bool kEnableMinidebugInfo = true;
45
46static constexpr const char* kMinidebugInfoSystemProperty = "dalvik.vm.dex2oat-minidebuginfo";
47static constexpr bool kMinidebugInfoSystemPropertyDefault = false;
48static constexpr const char* kMinidebugDex2oatFlag = "--generate-mini-debug-info";
49static constexpr const char* kDisableCompactDexFlag = "--compact-dex-level=none";
50
51// Location of the JIT Zygote image.
52static const char* kJitZygoteImage =
53 "boot.art:/nonx/boot-framework.art!/system/etc/boot-image.prof";
54
55std::vector<std::string> SplitBySpaces(const std::string& str) {
56 if (str.empty()) {
57 return {};
58 }
59 return android::base::Split(str, " ");
60}
61
62} // namespace
63
64RunDex2Oat::RunDex2Oat(const char* dex2oat_bin, ExecVHelper* execv_helper)
65 : dex2oat_bin_(dex2oat_bin), execv_helper_(execv_helper) {}
66
67void RunDex2Oat::Initialize(int zip_fd,
68 int oat_fd,
69 int input_vdex_fd,
70 int output_vdex_fd,
71 int image_fd,
72 const char* input_file_name,
73 const char* output_file_name,
74 int swap_fd,
75 const char* instruction_set,
76 const char* compiler_filter,
77 bool debuggable,
78 bool post_bootcomplete,
79 bool for_restore,
80 int profile_fd,
81 const char* class_loader_context,
82 const std::string& class_loader_context_fds,
83 int target_sdk_version,
84 bool enable_hidden_api_checks,
85 bool generate_compact_dex,
86 int dex_metadata_fd,
87 bool use_jitzygote_image,
88 const char* compilation_reason) {
89 // Get the relative path to the input file.
90 std::string input_basename = Basename(input_file_name);
91
92 std::string dex2oat_Xms_arg = MapPropertyToArg("dalvik.vm.dex2oat-Xms", "-Xms%s");
93 std::string dex2oat_Xmx_arg = MapPropertyToArg("dalvik.vm.dex2oat-Xmx", "-Xmx%s");
94
95 std::string threads_format = "-j%s";
96 std::string dex2oat_threads_arg = post_bootcomplete
97 ? (for_restore
98 ? MapPropertyToArgWithBackup(
99 "dalvik.vm.restore-dex2oat-threads",
100 "dalvik.vm.dex2oat-threads",
101 threads_format)
102 : MapPropertyToArg("dalvik.vm.dex2oat-threads", threads_format))
103 : MapPropertyToArg("dalvik.vm.boot-dex2oat-threads", threads_format);
104 std::string cpu_set_format = "--cpu-set=%s";
105 std::string dex2oat_cpu_set_arg = post_bootcomplete
106 ? (for_restore
107 ? MapPropertyToArgWithBackup(
108 "dalvik.vm.restore-dex2oat-cpu-set",
109 "dalvik.vm.dex2oat-cpu-set",
110 cpu_set_format)
111 : MapPropertyToArg("dalvik.vm.dex2oat-cpu-set", cpu_set_format))
112 : MapPropertyToArg("dalvik.vm.boot-dex2oat-cpu-set", cpu_set_format);
113
114 std::string bootclasspath;
115 char* dex2oat_bootclasspath = getenv("DEX2OATBOOTCLASSPATH");
116 if (dex2oat_bootclasspath != nullptr) {
117 bootclasspath = StringPrintf("-Xbootclasspath:%s", dex2oat_bootclasspath);
118 }
119 // If DEX2OATBOOTCLASSPATH is not in the environment, dex2oat is going to query
120 // BOOTCLASSPATH.
121
122 const std::string dex2oat_isa_features_key =
123 StringPrintf("dalvik.vm.isa.%s.features", instruction_set);
124 std::string instruction_set_features_arg =
125 MapPropertyToArg(dex2oat_isa_features_key, "--instruction-set-features=%s");
126
127 const std::string dex2oat_isa_variant_key =
128 StringPrintf("dalvik.vm.isa.%s.variant", instruction_set);
129 std::string instruction_set_variant_arg =
130 MapPropertyToArg(dex2oat_isa_variant_key, "--instruction-set-variant=%s");
131
132 const char* dex2oat_norelocation = "-Xnorelocate";
133
134 const std::string dex2oat_flags = GetProperty("dalvik.vm.dex2oat-flags", "");
135 std::vector<std::string> dex2oat_flags_args = SplitBySpaces(dex2oat_flags);
136 ALOGV("dalvik.vm.dex2oat-flags=%s\n", dex2oat_flags.c_str());
137
138 // If we are booting without the real /data, don't spend time compiling.
139 std::string vold_decrypt = GetProperty("vold.decrypt", "");
140 bool skip_compilation = vold_decrypt == "trigger_restart_min_framework" ||
141 vold_decrypt == "1";
142
143 std::string updatable_bcp_packages =
144 MapPropertyToArg("dalvik.vm.dex2oat-updatable-bcp-packages-file",
145 "--updatable-bcp-packages-file=%s");
146 if (updatable_bcp_packages.empty()) {
147 // Make dex2oat fail by providing non-existent file name.
148 updatable_bcp_packages = "--updatable-bcp-packages-file=/nonx/updatable-bcp-packages.txt";
149 }
150
151 std::string resolve_startup_string_arg =
152 MapPropertyToArg("persist.device_config.runtime.dex2oat_resolve_startup_strings",
153 "--resolve-startup-const-strings=%s");
154 if (resolve_startup_string_arg.empty()) {
155 // If empty, fall back to system property.
156 resolve_startup_string_arg =
157 MapPropertyToArg("dalvik.vm.dex2oat-resolve-startup-strings",
158 "--resolve-startup-const-strings=%s");
159 }
160
161 const std::string image_block_size_arg =
162 MapPropertyToArg("dalvik.vm.dex2oat-max-image-block-size",
163 "--max-image-block-size=%s");
164
165 const bool generate_debug_info = GetBoolProperty("debug.generate-debug-info", false);
166
167 std::string image_format_arg;
168 if (image_fd >= 0) {
169 image_format_arg = MapPropertyToArg("dalvik.vm.appimageformat", "--image-format=%s");
170 }
171
172 std::string dex2oat_large_app_threshold_arg =
173 MapPropertyToArg("dalvik.vm.dex2oat-very-large", "--very-large-app-threshold=%s");
174
175 bool generate_minidebug_info = kEnableMinidebugInfo &&
176 GetBoolProperty(kMinidebugInfoSystemProperty, kMinidebugInfoSystemPropertyDefault);
177
178 std::string boot_image;
179 if (use_jitzygote_image) {
180 boot_image = StringPrintf("--boot-image=%s", kJitZygoteImage);
181 } else {
182 boot_image = MapPropertyToArg("dalvik.vm.boot-image", "--boot-image=%s");
183 }
184
185 // clang FORTIFY doesn't let us use strlen in constant array bounds, so we
186 // use arraysize instead.
187 std::string zip_fd_arg = StringPrintf("--zip-fd=%d", zip_fd);
188 std::string zip_location_arg = StringPrintf("--zip-location=%s", input_basename.c_str());
189 std::string input_vdex_fd_arg = StringPrintf("--input-vdex-fd=%d", input_vdex_fd);
190 std::string output_vdex_fd_arg = StringPrintf("--output-vdex-fd=%d", output_vdex_fd);
191 std::string oat_fd_arg = StringPrintf("--oat-fd=%d", oat_fd);
192 std::string oat_location_arg = StringPrintf("--oat-location=%s", output_file_name);
193 std::string instruction_set_arg = StringPrintf("--instruction-set=%s", instruction_set);
194 std::string dex2oat_compiler_filter_arg;
195 std::string dex2oat_swap_fd;
196 std::string dex2oat_image_fd;
197 std::string target_sdk_version_arg;
198 if (target_sdk_version != 0) {
199 target_sdk_version_arg = StringPrintf("-Xtarget-sdk-version:%d", target_sdk_version);
200 }
201 std::string class_loader_context_arg;
202 std::string class_loader_context_fds_arg;
203 if (class_loader_context != nullptr) {
204 class_loader_context_arg = StringPrintf("--class-loader-context=%s",
205 class_loader_context);
206 if (!class_loader_context_fds.empty()) {
207 class_loader_context_fds_arg = StringPrintf("--class-loader-context-fds=%s",
208 class_loader_context_fds.c_str());
209 }
210 }
211
212 if (swap_fd >= 0) {
213 dex2oat_swap_fd = StringPrintf("--swap-fd=%d", swap_fd);
214 }
215 if (image_fd >= 0) {
216 dex2oat_image_fd = StringPrintf("--app-image-fd=%d", image_fd);
217 }
218
219 // Compute compiler filter.
220 bool have_dex2oat_relocation_skip_flag = false;
221 if (skip_compilation) {
222 dex2oat_compiler_filter_arg = "--compiler-filter=extract";
223 have_dex2oat_relocation_skip_flag = true;
224 } else if (compiler_filter != nullptr) {
225 dex2oat_compiler_filter_arg = StringPrintf("--compiler-filter=%s", compiler_filter);
226 }
227
228 if (dex2oat_compiler_filter_arg.empty()) {
229 dex2oat_compiler_filter_arg = MapPropertyToArg("dalvik.vm.dex2oat-filter",
230 "--compiler-filter=%s");
231 }
232
233 // Check whether all apps should be compiled debuggable.
234 if (!debuggable) {
235 debuggable = GetProperty("dalvik.vm.always_debuggable", "") == "1";
236 }
237 std::string profile_arg;
238 if (profile_fd != -1) {
239 profile_arg = StringPrintf("--profile-file-fd=%d", profile_fd);
240 }
241
242 // Get the directory of the apk to pass as a base classpath directory.
243 std::string base_dir;
244 std::string apk_dir(input_file_name);
245 unsigned long dir_index = apk_dir.rfind('/');
246 bool has_base_dir = dir_index != std::string::npos;
247 if (has_base_dir) {
248 apk_dir = apk_dir.substr(0, dir_index);
249 base_dir = StringPrintf("--classpath-dir=%s", apk_dir.c_str());
250 }
251
252 std::string dex_metadata_fd_arg = "--dm-fd=" + std::to_string(dex_metadata_fd);
253
254 std::string compilation_reason_arg = compilation_reason == nullptr
255 ? ""
256 : std::string("--compilation-reason=") + compilation_reason;
257
258 ALOGV("Running %s in=%s out=%s\n", dex2oat_bin_.c_str(), input_basename.c_str(),
259 output_file_name);
260
261 // Disable cdex if update input vdex is true since this combination of options is not
262 // supported.
263 const bool disable_cdex = !generate_compact_dex || (input_vdex_fd == output_vdex_fd);
264
265 AddArg(zip_fd_arg);
266 AddArg(zip_location_arg);
267 AddArg(input_vdex_fd_arg);
268 AddArg(output_vdex_fd_arg);
269 AddArg(oat_fd_arg);
270 AddArg(oat_location_arg);
271 AddArg(instruction_set_arg);
272
273 AddArg(instruction_set_variant_arg);
274 AddArg(instruction_set_features_arg);
275
276 AddArg(boot_image);
277
278 AddRuntimeArg(bootclasspath);
279 AddRuntimeArg(dex2oat_Xms_arg);
280 AddRuntimeArg(dex2oat_Xmx_arg);
281
282 AddArg(updatable_bcp_packages);
283 AddArg(resolve_startup_string_arg);
284 AddArg(image_block_size_arg);
285 AddArg(dex2oat_compiler_filter_arg);
286 AddArg(dex2oat_threads_arg);
287 AddArg(dex2oat_cpu_set_arg);
288 AddArg(dex2oat_swap_fd);
289 AddArg(dex2oat_image_fd);
290
291 if (generate_debug_info) {
292 AddArg("--generate-debug-info");
293 }
294 if (debuggable) {
295 AddArg("--debuggable");
296 }
297 AddArg(image_format_arg);
298 AddArg(dex2oat_large_app_threshold_arg);
299
300 if (have_dex2oat_relocation_skip_flag) {
301 AddRuntimeArg(dex2oat_norelocation);
302 }
303 AddArg(profile_arg);
304 AddArg(base_dir);
305 AddArg(class_loader_context_arg);
306 AddArg(class_loader_context_fds_arg);
307 if (generate_minidebug_info) {
308 AddArg(kMinidebugDex2oatFlag);
309 }
310 if (disable_cdex) {
311 AddArg(kDisableCompactDexFlag);
312 }
313 AddRuntimeArg(target_sdk_version_arg);
314 if (enable_hidden_api_checks) {
315 AddRuntimeArg("-Xhidden-api-policy:enabled");
316 }
317
318 if (dex_metadata_fd > -1) {
319 AddArg(dex_metadata_fd_arg);
320 }
321
322 AddArg(compilation_reason_arg);
323
324 // Do not add args after dex2oat_flags, they should override others for debugging.
325 for (auto it = dex2oat_flags_args.begin(); it != dex2oat_flags_args.end(); ++it) {
326 AddArg(*it);
327 }
328
329 execv_helper_->PrepareArgs(dex2oat_bin_);
330}
331
332RunDex2Oat::~RunDex2Oat() {}
333
334void RunDex2Oat::Exec(int exit_code) {
335 LOG(ERROR) << "RunDex2Oat::Exec";
336 execv_helper_->Exec(exit_code);
337}
338
339void RunDex2Oat::AddArg(const std::string& arg) {
340 execv_helper_->AddArg(arg);
341}
342
343void RunDex2Oat::AddRuntimeArg(const std::string& arg) {
344 execv_helper_->AddRuntimeArg(arg);
345}
346
347std::string RunDex2Oat::GetProperty(const std::string& key,
348 const std::string& default_value) {
349 return android::base::GetProperty(key, default_value);
350}
351
352bool RunDex2Oat::GetBoolProperty(const std::string& key, bool default_value) {
353 return android::base::GetBoolProperty(key, default_value);
354}
355
356std::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
366std::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