blob: 47ac9f0f7e9ecc09a4fe0c9c271bd77a1263e4cd [file] [log] [blame]
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +00001/*
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
17#include <sys/stat.h>
18
19#include <string>
20#include <string_view>
21
Victor Hsieh73c4f792021-10-01 18:13:52 +000022#include "android-base/parseint.h"
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +000023#include "android-base/properties.h"
24#include "android-base/stringprintf.h"
25#include "android-base/strings.h"
26#include "arch/instruction_set.h"
27#include "base/file_utils.h"
28#include "base/globals.h"
29#include "odr_common.h"
30#include "odr_compilation_log.h"
31#include "odr_config.h"
32#include "odr_metrics.h"
33#include "odrefresh.h"
34#include "odrefresh/odrefresh.h"
35
36namespace {
37
Jiakai Zhang83c38e22021-11-03 20:54:55 +000038using ::art::odrefresh::CompilationOptions;
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +000039using ::art::odrefresh::ExitCode;
40using ::art::odrefresh::OdrCompilationLog;
41using ::art::odrefresh::OdrConfig;
42using ::art::odrefresh::OdrMetrics;
43using ::art::odrefresh::OnDeviceRefresh;
44using ::art::odrefresh::QuotePath;
45using ::art::odrefresh::ZygoteKind;
46
47void UsageErrorV(const char* fmt, va_list ap) {
48 std::string error;
49 android::base::StringAppendV(&error, fmt, ap);
50 if (isatty(fileno(stderr))) {
51 std::cerr << error << std::endl;
52 } else {
53 LOG(ERROR) << error;
54 }
55}
56
57void UsageError(const char* fmt, ...) {
58 va_list ap;
59 va_start(ap, fmt);
60 UsageErrorV(fmt, ap);
61 va_end(ap);
62}
63
64NO_RETURN void ArgumentError(const char* fmt, ...) {
65 va_list ap;
66 va_start(ap, fmt);
67 UsageErrorV(fmt, ap);
68 va_end(ap);
69 UsageError("Try '--help' for more information.");
70 exit(EX_USAGE);
71}
72
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +000073bool ParseZygoteKind(const char* input, ZygoteKind* zygote_kind) {
74 std::string_view z(input);
75 if (z == "zygote32") {
76 *zygote_kind = ZygoteKind::kZygote32;
77 return true;
78 } else if (z == "zygote32_64") {
79 *zygote_kind = ZygoteKind::kZygote32_64;
80 return true;
81 } else if (z == "zygote64_32") {
82 *zygote_kind = ZygoteKind::kZygote64_32;
83 return true;
84 } else if (z == "zygote64") {
85 *zygote_kind = ZygoteKind::kZygote64;
86 return true;
87 }
88 return false;
89}
90
91std::string GetEnvironmentVariableOrDie(const char* name) {
92 const char* value = getenv(name);
93 LOG_ALWAYS_FATAL_IF(value == nullptr, "%s is not defined.", name);
94 return value;
95}
96
Jiakai Zhang9b7ddf62021-11-01 11:36:52 +000097std::string GetEnvironmentVariableOrDefault(const char* name, std::string default_value) {
98 const char* value = getenv(name);
99 if (value == nullptr) {
100 return default_value;
101 }
102 return value;
103}
104
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +0000105bool ArgumentMatches(std::string_view argument, std::string_view prefix, std::string* value) {
106 if (android::base::StartsWith(argument, prefix)) {
107 *value = std::string(argument.substr(prefix.size()));
108 return true;
109 }
110 return false;
111}
112
113bool ArgumentEquals(std::string_view argument, std::string_view expected) {
114 return argument == expected;
115}
116
Jiakai Zhangfcdc7cf2022-01-07 14:40:26 +0000117int InitializeConfig(int argc, char** argv, OdrConfig* config) {
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +0000118 config->SetApexInfoListFile("/apex/apex-info-list.xml");
119 config->SetArtBinDir(art::GetArtBinDir());
120 config->SetBootClasspath(GetEnvironmentVariableOrDie("BOOTCLASSPATH"));
121 config->SetDex2oatBootclasspath(GetEnvironmentVariableOrDie("DEX2OATBOOTCLASSPATH"));
122 config->SetSystemServerClasspath(GetEnvironmentVariableOrDie("SYSTEMSERVERCLASSPATH"));
Jiakai Zhang9b7ddf62021-11-01 11:36:52 +0000123 config->SetStandaloneSystemServerJars(
124 GetEnvironmentVariableOrDefault("STANDALONE_SYSTEMSERVER_JARS", /*default_value=*/""));
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +0000125 config->SetIsa(art::kRuntimeISA);
126
Victor Hsieh3644cb42021-11-16 10:49:28 -0800127 std::string zygote;
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +0000128 int n = 1;
129 for (; n < argc - 1; ++n) {
130 const char* arg = argv[n];
131 std::string value;
132 if (ArgumentMatches(arg, "--use-compilation-os=", &value)) {
Victor Hsieh73c4f792021-10-01 18:13:52 +0000133 int cid;
134 if (!android::base::ParseInt(value, &cid)) {
135 ArgumentError("Failed to parse CID: %s", value.c_str());
136 }
137 config->SetCompilationOsAddress(cid);
Jiakai Zhang34dcce52022-01-07 16:45:11 +0000138 } else if (ArgumentEquals(arg, "--compilation-os-mode")) {
139 config->SetCompilationOsMode(true);
Alan Stokesd4d21bf2021-10-13 11:07:25 +0100140 } else if (ArgumentMatches(arg, "--dalvik-cache=", &value)) {
141 art::OverrideDalvikCacheSubDirectory(value);
Alan Stokes1f8d2612021-12-14 14:27:45 +0000142 config->SetArtifactDirectory(GetApexDataDalvikCacheDirectory(art::InstructionSet::kNone));
Victor Hsieh884fe762021-10-13 13:55:41 -0700143 } else if (ArgumentMatches(arg, "--max-execution-seconds=", &value)) {
144 int seconds;
145 if (!android::base::ParseInt(value, &seconds)) {
146 ArgumentError("Failed to parse integer: %s", value.c_str());
147 }
148 config->SetMaxExecutionSeconds(seconds);
149 } else if (ArgumentMatches(arg, "--max-child-process-seconds=", &value)) {
150 int seconds;
151 if (!android::base::ParseInt(value, &seconds)) {
152 ArgumentError("Failed to parse integer: %s", value.c_str());
153 }
154 config->SetMaxChildProcessSeconds(seconds);
Victor Hsieh3644cb42021-11-16 10:49:28 -0800155 } else if (ArgumentMatches(arg, "--zygote-arch=", &value)) {
156 zygote = value;
Victor Hsieha39356a2021-12-16 11:40:39 -0800157 } else if (ArgumentMatches(arg, "--system-server-compiler-filter=", &value)) {
158 config->SetSystemServerCompilerFilter(value);
Victor Hsieh27a740c2021-11-18 13:35:41 -0800159 } else if (ArgumentMatches(arg, "--staging-dir=", &value)) {
160 config->SetStagingDir(value);
Jiakai Zhangfcdc7cf2022-01-07 14:40:26 +0000161 } else if (ArgumentEquals(arg, "--dry-run")) {
162 config->SetDryRun();
163 } else if (ArgumentEquals(arg, "--partial-compilation")) {
164 config->SetPartialCompilation(true);
165 } else if (ArgumentEquals(arg, "--no-refresh")) {
166 config->SetRefresh(false);
167 } else {
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +0000168 UsageError("Unrecognized argument: '%s'", arg);
169 }
170 }
Victor Hsieh3644cb42021-11-16 10:49:28 -0800171
172 if (zygote.empty()) {
173 // Use ro.zygote by default, if not overridden by --zygote-arch flag.
174 zygote = android::base::GetProperty("ro.zygote", {});
175 }
176 ZygoteKind zygote_kind;
177 if (!ParseZygoteKind(zygote.c_str(), &zygote_kind)) {
178 LOG(FATAL) << "Unknown zygote: " << QuotePath(zygote);
179 }
180 config->SetZygoteKind(zygote_kind);
181
Victor Hsieha39356a2021-12-16 11:40:39 -0800182 if (config->GetSystemServerCompilerFilter().empty()) {
183 std::string filter =
184 android::base::GetProperty("dalvik.vm.systemservercompilerfilter", "speed");
185 config->SetSystemServerCompilerFilter(filter);
186 }
187
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +0000188 return n;
189}
190
Jiakai Zhangfcdc7cf2022-01-07 14:40:26 +0000191void OptionsHelp() {
192 UsageError("--dry-run");
193 UsageError("--partial-compilation Only generate artifacts that are out-of-date or");
194 UsageError(" missing.");
195 UsageError("--no-refresh Do not refresh existing artifacts.");
Victor Hsiehb37da9d2021-10-18 09:40:51 -0700196 UsageError("--use-compilation-os=<CID> Run compilation in the VM with the given CID.");
197 UsageError(" (0 = do not use VM, -1 = use composd's VM)");
Jiakai Zhang34dcce52022-01-07 16:45:11 +0000198 UsageError("--compilation-os-mode Indicate that odrefresh is running in Compilation");
199 UsageError(" OS.");
Alan Stokes1f8d2612021-12-14 14:27:45 +0000200 UsageError("--dalvik-cache=<DIR> Write artifacts to .../<DIR> rather than");
201 UsageError(" .../dalvik-cache");
Victor Hsiehb37da9d2021-10-18 09:40:51 -0700202 UsageError("--max-execution-seconds=<N> Maximum timeout of all compilation combined");
203 UsageError("--max-child-process-seconds=<N> Maximum timeout of each compilation task");
Alan Stokes1f8d2612021-12-14 14:27:45 +0000204 UsageError("--staging-dir=<DIR> Write temporary artifacts to <DIR> rather than");
205 UsageError(" .../staging");
Victor Hsieh3644cb42021-11-16 10:49:28 -0800206 UsageError("--zygote-arch=<STRING> Zygote kind that overrides ro.zygote");
Victor Hsieha39356a2021-12-16 11:40:39 -0800207 UsageError("--system-server-compiler-filter=<STRING>");
208 UsageError(" Compiler filter that overrides");
209 UsageError(" dalvik.vm.systemservercompilerfilter");
Alan Stokesd4d21bf2021-10-13 11:07:25 +0100210}
211
Alan Stokesd4d21bf2021-10-13 11:07:25 +0100212NO_RETURN void UsageHelp(const char* argv0) {
213 std::string name(android::base::Basename(argv0));
214 UsageError("Usage: %s [OPTION...] ACTION", name.c_str());
215 UsageError("On-device refresh tool for boot class path extensions and system server");
216 UsageError("following an update of the ART APEX.");
217 UsageError("");
218 UsageError("Valid ACTION choices are:");
219 UsageError("");
Jiakai Zhang619121a2021-11-03 10:25:28 +0000220 UsageError("--check Check compilation artifacts are up-to-date based on metadata.");
Alan Stokesd4d21bf2021-10-13 11:07:25 +0100221 UsageError("--compile Compile boot class path extensions and system_server jars");
222 UsageError(" when necessary.");
223 UsageError("--force-compile Unconditionally compile the boot class path extensions and");
224 UsageError(" system_server jars.");
Alan Stokesd4d21bf2021-10-13 11:07:25 +0100225 UsageError("--help Display this help information.");
226 UsageError("");
227 UsageError("Available OPTIONs are:");
228 UsageError("");
Jiakai Zhangfcdc7cf2022-01-07 14:40:26 +0000229 OptionsHelp();
Alan Stokesd4d21bf2021-10-13 11:07:25 +0100230
231 exit(EX_USAGE);
232}
233
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +0000234} // namespace
235
Orion Hodsona182c932021-09-27 13:51:22 +0100236int main(int argc, char** argv) {
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +0000237 // odrefresh is launched by `init` which sets the umask of forked processed to
238 // 077 (S_IRWXG | S_IRWXO). This blocks the ability to make files and directories readable
239 // by others and prevents system_server from loading generated artifacts.
240 umask(S_IWGRP | S_IWOTH);
241
Orion Hodsona182c932021-09-27 13:51:22 +0100242 // Explicitly initialize logging (b/201042799).
243 android::base::InitLogging(argv, android::base::LogdLogger(android::base::SYSTEM));
244
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +0000245 OdrConfig config(argv[0]);
246 int n = InitializeConfig(argc, argv, &config);
247 argv += n;
248 argc -= n;
249 if (argc != 1) {
250 UsageError("Expected 1 argument, but have %d.", argc);
Victor Hsieh08e9f5f2021-12-16 10:22:02 -0800251 exit(EX_USAGE);
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +0000252 }
253
Alan Stokesd4d21bf2021-10-13 11:07:25 +0100254 OdrMetrics metrics(config.GetArtifactDirectory());
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +0000255 OnDeviceRefresh odr(config);
Victor Hsieh08e9f5f2021-12-16 10:22:02 -0800256
257 std::string_view action(argv[0]);
258 CompilationOptions compilation_options;
259 if (action == "--check") {
260 // Fast determination of whether artifacts are up to date.
261 return odr.CheckArtifactsAreUpToDate(metrics, &compilation_options);
262 } else if (action == "--compile") {
263 const ExitCode exit_code = odr.CheckArtifactsAreUpToDate(metrics, &compilation_options);
264 if (exit_code != ExitCode::kCompilationRequired) {
265 return exit_code;
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +0000266 }
Victor Hsieh08e9f5f2021-12-16 10:22:02 -0800267 OdrCompilationLog compilation_log;
268 if (!compilation_log.ShouldAttemptCompile(metrics.GetTrigger())) {
269 LOG(INFO) << "Compilation skipped because it was attempted recently";
270 return ExitCode::kOkay;
271 }
272 ExitCode compile_result = odr.Compile(metrics, compilation_options);
273 compilation_log.Log(metrics.GetArtApexVersion(),
274 metrics.GetArtApexLastUpdateMillis(),
275 metrics.GetTrigger(),
276 compile_result);
277 return compile_result;
278 } else if (action == "--force-compile") {
279 // Clean-up existing files.
280 if (!odr.RemoveArtifactsDirectory()) {
281 metrics.SetStatus(OdrMetrics::Status::kIoError);
282 return ExitCode::kCleanupFailed;
283 }
284 return odr.Compile(metrics,
285 CompilationOptions{
286 .compile_boot_extensions_for_isas = config.GetBootExtensionIsas(),
287 .system_server_jars_to_compile = odr.AllSystemServerJars(),
288 });
289 } else if (action == "--help") {
290 UsageHelp(argv[0]);
291 } else {
292 UsageError("Unknown argument: ", action);
293 exit(EX_USAGE);
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +0000294 }
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +0000295}