blob: aa5b72f38c4885ef3a62b34df48e7e8077497cf4 [file] [log] [blame]
Orion Hodson4c3ade62021-02-10 14:07:10 +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 "odrefresh/odrefresh.h"
18
Orion Hodson947a8502021-03-08 15:40:09 +000019#include <errno.h>
Orion Hodson4c3ade62021-02-10 14:07:10 +000020#include <fcntl.h>
Orion Hodson947a8502021-03-08 15:40:09 +000021#include <inttypes.h>
Orion Hodson3407fb22021-03-17 14:40:51 +000022#include <limits.h>
Orion Hodson4c3ade62021-02-10 14:07:10 +000023#include <stdio.h>
Orion Hodson947a8502021-03-08 15:40:09 +000024#include <string.h>
Orion Hodson4c3ade62021-02-10 14:07:10 +000025#include <sys/stat.h>
Orion Hodson4c3ade62021-02-10 14:07:10 +000026#include <sysexits.h>
27#include <time.h>
28#include <unistd.h>
29
Orion Hodson947a8502021-03-08 15:40:09 +000030#include <algorithm>
Orion Hodson4c3ade62021-02-10 14:07:10 +000031#include <cstdarg>
Orion Hodson3407fb22021-03-17 14:40:51 +000032#include <cstdint>
Orion Hodson4c3ade62021-02-10 14:07:10 +000033#include <cstdlib>
Orion Hodson947a8502021-03-08 15:40:09 +000034#include <fstream>
Orion Hodson4c3ade62021-02-10 14:07:10 +000035#include <initializer_list>
36#include <iosfwd>
37#include <iostream>
38#include <memory>
Orion Hodson947a8502021-03-08 15:40:09 +000039#include <optional>
Orion Hodson4c3ade62021-02-10 14:07:10 +000040#include <ostream>
Orion Hodson4c3ade62021-02-10 14:07:10 +000041#include <sstream>
42#include <string>
43#include <string_view>
Orion Hodson947a8502021-03-08 15:40:09 +000044#include <type_traits>
45#include <utility>
Orion Hodson4c3ade62021-02-10 14:07:10 +000046#include <vector>
47
48#include "android-base/file.h"
49#include "android-base/logging.h"
50#include "android-base/macros.h"
51#include "android-base/properties.h"
52#include "android-base/stringprintf.h"
53#include "android-base/strings.h"
54#include "android/log.h"
55#include "arch/instruction_set.h"
Orion Hodson947a8502021-03-08 15:40:09 +000056#include "base/file_utils.h"
Orion Hodson4c3ade62021-02-10 14:07:10 +000057#include "base/globals.h"
58#include "base/macros.h"
59#include "base/os.h"
60#include "base/string_view_cpp20.h"
61#include "base/unix_file/fd_file.h"
62#include "com_android_apex.h"
Orion Hodson947a8502021-03-08 15:40:09 +000063#include "com_android_art.h"
64#include "dex/art_dex_file_loader.h"
Orion Hodson4c3ade62021-02-10 14:07:10 +000065#include "dexoptanalyzer.h"
66#include "exec_utils.h"
Orion Hodson957fb152021-04-08 07:52:15 +010067#include "log/log.h"
Orion Hodson4c3ade62021-02-10 14:07:10 +000068#include "palette/palette.h"
69#include "palette/palette_types.h"
70
71#include "odr_artifacts.h"
Orion Hodsonf761f582021-06-09 10:50:57 +010072#include "odr_compilation_log.h"
Orion Hodson4c3ade62021-02-10 14:07:10 +000073#include "odr_config.h"
Orion Hodsonf96c9162021-04-07 10:43:01 +010074#include "odr_fs_utils.h"
Orion Hodson957fb152021-04-08 07:52:15 +010075#include "odr_metrics.h"
Orion Hodson4c3ade62021-02-10 14:07:10 +000076
77namespace art {
78namespace odrefresh {
Orion Hodson947a8502021-03-08 15:40:09 +000079
80namespace apex = com::android::apex;
81namespace art_apex = com::android::art;
82
Orion Hodson4c3ade62021-02-10 14:07:10 +000083namespace {
84
Orion Hodson947a8502021-03-08 15:40:09 +000085// Name of cache info file in the ART Apex artifact cache.
86static constexpr const char* kCacheInfoFile = "cache-info.xml";
87
Orion Hodson4c3ade62021-02-10 14:07:10 +000088static void UsageErrorV(const char* fmt, va_list ap) {
89 std::string error;
90 android::base::StringAppendV(&error, fmt, ap);
91 if (isatty(fileno(stderr))) {
92 std::cerr << error << std::endl;
93 } else {
94 LOG(ERROR) << error;
95 }
96}
97
98static void UsageError(const char* fmt, ...) {
99 va_list ap;
100 va_start(ap, fmt);
101 UsageErrorV(fmt, ap);
102 va_end(ap);
103}
104
105NO_RETURN static void ArgumentError(const char* fmt, ...) {
106 va_list ap;
107 va_start(ap, fmt);
108 UsageErrorV(fmt, ap);
109 va_end(ap);
110 UsageError("Try '--help' for more information.");
111 exit(EX_USAGE);
112}
113
114NO_RETURN static void UsageHelp(const char* argv0) {
115 std::string name(android::base::Basename(argv0));
116 UsageError("Usage: %s ACTION", name.c_str());
117 UsageError("On-device refresh tool for boot class path extensions and system server");
118 UsageError("following an update of the ART APEX.");
119 UsageError("");
120 UsageError("Valid ACTION choices are:");
121 UsageError("");
Orion Hodson947a8502021-03-08 15:40:09 +0000122 UsageError(
123 "--check Check compilation artifacts are up-to-date based on metadata (fast).");
Orion Hodson4c3ade62021-02-10 14:07:10 +0000124 UsageError("--compile Compile boot class path extensions and system_server jars");
Orion Hodsonfcbbdd42021-03-22 17:02:05 +0000125 UsageError(" when necessary.");
Orion Hodson4c3ade62021-02-10 14:07:10 +0000126 UsageError("--force-compile Unconditionally compile the boot class path extensions and");
127 UsageError(" system_server jars.");
Orion Hodson947a8502021-03-08 15:40:09 +0000128 UsageError("--verify Verify artifacts are up-to-date with dexoptanalyzer (slow).");
Orion Hodson4c3ade62021-02-10 14:07:10 +0000129 UsageError("--help Display this help information.");
130 exit(EX_USAGE);
131}
132
133static std::string Concatenate(std::initializer_list<std::string_view> args) {
134 std::stringstream ss;
135 for (auto arg : args) {
136 ss << arg;
137 }
138 return ss.str();
139}
140
Orion Hodson35363cf2021-03-18 14:23:13 +0000141static std::string GetEnvironmentVariableOrDie(const char* name) {
142 const char* value = getenv(name);
143 LOG_ALWAYS_FATAL_IF(value == nullptr, "%s is not defined.", name);
144 return value;
145}
146
Orion Hodson4c3ade62021-02-10 14:07:10 +0000147static std::string QuotePath(std::string_view path) {
148 return Concatenate({"'", path, "'"});
149}
150
151static void EraseFiles(const std::vector<std::unique_ptr<File>>& files) {
152 for (auto& file : files) {
153 file->Erase(/*unlink=*/true);
154 }
155}
156
157// Moves `files` to the directory `output_directory_path`.
158//
159// If any of the files cannot be moved, then all copies of the files are removed from both
160// the original location and the output location.
161//
162// Returns true if all files are moved, false otherwise.
163static bool MoveOrEraseFiles(const std::vector<std::unique_ptr<File>>& files,
164 std::string_view output_directory_path) {
165 std::vector<std::unique_ptr<File>> output_files;
166 for (auto& file : files) {
167 const std::string file_basename(android::base::Basename(file->GetPath()));
168 const std::string output_file_path = Concatenate({output_directory_path, "/", file_basename});
169 const std::string input_file_path = file->GetPath();
170
171 output_files.emplace_back(OS::CreateEmptyFileWriteOnly(output_file_path.c_str()));
172 if (output_files.back() == nullptr) {
173 PLOG(ERROR) << "Failed to open " << QuotePath(output_file_path);
174 output_files.pop_back();
175 EraseFiles(output_files);
176 EraseFiles(files);
177 return false;
178 }
179
Orion Hodson8f198672021-02-27 22:23:18 +0000180 static constexpr mode_t kFileMode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
Orion Hodson3407fb22021-03-17 14:40:51 +0000181 if (fchmod(output_files.back()->Fd(), kFileMode) != 0) {
Orion Hodson8f198672021-02-27 22:23:18 +0000182 PLOG(ERROR) << "Could not set file mode on " << QuotePath(output_file_path);
183 EraseFiles(output_files);
184 EraseFiles(files);
185 return false;
186 }
187
Orion Hodson4c3ade62021-02-10 14:07:10 +0000188 const size_t file_bytes = file->GetLength();
189 if (!output_files.back()->Copy(file.get(), /*offset=*/0, file_bytes)) {
190 PLOG(ERROR) << "Failed to copy " << QuotePath(file->GetPath())
191 << " to " << QuotePath(output_file_path);
192 EraseFiles(output_files);
193 EraseFiles(files);
194 return false;
195 }
196
197 if (!file->Erase(/*unlink=*/true)) {
198 PLOG(ERROR) << "Failed to erase " << QuotePath(file->GetPath());
199 EraseFiles(output_files);
200 EraseFiles(files);
201 return false;
202 }
203
204 if (output_files.back()->FlushCloseOrErase() != 0) {
205 PLOG(ERROR) << "Failed to flush and close file " << QuotePath(output_file_path);
206 EraseFiles(output_files);
207 EraseFiles(files);
208 return false;
209 }
210 }
211 return true;
212}
213
214} // namespace
215
216bool ParseZygoteKind(const char* input, ZygoteKind* zygote_kind) {
217 std::string_view z(input);
218 if (z == "zygote32") {
219 *zygote_kind = ZygoteKind::kZygote32;
220 return true;
221 } else if (z == "zygote32_64") {
222 *zygote_kind = ZygoteKind::kZygote32_64;
223 return true;
224 } else if (z == "zygote64_32") {
225 *zygote_kind = ZygoteKind::kZygote64_32;
226 return true;
227 } else if (z == "zygote64") {
228 *zygote_kind = ZygoteKind::kZygote64;
229 return true;
230 }
231 return false;
232}
233
234class OnDeviceRefresh final {
235 private:
236 // Maximum execution time for odrefresh from start to end.
237 static constexpr time_t kMaximumExecutionSeconds = 300;
238
239 // Maximum execution time for any child process spawned.
240 static constexpr time_t kMaxChildProcessSeconds = 90;
241
Orion Hodson947a8502021-03-08 15:40:09 +0000242 // Configuration to use.
Orion Hodson4c3ade62021-02-10 14:07:10 +0000243 const OdrConfig& config_;
244
Orion Hodson947a8502021-03-08 15:40:09 +0000245 // Path to cache information file that is used to speed up artifact checking.
246 const std::string cache_info_filename_;
247
248 // List of boot extension components that should be compiled.
Orion Hodson4c3ade62021-02-10 14:07:10 +0000249 std::vector<std::string> boot_extension_compilable_jars_;
250
Orion Hodson947a8502021-03-08 15:40:09 +0000251 // List of system_server components that should be compiled.
Orion Hodson4c3ade62021-02-10 14:07:10 +0000252 std::vector<std::string> systemserver_compilable_jars_;
253
254 const time_t start_time_;
255
256 public:
Orion Hodson947a8502021-03-08 15:40:09 +0000257 explicit OnDeviceRefresh(const OdrConfig& config)
258 : config_{config},
259 cache_info_filename_{Concatenate({kOdrefreshArtifactDirectory, "/", kCacheInfoFile})},
260 start_time_{time(nullptr)} {
Orion Hodson4c3ade62021-02-10 14:07:10 +0000261 for (const std::string& jar : android::base::Split(config_.GetDex2oatBootClasspath(), ":")) {
262 // Boot class path extensions are those not in the ART APEX. Updatable APEXes should not
263 // have DEX files in the DEX2OATBOOTCLASSPATH. At the time of writing i18n is a non-updatable
264 // APEX and so does appear in the DEX2OATBOOTCLASSPATH.
265 if (!LocationIsOnArtModule(jar)) {
266 boot_extension_compilable_jars_.emplace_back(jar);
267 }
268 }
269
270 for (const std::string& jar : android::base::Split(config_.GetSystemServerClasspath(), ":")) {
271 // Only consider DEX files on the SYSTEMSERVERCLASSPATH for compilation that do not reside
272 // in APEX modules. Otherwise, we'll recompile on boot any time one of these APEXes updates.
273 if (!LocationIsOnApex(jar)) {
274 systemserver_compilable_jars_.emplace_back(jar);
275 }
276 }
277 }
278
279 time_t GetExecutionTimeUsed() const { return time(nullptr) - start_time_; }
280
281 time_t GetExecutionTimeRemaining() const {
282 return kMaximumExecutionSeconds - GetExecutionTimeUsed();
283 }
284
285 time_t GetSubprocessTimeout() const {
286 return std::max(GetExecutionTimeRemaining(), kMaxChildProcessSeconds);
287 }
288
Orion Hodson947a8502021-03-08 15:40:09 +0000289 // Gets the `ApexInfo` associated with the currently active ART APEX.
290 std::optional<apex::ApexInfo> GetArtApexInfo() const {
291 auto info_list = apex::readApexInfoList(config_.GetApexInfoListFile().c_str());
Orion Hodson4c3ade62021-02-10 14:07:10 +0000292 if (!info_list.has_value()) {
Orion Hodson947a8502021-03-08 15:40:09 +0000293 return {};
Orion Hodson4c3ade62021-02-10 14:07:10 +0000294 }
295
Orion Hodson947a8502021-03-08 15:40:09 +0000296 for (const apex::ApexInfo& info : info_list->getApexInfo()) {
Orion Hodson4c3ade62021-02-10 14:07:10 +0000297 if (info.getIsActive() && info.getModuleName() == "com.android.art") {
Orion Hodson947a8502021-03-08 15:40:09 +0000298 return info;
299 }
300 }
301 return {};
302 }
303
304 // Reads the ART APEX cache information (if any) found in `kOdrefreshArtifactDirectory`.
305 std::optional<art_apex::CacheInfo> ReadCacheInfo() {
306 return art_apex::read(cache_info_filename_.c_str());
307 }
308
309 // Write ART APEX cache information to `kOdrefreshArtifactDirectory`.
310 void WriteCacheInfo() const {
311 if (OS::FileExists(cache_info_filename_.c_str())) {
312 if (unlink(cache_info_filename_.c_str()) != 0) {
313 PLOG(ERROR) << "Failed to unlink() file " << QuotePath(cache_info_filename_);
Orion Hodson4c3ade62021-02-10 14:07:10 +0000314 }
315 }
316
Orion Hodson84ebf3c2021-03-22 17:03:42 +0000317 const std::string dir_name = android::base::Dirname(cache_info_filename_);
318 if (!EnsureDirectoryExists(dir_name)) {
319 LOG(ERROR) << "Could not create directory: " << QuotePath(dir_name);
320 return;
321 }
322
Orion Hodson947a8502021-03-08 15:40:09 +0000323 std::optional<art_apex::ArtModuleInfo> art_module_info = GenerateArtModuleInfo();
324 if (!art_module_info.has_value()) {
325 LOG(ERROR) << "Unable to generate cache provenance";
326 return;
327 }
328
329 // There can be only one CacheProvence in the XML file, but `xsdc` does not have
330 // minOccurs/maxOccurs in the xsd schema.
331 const std::vector<art_apex::ArtModuleInfo> art_module_infos { art_module_info.value() };
332
333 std::optional<std::vector<art_apex::Component>> bcp_components =
334 GenerateBootExtensionComponents();
335 if (!bcp_components.has_value()) {
Orion Hodson84ebf3c2021-03-22 17:03:42 +0000336 LOG(ERROR) << "No boot classpath extension components.";
Orion Hodson947a8502021-03-08 15:40:09 +0000337 return;
338 }
339
340 std::optional<std::vector<art_apex::Component>> system_server_components =
341 GenerateSystemServerComponents();
342 if (!system_server_components.has_value()) {
Orion Hodson84ebf3c2021-03-22 17:03:42 +0000343 LOG(ERROR) << "No system_server extension components.";
Orion Hodson947a8502021-03-08 15:40:09 +0000344 return;
345 }
346
347 std::ofstream out(cache_info_filename_.c_str());
Orion Hodson84ebf3c2021-03-22 17:03:42 +0000348 art_apex::CacheInfo info{art_module_infos,
349 {{art_apex::Dex2oatBootClasspath{bcp_components.value()}}},
350 {{art_apex::SystemServerClasspath{system_server_components.value()}}}};
Orion Hodson947a8502021-03-08 15:40:09 +0000351
352 art_apex::write(out, info);
353 }
354
355 // Returns cache provenance information based on the current ART APEX version and filesystem
356 // information.
357 std::optional<art_apex::ArtModuleInfo> GenerateArtModuleInfo() const {
358 auto info = GetArtApexInfo();
359 if (!info.has_value()) {
360 LOG(ERROR) << "Could not update " << QuotePath(cache_info_filename_) << " : no ART Apex info";
361 return {};
362 }
363 return art_apex::ArtModuleInfo{info->getVersionCode(), info->getVersionName()};
364 }
365
366 bool CheckComponents(const std::vector<art_apex::Component>& expected_components,
367 const std::vector<art_apex::Component>& actual_components,
368 std::string* error_msg) const {
369 if (expected_components.size() != actual_components.size()) {
370 return false;
371 }
372
373 for (size_t i = 0; i < expected_components.size(); ++i) {
374 const art_apex::Component& expected = expected_components[i];
375 const art_apex::Component& actual = actual_components[i];
376
377 if (expected.getFile() != actual.getFile()) {
378 *error_msg = android::base::StringPrintf("Component %zu file differs ('%s' != '%s')",
379 i,
380 expected.getFile().c_str(),
381 actual.getFile().c_str());
382 return false;
383 }
384 if (expected.getSize() != actual.getSize()) {
385 *error_msg = android::base::StringPrintf("Component %zu size differs (%" PRIu64
386 " != %" PRIu64 ")",
387 i,
388 expected.getSize(),
389 actual.getSize());
390 return false;
391 }
392 if (expected.getChecksums() != actual.getChecksums()) {
393 *error_msg = android::base::StringPrintf("Component %zu checksums differ ('%s' != '%s')",
394 i,
395 expected.getChecksums().c_str(),
396 actual.getChecksums().c_str());
397 return false;
398 }
399 }
400
401 return true;
402 }
403
404 std::vector<art_apex::Component> GenerateComponents(const std::vector<std::string>& jars) const {
405 std::vector<art_apex::Component> components;
406
407 ArtDexFileLoader loader;
408 for (const std::string& path : jars) {
409 struct stat sb;
410 if (stat(path.c_str(), &sb) == -1) {
411 PLOG(ERROR) << "Failed to get component: " << QuotePath(path);
412 return {};
413 }
414
415 std::vector<uint32_t> checksums;
416 std::vector<std::string> dex_locations;
417 std::string error_msg;
418 if (!loader.GetMultiDexChecksums(path.c_str(), &checksums, &dex_locations, &error_msg)) {
419 LOG(ERROR) << "Failed to get components: " << error_msg;
420 return {};
421 }
422
423 std::ostringstream oss;
424 for (size_t i = 0; i < checksums.size(); ++i) {
425 if (i != 0) {
426 oss << ';';
427 }
428 oss << android::base::StringPrintf("%08x", checksums[i]);
429 }
430 const std::string checksum = oss.str();
431
432 components.emplace_back(
433 art_apex::Component{path, static_cast<uint64_t>(sb.st_size), checksum});
434 }
435
436 return components;
437 }
438
439 std::vector<art_apex::Component> GenerateBootExtensionComponents() const {
440 return GenerateComponents(boot_extension_compilable_jars_);
441 }
442
443 std::vector<art_apex::Component> GenerateSystemServerComponents() const {
444 return GenerateComponents(systemserver_compilable_jars_);
445 }
446
447 // Checks whether a group of artifacts exists. Returns true if all are present, false otherwise.
448 static bool ArtifactsExist(const OdrArtifacts& artifacts, /*out*/ std::string* error_msg) {
449 const auto paths = {
450 artifacts.ImagePath().c_str(), artifacts.OatPath().c_str(), artifacts.VdexPath().c_str()};
451 for (const char* path : paths) {
452 if (!OS::FileExists(path)) {
453 if (errno == EACCES) {
454 PLOG(ERROR) << "Failed to stat() " << path;
455 }
456 *error_msg = "Missing file: " + QuotePath(path);
457 return false;
458 }
459 }
460 return true;
461 }
462
463 // Checks whether all boot extension artifacts are present on /data. Returns true if all are
464 // present, false otherwise.
Orion Hodson3407fb22021-03-17 14:40:51 +0000465 WARN_UNUSED bool BootExtensionArtifactsExistOnData(const InstructionSet isa,
466 /*out*/ std::string* error_msg) const {
Orion Hodson947a8502021-03-08 15:40:09 +0000467 const std::string apexdata_image_location = GetBootImageExtensionImagePath(isa);
468 const OdrArtifacts artifacts = OdrArtifacts::ForBootImageExtension(apexdata_image_location);
469 return ArtifactsExist(artifacts, error_msg);
470 }
471
Orion Hodson3407fb22021-03-17 14:40:51 +0000472 // Checks whether all system_server artifacts are present on /data. The artifacts are checked in
473 // their order of compilation. Returns true if all are present, false otherwise.
474 WARN_UNUSED bool SystemServerArtifactsExistOnData(/*out*/ std::string* error_msg) const {
Orion Hodson947a8502021-03-08 15:40:09 +0000475 for (const std::string& jar_path : systemserver_compilable_jars_) {
476 const std::string image_location = GetSystemServerImagePath(/*on_system=*/false, jar_path);
477 const OdrArtifacts artifacts = OdrArtifacts::ForSystemServer(image_location);
478 if (!ArtifactsExist(artifacts, error_msg)) {
479 return false;
480 }
481 }
482 return true;
483 }
484
Orion Hodson957fb152021-04-08 07:52:15 +0100485 WARN_UNUSED ExitCode CheckArtifactsAreUpToDate(OdrMetrics& metrics) {
486 metrics.SetStage(OdrMetrics::Stage::kCheck);
487
Orion Hodson3407fb22021-03-17 14:40:51 +0000488 // Clean-up helper used to simplify clean-ups and handling failures there.
489 auto cleanup_return = [this](ExitCode exit_code) {
490 return CleanApexdataDirectory() ? exit_code : ExitCode::kCleanupFailed;
491 };
492
Orion Hodson947a8502021-03-08 15:40:09 +0000493 const auto apex_info = GetArtApexInfo();
494 if (!apex_info.has_value()) {
Orion Hodson957fb152021-04-08 07:52:15 +0100495 // This should never happen, further up-to-date checks are not possible if it does.
Orion Hodson947a8502021-03-08 15:40:09 +0000496 LOG(ERROR) << "Could not get ART APEX info.";
Orion Hodson957fb152021-04-08 07:52:15 +0100497 metrics.SetTrigger(OdrMetrics::Trigger::kApexVersionMismatch);
Orion Hodson3407fb22021-03-17 14:40:51 +0000498 return cleanup_return(ExitCode::kCompilationRequired);
Orion Hodson947a8502021-03-08 15:40:09 +0000499 }
500
501 if (apex_info->getIsFactory()) {
502 // Remove any artifacts on /data as they are not necessary and no compilation is necessary.
Orion Hodson84ebf3c2021-03-22 17:03:42 +0000503 LOG(INFO) << "Factory APEX mounted.";
Orion Hodson3407fb22021-03-17 14:40:51 +0000504 return cleanup_return(ExitCode::kOkay);
Orion Hodson947a8502021-03-08 15:40:09 +0000505 }
506
507 if (!OS::FileExists(cache_info_filename_.c_str())) {
Orion Hodson84ebf3c2021-03-22 17:03:42 +0000508 // If the cache info file does not exist, assume compilation is required because the
509 // file is missing and because the current ART APEX is not factory installed.
Orion Hodson947a8502021-03-08 15:40:09 +0000510 PLOG(ERROR) << "No prior cache-info file: " << QuotePath(cache_info_filename_);
Orion Hodson957fb152021-04-08 07:52:15 +0100511 metrics.SetTrigger(OdrMetrics::Trigger::kApexVersionMismatch);
Orion Hodson3407fb22021-03-17 14:40:51 +0000512 return cleanup_return(ExitCode::kCompilationRequired);
Orion Hodson947a8502021-03-08 15:40:09 +0000513 }
514
515 // Get and parse the ART APEX cache info file.
516 std::optional<art_apex::CacheInfo> cache_info = ReadCacheInfo();
517 if (!cache_info.has_value()) {
Orion Hodson957fb152021-04-08 07:52:15 +0100518 // This should never happen, further up-to-date checks are not possible if it does.
Orion Hodson947a8502021-03-08 15:40:09 +0000519 PLOG(ERROR) << "Failed to read cache-info file: " << QuotePath(cache_info_filename_);
Orion Hodson957fb152021-04-08 07:52:15 +0100520 metrics.SetTrigger(OdrMetrics::Trigger::kUnknown);
Orion Hodson3407fb22021-03-17 14:40:51 +0000521 return cleanup_return(ExitCode::kCompilationRequired);
Orion Hodson947a8502021-03-08 15:40:09 +0000522 }
523
524 // Generate current module info for the current ART APEX.
525 const auto current_info = GenerateArtModuleInfo();
526 if (!current_info.has_value()) {
Orion Hodson957fb152021-04-08 07:52:15 +0100527 // This should never happen, further up-to-date checks are not possible if it does.
Orion Hodson947a8502021-03-08 15:40:09 +0000528 LOG(ERROR) << "Failed to generate cache provenance.";
Orion Hodson957fb152021-04-08 07:52:15 +0100529 metrics.SetTrigger(OdrMetrics::Trigger::kUnknown);
Orion Hodson3407fb22021-03-17 14:40:51 +0000530 return cleanup_return(ExitCode::kCompilationRequired);
Orion Hodson947a8502021-03-08 15:40:09 +0000531 }
532
Orion Hodson957fb152021-04-08 07:52:15 +0100533 // Record ART Apex version for metrics reporting.
534 metrics.SetArtApexVersion(current_info->getVersionCode());
535
Orion Hodson947a8502021-03-08 15:40:09 +0000536 // Check whether the current cache ART module info differs from the current ART module info.
537 // Always check APEX version.
538 const auto cached_info = cache_info->getFirstArtModuleInfo();
Orion Hodson957fb152021-04-08 07:52:15 +0100539
Orion Hodson947a8502021-03-08 15:40:09 +0000540 if (cached_info->getVersionCode() != current_info->getVersionCode()) {
541 LOG(INFO) << "ART APEX version code mismatch ("
542 << cached_info->getVersionCode()
543 << " != " << current_info->getVersionCode() << ").";
Orion Hodson957fb152021-04-08 07:52:15 +0100544 metrics.SetTrigger(OdrMetrics::Trigger::kApexVersionMismatch);
Orion Hodson3407fb22021-03-17 14:40:51 +0000545 return cleanup_return(ExitCode::kCompilationRequired);
Orion Hodson947a8502021-03-08 15:40:09 +0000546 }
547
548 if (cached_info->getVersionName() != current_info->getVersionName()) {
549 LOG(INFO) << "ART APEX version code mismatch ("
550 << cached_info->getVersionName()
551 << " != " << current_info->getVersionName() << ").";
Orion Hodson957fb152021-04-08 07:52:15 +0100552 metrics.SetTrigger(OdrMetrics::Trigger::kApexVersionMismatch);
Orion Hodson3407fb22021-03-17 14:40:51 +0000553 return cleanup_return(ExitCode::kCompilationRequired);
Orion Hodson947a8502021-03-08 15:40:09 +0000554 }
555
556 // Check boot class components.
557 //
558 // This checks the size and checksums of odrefresh compilable files on the DEX2OATBOOTCLASSPATH
559 // (the Odrefresh constructor determines which files are compilable). If the number of files
560 // there changes, or their size or checksums change then compilation will be triggered.
561 //
562 // The boot class components may change unexpectedly, for example an OTA could update
563 // framework.jar.
564 const std::vector<art_apex::Component> expected_bcp_components =
565 GenerateBootExtensionComponents();
566 if (expected_bcp_components.size() != 0 &&
567 (!cache_info->hasDex2oatBootClasspath() ||
568 !cache_info->getFirstDex2oatBootClasspath()->hasComponent())) {
569 LOG(INFO) << "Missing Dex2oatBootClasspath components.";
Orion Hodson957fb152021-04-08 07:52:15 +0100570 metrics.SetTrigger(OdrMetrics::Trigger::kDexFilesChanged);
Orion Hodson3407fb22021-03-17 14:40:51 +0000571 return cleanup_return(ExitCode::kCompilationRequired);
Orion Hodson947a8502021-03-08 15:40:09 +0000572 }
573
574 std::string error_msg;
575 const std::vector<art_apex::Component>& bcp_components =
576 cache_info->getFirstDex2oatBootClasspath()->getComponent();
577 if (!CheckComponents(expected_bcp_components, bcp_components, &error_msg)) {
578 LOG(INFO) << "Dex2OatClasspath components mismatch: " << error_msg;
Orion Hodson957fb152021-04-08 07:52:15 +0100579 metrics.SetTrigger(OdrMetrics::Trigger::kDexFilesChanged);
Orion Hodson3407fb22021-03-17 14:40:51 +0000580 return cleanup_return(ExitCode::kCompilationRequired);
Orion Hodson947a8502021-03-08 15:40:09 +0000581 }
582
583 // Check system server components.
584 //
585 // This checks the size and checksums of odrefresh compilable files on the
586 // SYSTEMSERVERCLASSPATH (the Odrefresh constructor determines which files are compilable). If
587 // the number of files there changes, or their size or checksums change then compilation will be
588 // triggered.
589 //
590 // The system_server components may change unexpectedly, for example an OTA could update
591 // services.jar.
Orion Hodson3407fb22021-03-17 14:40:51 +0000592 auto cleanup_system_server_return = [this](ExitCode exit_code) {
593 return RemoveSystemServerArtifactsFromData() ? exit_code : ExitCode::kCleanupFailed;
594 };
595
Orion Hodson947a8502021-03-08 15:40:09 +0000596 const std::vector<art_apex::Component> expected_system_server_components =
597 GenerateSystemServerComponents();
598 if (expected_system_server_components.size() != 0 &&
599 (!cache_info->hasSystemServerClasspath() ||
600 !cache_info->getFirstSystemServerClasspath()->hasComponent())) {
601 LOG(INFO) << "Missing SystemServerClasspath components.";
Orion Hodson957fb152021-04-08 07:52:15 +0100602 metrics.SetTrigger(OdrMetrics::Trigger::kDexFilesChanged);
Orion Hodson3407fb22021-03-17 14:40:51 +0000603 return cleanup_system_server_return(ExitCode::kCompilationRequired);
Orion Hodson947a8502021-03-08 15:40:09 +0000604 }
605
606 const std::vector<art_apex::Component>& system_server_components =
607 cache_info->getFirstSystemServerClasspath()->getComponent();
608 if (!CheckComponents(expected_system_server_components, system_server_components, &error_msg)) {
609 LOG(INFO) << "SystemServerClasspath components mismatch: " << error_msg;
Orion Hodson957fb152021-04-08 07:52:15 +0100610 metrics.SetTrigger(OdrMetrics::Trigger::kDexFilesChanged);
Orion Hodson3407fb22021-03-17 14:40:51 +0000611 return cleanup_system_server_return(ExitCode::kCompilationRequired);
Orion Hodson947a8502021-03-08 15:40:09 +0000612 }
613
Orion Hodson263c39e2021-05-07 10:17:14 +0100614 // Cache info looks good, check all compilation artifacts exist.
Orion Hodson3407fb22021-03-17 14:40:51 +0000615 auto cleanup_boot_extensions_return = [this](ExitCode exit_code, InstructionSet isa) {
616 return RemoveBootExtensionArtifactsFromData(isa) ? exit_code : ExitCode::kCleanupFailed;
617 };
618
Orion Hodson947a8502021-03-08 15:40:09 +0000619 for (const InstructionSet isa : config_.GetBootExtensionIsas()) {
620 if (!BootExtensionArtifactsExistOnData(isa, &error_msg)) {
621 LOG(INFO) << "Incomplete boot extension artifacts. " << error_msg;
Orion Hodson957fb152021-04-08 07:52:15 +0100622 metrics.SetTrigger(OdrMetrics::Trigger::kMissingArtifacts);
Orion Hodson3407fb22021-03-17 14:40:51 +0000623 return cleanup_boot_extensions_return(ExitCode::kCompilationRequired, isa);
Orion Hodson947a8502021-03-08 15:40:09 +0000624 }
625 }
626
627 if (!SystemServerArtifactsExistOnData(&error_msg)) {
Orion Hodson3407fb22021-03-17 14:40:51 +0000628 LOG(INFO) << "Incomplete system_server artifacts. " << error_msg;
629 // No clean-up is required here: we have boot extension artifacts. The method
630 // `SystemServerArtifactsExistOnData()` checks in compilation order so it is possible some of
631 // the artifacts are here. We likely ran out of space compiling the system_server artifacts.
632 // Any artifacts present are usable.
Orion Hodson957fb152021-04-08 07:52:15 +0100633 metrics.SetTrigger(OdrMetrics::Trigger::kMissingArtifacts);
Orion Hodson3407fb22021-03-17 14:40:51 +0000634 return ExitCode::kCompilationRequired;
Orion Hodson947a8502021-03-08 15:40:09 +0000635 }
636
637 return ExitCode::kOkay;
Orion Hodson4c3ade62021-02-10 14:07:10 +0000638 }
639
640 static void AddDex2OatCommonOptions(/*inout*/ std::vector<std::string>& args) {
641 args.emplace_back("--android-root=out/empty");
642 args.emplace_back("--abort-on-hard-verifier-error");
Orion Hodsona2e2eb12021-03-16 18:05:42 +0000643 args.emplace_back("--no-abort-on-soft-verifier-error");
Orion Hodson4c3ade62021-02-10 14:07:10 +0000644 args.emplace_back("--compilation-reason=boot");
Orion Hodsona2e2eb12021-03-16 18:05:42 +0000645 args.emplace_back("--image-format=lz4");
646 args.emplace_back("--force-determinism");
Orion Hodson4c3ade62021-02-10 14:07:10 +0000647 args.emplace_back("--resolve-startup-const-strings=true");
648 }
649
650 static void AddDex2OatConcurrencyArguments(/*inout*/ std::vector<std::string>& args) {
651 static constexpr std::pair<const char*, const char*> kPropertyArgPairs[] = {
652 std::make_pair("dalvik.vm.boot-dex2oat-cpu-set", "--cpu-set="),
653 std::make_pair("dalvik.vm.boot-dex2oat-threads", "-j"),
654 };
655 for (auto property_arg_pair : kPropertyArgPairs) {
656 auto [property, arg] = property_arg_pair;
657 std::string value = android::base::GetProperty(property, {});
658 if (!value.empty()) {
659 args.push_back(arg + value);
660 }
661 }
662 }
663
664 static void AddDex2OatDebugInfo(/*inout*/ std::vector<std::string>& args) {
Orion Hodson4c3ade62021-02-10 14:07:10 +0000665 args.emplace_back("--generate-mini-debug-info");
666 args.emplace_back("--strip");
667 }
668
669 static void AddDex2OatInstructionSet(/*inout*/ std::vector<std::string> args,
Orion Hodson3407fb22021-03-17 14:40:51 +0000670 InstructionSet isa) {
Orion Hodson4c3ade62021-02-10 14:07:10 +0000671 const char* isa_str = GetInstructionSetString(isa);
672 args.emplace_back(Concatenate({"--instruction-set=", isa_str}));
673 }
674
Victor Hsieha9f80fc2021-05-17 17:28:26 -0700675 static std::unique_ptr<File> AddDex2OatProfileAndCompilerFilter(
676 /*inout*/ std::vector<std::string>& args,
677 const std::string& profile_path) {
678 std::unique_ptr<File> profile_file(OS::OpenFileForReading(profile_path.c_str()));
679 if (profile_file && profile_file->IsOpened()) {
680 args.emplace_back(android::base::StringPrintf("--profile-file-fd=%d", profile_file->Fd()));
Orion Hodson4c3ade62021-02-10 14:07:10 +0000681 args.emplace_back("--compiler-filter=speed-profile");
682 } else {
683 args.emplace_back("--compiler-filter=speed");
684 }
Victor Hsieha9f80fc2021-05-17 17:28:26 -0700685 return profile_file;
Orion Hodson4c3ade62021-02-10 14:07:10 +0000686 }
687
Victor Hsieh0be3da62021-06-14 12:37:03 -0700688 static bool AddBootClasspathFds(/*inout*/ std::vector<std::string>& args,
689 /*inout*/ std::vector<std::unique_ptr<File>>& output_files,
690 const std::vector<std::string>& bcp_jars) {
691 auto bcp_fds = std::vector<std::string>();
692 for (const std::string& jar : bcp_jars) {
693 std::unique_ptr<File> jar_file(OS::OpenFileForReading(jar.c_str()));
694 if (!jar_file->IsValid()) {
695 LOG(ERROR) << "Failed to open a BCP jar " << jar;
696 return false;
697 }
698 bcp_fds.push_back(std::to_string(jar_file->Fd()));
699 output_files.push_back(std::move(jar_file));
700 }
701 args.emplace_back("--runtime-arg");
702 args.emplace_back(Concatenate({"-Xbootclasspathfds:", android::base::Join(bcp_fds, ':')}));
703 return true;
704 }
705
Orion Hodson3407fb22021-03-17 14:40:51 +0000706 WARN_UNUSED bool VerifySystemServerArtifactsAreUpToDate(bool on_system) const {
Orion Hodson4c3ade62021-02-10 14:07:10 +0000707 std::vector<std::string> classloader_context;
708 for (const std::string& jar_path : systemserver_compilable_jars_) {
709 std::vector<std::string> args;
710 args.emplace_back(config_.GetDexOptAnalyzer());
711 args.emplace_back("--dex-file=" + jar_path);
712
713 const std::string image_location = GetSystemServerImagePath(on_system, jar_path);
714
715 // odrefresh produces app-image files, but these are not guaranteed for those pre-installed
716 // on /system.
717 if (!on_system && !OS::FileExists(image_location.c_str(), true)) {
718 LOG(INFO) << "Missing image file: " << QuotePath(image_location);
719 return false;
720 }
721
722 // Generate set of artifacts that are output by compilation.
723 OdrArtifacts artifacts = OdrArtifacts::ForSystemServer(image_location);
724 if (!on_system) {
725 CHECK_EQ(artifacts.OatPath(),
726 GetApexDataOdexFilename(jar_path, config_.GetSystemServerIsa()));
727 CHECK_EQ(artifacts.ImagePath(),
728 GetApexDataDalvikCacheFilename(jar_path, config_.GetSystemServerIsa(), "art"));
729 CHECK_EQ(artifacts.OatPath(),
730 GetApexDataDalvikCacheFilename(jar_path, config_.GetSystemServerIsa(), "odex"));
731 CHECK_EQ(artifacts.VdexPath(),
732 GetApexDataDalvikCacheFilename(jar_path, config_.GetSystemServerIsa(), "vdex"));
733 }
734
735 // Associate inputs and outputs with dexoptanalyzer arguments.
736 std::pair<const std::string, const char*> location_args[] = {
737 std::make_pair(artifacts.OatPath(), "--oat-fd="),
738 std::make_pair(artifacts.VdexPath(), "--vdex-fd="),
739 std::make_pair(jar_path, "--zip-fd=")
740 };
741
742 // Open file descriptors for dexoptanalyzer file inputs and add to the command-line.
743 std::vector<std::unique_ptr<File>> files;
744 for (const auto& location_arg : location_args) {
745 auto& [location, arg] = location_arg;
746 std::unique_ptr<File> file(OS::OpenFileForReading(location.c_str()));
747 if (file == nullptr) {
748 PLOG(ERROR) << "Failed to open \"" << location << "\"";
749 return false;
750 }
751 args.emplace_back(android::base::StringPrintf("%s%d", arg, file->Fd()));
752 files.emplace_back(file.release());
753 }
754
755 const std::string basename(android::base::Basename(jar_path));
756 const std::string root = GetAndroidRoot();
757 const std::string profile_file = Concatenate({root, "/framework/", basename, ".prof"});
758 if (OS::FileExists(profile_file.c_str())) {
759 args.emplace_back("--compiler-filter=speed-profile");
760 } else {
761 args.emplace_back("--compiler-filter=speed");
762 }
763
764 args.emplace_back(
765 Concatenate({"--image=", GetBootImage(), ":", GetBootImageExtensionImage(on_system)}));
766 args.emplace_back(
767 Concatenate({"--isa=", GetInstructionSetString(config_.GetSystemServerIsa())}));
768 args.emplace_back("--runtime-arg");
769 args.emplace_back(Concatenate({"-Xbootclasspath:", config_.GetDex2oatBootClasspath()}));
770 args.emplace_back(Concatenate(
771 {"--class-loader-context=PCL[", android::base::Join(classloader_context, ':'), "]"}));
772
773 classloader_context.emplace_back(jar_path);
774
775 LOG(INFO) << "Checking " << jar_path << ": " << android::base::Join(args, ' ');
776 std::string error_msg;
777 bool timed_out = false;
778 const time_t timeout = GetSubprocessTimeout();
779 const int dexoptanalyzer_result = ExecAndReturnCode(args, timeout, &timed_out, &error_msg);
780 if (dexoptanalyzer_result == -1) {
781 LOG(ERROR) << "Unexpected exit from dexoptanalyzer: " << error_msg;
782 if (timed_out) {
783 // TODO(oth): record metric for timeout.
784 }
785 return false;
786 }
787 LOG(INFO) << "dexoptanalyzer returned " << dexoptanalyzer_result;
788
789 bool unexpected_result = true;
790 switch (static_cast<dexoptanalyzer::ReturnCode>(dexoptanalyzer_result)) {
791 case art::dexoptanalyzer::ReturnCode::kNoDexOptNeeded:
792 unexpected_result = false;
793 break;
794
795 // Recompile needed
796 case art::dexoptanalyzer::ReturnCode::kDex2OatFromScratch:
797 case art::dexoptanalyzer::ReturnCode::kDex2OatForBootImageOat:
798 case art::dexoptanalyzer::ReturnCode::kDex2OatForFilterOat:
799 case art::dexoptanalyzer::ReturnCode::kDex2OatForBootImageOdex:
800 case art::dexoptanalyzer::ReturnCode::kDex2OatForFilterOdex:
801 return false;
802
803 // Unexpected issues (note no default-case here to catch missing enum values, but the
804 // return code from dexoptanalyzer may also be outside expected values, such as a
805 // process crash.
806 case art::dexoptanalyzer::ReturnCode::kFlattenClassLoaderContextSuccess:
807 case art::dexoptanalyzer::ReturnCode::kErrorInvalidArguments:
808 case art::dexoptanalyzer::ReturnCode::kErrorCannotCreateRuntime:
809 case art::dexoptanalyzer::ReturnCode::kErrorUnknownDexOptNeeded:
810 break;
811 }
812
813 if (unexpected_result) {
814 LOG(ERROR) << "Unexpected result from dexoptanalyzer: " << dexoptanalyzer_result;
815 return false;
816 }
817 }
818 return true;
819 }
820
Orion Hodson3407fb22021-03-17 14:40:51 +0000821 WARN_UNUSED bool RemoveSystemServerArtifactsFromData() const {
Orion Hodson4c3ade62021-02-10 14:07:10 +0000822 if (config_.GetDryRun()) {
823 LOG(INFO) << "Removal of system_server artifacts on /data skipped (dry-run).";
Orion Hodson3407fb22021-03-17 14:40:51 +0000824 return true;
Orion Hodson4c3ade62021-02-10 14:07:10 +0000825 }
Orion Hodson947a8502021-03-08 15:40:09 +0000826
Orion Hodson3407fb22021-03-17 14:40:51 +0000827 bool success = true;
Orion Hodson4c3ade62021-02-10 14:07:10 +0000828 for (const std::string& jar_path : systemserver_compilable_jars_) {
829 const std::string image_location =
830 GetSystemServerImagePath(/*on_system=*/false, jar_path);
831 const OdrArtifacts artifacts = OdrArtifacts::ForSystemServer(image_location);
832 LOG(INFO) << "Removing system_server artifacts on /data for " << QuotePath(jar_path);
Orion Hodson3407fb22021-03-17 14:40:51 +0000833 success &= RemoveArtifacts(artifacts);
Orion Hodson4c3ade62021-02-10 14:07:10 +0000834 }
Orion Hodson3407fb22021-03-17 14:40:51 +0000835 return success;
Orion Hodson4c3ade62021-02-10 14:07:10 +0000836 }
837
Orion Hodson947a8502021-03-08 15:40:09 +0000838 // Verify the validity of system server artifacts on both /system and /data.
Orion Hodson4c3ade62021-02-10 14:07:10 +0000839 // This method has the side-effect of removing system server artifacts on /data, if there are
840 // valid artifacts on /system, or if the artifacts on /data are not valid.
841 // Returns true if valid artifacts are found.
Orion Hodson3407fb22021-03-17 14:40:51 +0000842 WARN_UNUSED bool VerifySystemServerArtifactsAreUpToDate() const {
Orion Hodson947a8502021-03-08 15:40:09 +0000843 bool system_ok = VerifySystemServerArtifactsAreUpToDate(/*on_system=*/true);
Orion Hodson4c3ade62021-02-10 14:07:10 +0000844 LOG(INFO) << "system_server artifacts on /system are " << (system_ok ? "ok" : "stale");
Orion Hodson947a8502021-03-08 15:40:09 +0000845 bool data_ok = VerifySystemServerArtifactsAreUpToDate(/*on_system=*/false);
Orion Hodson4c3ade62021-02-10 14:07:10 +0000846 LOG(INFO) << "system_server artifacts on /data are " << (data_ok ? "ok" : "stale");
Orion Hodson4c3ade62021-02-10 14:07:10 +0000847 return system_ok || data_ok;
848 }
849
850 // Check the validity of boot class path extension artifacts.
851 //
852 // Returns true if artifacts exist and are valid according to dexoptanalyzer.
Orion Hodson3407fb22021-03-17 14:40:51 +0000853 WARN_UNUSED bool VerifyBootExtensionArtifactsAreUpToDate(const InstructionSet isa,
854 bool on_system) const {
Orion Hodson4c3ade62021-02-10 14:07:10 +0000855 const std::string dex_file = boot_extension_compilable_jars_.front();
856 const std::string image_location = GetBootImageExtensionImage(on_system);
857
858 std::vector<std::string> args;
859 args.emplace_back(config_.GetDexOptAnalyzer());
860 args.emplace_back("--validate-bcp");
861 args.emplace_back(Concatenate({"--image=", GetBootImage(), ":", image_location}));
862 args.emplace_back(Concatenate({"--isa=", GetInstructionSetString(isa)}));
863 args.emplace_back("--runtime-arg");
864 args.emplace_back(Concatenate({"-Xbootclasspath:", config_.GetDex2oatBootClasspath()}));
865
866 LOG(INFO) << "Checking " << dex_file << ": " << android::base::Join(args, ' ');
867
868 std::string error_msg;
869 bool timed_out = false;
870 const time_t timeout = GetSubprocessTimeout();
871 const int dexoptanalyzer_result = ExecAndReturnCode(args, timeout, &timed_out, &error_msg);
872 if (dexoptanalyzer_result == -1) {
873 LOG(ERROR) << "Unexpected exit from dexoptanalyzer: " << error_msg;
874 if (timed_out) {
875 // TODO(oth): record metric for timeout.
876 }
877 return false;
878 }
879 auto rc = static_cast<dexoptanalyzer::ReturnCode>(dexoptanalyzer_result);
880 if (rc == dexoptanalyzer::ReturnCode::kNoDexOptNeeded) {
881 return true;
882 }
883 return false;
884 }
885
886 // Remove boot extension artifacts from /data.
Orion Hodson3407fb22021-03-17 14:40:51 +0000887 WARN_UNUSED bool RemoveBootExtensionArtifactsFromData(InstructionSet isa) const {
Orion Hodson4c3ade62021-02-10 14:07:10 +0000888 if (config_.GetDryRun()) {
889 LOG(INFO) << "Removal of bcp extension artifacts on /data skipped (dry-run).";
Orion Hodson3407fb22021-03-17 14:40:51 +0000890 return true;
Orion Hodson4c3ade62021-02-10 14:07:10 +0000891 }
Orion Hodson3407fb22021-03-17 14:40:51 +0000892
893 bool success = true;
894 if (isa == config_.GetSystemServerIsa()) {
895 // system_server artifacts are invalid without boot extension artifacts.
896 success &= RemoveSystemServerArtifactsFromData();
897 }
898
Orion Hodson4c3ade62021-02-10 14:07:10 +0000899 const std::string apexdata_image_location = GetBootImageExtensionImagePath(isa);
900 LOG(INFO) << "Removing boot class path artifacts on /data for "
901 << QuotePath(apexdata_image_location);
Orion Hodson3407fb22021-03-17 14:40:51 +0000902 success &= RemoveArtifacts(OdrArtifacts::ForBootImageExtension(apexdata_image_location));
903 return success;
Orion Hodson4c3ade62021-02-10 14:07:10 +0000904 }
905
Orion Hodson947a8502021-03-08 15:40:09 +0000906 // Verify whether boot extension artifacts for `isa` are valid on system partition or in apexdata.
Orion Hodson4c3ade62021-02-10 14:07:10 +0000907 // This method has the side-effect of removing boot classpath extension artifacts on /data,
908 // if there are valid artifacts on /system, or if the artifacts on /data are not valid.
909 // Returns true if valid boot externsion artifacts are valid.
Orion Hodson3407fb22021-03-17 14:40:51 +0000910 WARN_UNUSED bool VerifyBootExtensionArtifactsAreUpToDate(InstructionSet isa) const {
Orion Hodson947a8502021-03-08 15:40:09 +0000911 bool system_ok = VerifyBootExtensionArtifactsAreUpToDate(isa, /*on_system=*/true);
Orion Hodson4c3ade62021-02-10 14:07:10 +0000912 LOG(INFO) << "Boot extension artifacts on /system are " << (system_ok ? "ok" : "stale");
Orion Hodson947a8502021-03-08 15:40:09 +0000913 bool data_ok = VerifyBootExtensionArtifactsAreUpToDate(isa, /*on_system=*/false);
Orion Hodson4c3ade62021-02-10 14:07:10 +0000914 LOG(INFO) << "Boot extension artifacts on /data are " << (data_ok ? "ok" : "stale");
Orion Hodson4c3ade62021-02-10 14:07:10 +0000915 return system_ok || data_ok;
916 }
917
Orion Hodson947a8502021-03-08 15:40:09 +0000918 // Verify all artifacts are up-to-date.
919 //
920 // This method checks artifacts can be loaded by the runtime.
921 //
922 // Returns ExitCode::kOkay if artifacts are up-to-date, ExitCode::kCompilationRequired otherwise.
923 //
924 // NB This is the main function used by the --check command-line option. When invoked with
925 // --compile, we only recompile the out-of-date artifacts, not all (see `Odrefresh::Compile`).
Orion Hodson3407fb22021-03-17 14:40:51 +0000926 WARN_UNUSED ExitCode VerifyArtifactsAreUpToDate() {
Orion Hodson947a8502021-03-08 15:40:09 +0000927 ExitCode exit_code = ExitCode::kOkay;
928 for (const InstructionSet isa : config_.GetBootExtensionIsas()) {
929 if (!VerifyBootExtensionArtifactsAreUpToDate(isa)) {
Orion Hodson3407fb22021-03-17 14:40:51 +0000930 if (!RemoveBootExtensionArtifactsFromData(isa)) {
931 return ExitCode::kCleanupFailed;
932 }
Orion Hodson947a8502021-03-08 15:40:09 +0000933 exit_code = ExitCode::kCompilationRequired;
934 }
935 }
936 if (!VerifySystemServerArtifactsAreUpToDate()) {
Orion Hodson3407fb22021-03-17 14:40:51 +0000937 if (!RemoveSystemServerArtifactsFromData()) {
938 return ExitCode::kCleanupFailed;
939 }
Orion Hodson947a8502021-03-08 15:40:09 +0000940 exit_code = ExitCode::kCompilationRequired;
941 }
942 return exit_code;
943 }
944
Orion Hodson3407fb22021-03-17 14:40:51 +0000945 WARN_UNUSED bool CleanApexdataDirectory() const {
Orion Hodsonf96c9162021-04-07 10:43:01 +0100946 const std::string& apex_data_path = GetArtApexData();
947 if (config_.GetDryRun()) {
948 LOG(INFO) << "Files under `" << QuotePath(apex_data_path) << " would be removed (dry-run).";
949 return true;
950 }
951 return CleanDirectory(apex_data_path);
Orion Hodson3407fb22021-03-17 14:40:51 +0000952 }
953
954 WARN_UNUSED bool RemoveArtifacts(const OdrArtifacts& artifacts) const {
955 bool success = true;
Orion Hodson4c3ade62021-02-10 14:07:10 +0000956 for (const auto& location :
957 {artifacts.ImagePath(), artifacts.OatPath(), artifacts.VdexPath()}) {
Orion Hodson947a8502021-03-08 15:40:09 +0000958 if (config_.GetDryRun()) {
959 LOG(INFO) << "Removing " << QuotePath(location) << " (dry-run).";
960 continue;
961 }
962
Orion Hodson3407fb22021-03-17 14:40:51 +0000963 if (OS::FileExists(location.c_str()) && unlink(location.c_str()) != 0) {
Orion Hodson4c3ade62021-02-10 14:07:10 +0000964 PLOG(ERROR) << "Failed to remove: " << QuotePath(location);
Orion Hodson3407fb22021-03-17 14:40:51 +0000965 success = false;
Orion Hodson4c3ade62021-02-10 14:07:10 +0000966 }
967 }
Orion Hodson3407fb22021-03-17 14:40:51 +0000968 return success;
Orion Hodson4c3ade62021-02-10 14:07:10 +0000969 }
970
Orion Hodson4c3ade62021-02-10 14:07:10 +0000971 static std::string GetBootImage() {
972 // Typically "/apex/com.android.art/javalib/boot.art".
973 return GetArtRoot() + "/javalib/boot.art";
974 }
975
976 std::string GetBootImageExtensionImage(bool on_system) const {
977 CHECK(!boot_extension_compilable_jars_.empty());
978 const std::string leading_jar = boot_extension_compilable_jars_[0];
979 if (on_system) {
980 const std::string jar_name = android::base::Basename(leading_jar);
981 const std::string image_name = ReplaceFileExtension(jar_name, "art");
982 // Typically "/system/framework/boot-framework.art".
983 return Concatenate({GetAndroidRoot(), "/framework/boot-", image_name});
984 } else {
985 // Typically "/data/misc/apexdata/com.android.art/dalvik-cache/boot-framework.art".
986 return GetApexDataBootImage(leading_jar);
987 }
988 }
989
990 std::string GetBootImageExtensionImagePath(const InstructionSet isa) const {
991 // Typically "/data/misc/apexdata/com.android.art/dalvik-cache/<isa>/boot-framework.art".
992 return GetSystemImageFilename(GetBootImageExtensionImage(/*on_system=*/false).c_str(), isa);
993 }
994
995 std::string GetSystemServerImagePath(bool on_system, const std::string& jar_path) const {
996 if (on_system) {
997 const std::string jar_name = android::base::Basename(jar_path);
998 const std::string image_name = ReplaceFileExtension(jar_name, "art");
999 const char* isa_str = GetInstructionSetString(config_.GetSystemServerIsa());
1000 // Typically "/system/framework/oat/<isa>/services.art".
1001 return Concatenate({GetAndroidRoot(), "/framework/oat/", isa_str, "/", image_name});
1002 } else {
1003 // Typically
1004 // "/data/misc/apexdata/.../dalvik-cache/<isa>/system@framework@services.jar@classes.art".
1005 const std::string image = GetApexDataImage(jar_path.c_str());
1006 return GetSystemImageFilename(image.c_str(), config_.GetSystemServerIsa());
1007 }
1008 }
1009
1010 std::string GetStagingLocation(const std::string& staging_dir, const std::string& path) const {
1011 return Concatenate({staging_dir, "/", android::base::Basename(path)});
1012 }
1013
Victor Hsiehb3a4e012021-06-14 12:48:10 -07001014 std::string JoinFilesAsFDs(const std::vector<std::unique_ptr<File>>& files, char delimiter) const {
1015 std::stringstream output;
1016 bool is_first = true;
1017 for (const auto& f : files) {
1018 output << std::to_string(f->Fd());
1019 if (is_first) {
1020 is_first = false;
1021 } else {
1022 output << delimiter;
1023 }
1024 }
1025 return output.str();
1026 }
1027
Orion Hodson3407fb22021-03-17 14:40:51 +00001028 WARN_UNUSED bool CompileBootExtensionArtifacts(const InstructionSet isa,
1029 const std::string& staging_dir,
Orion Hodson957fb152021-04-08 07:52:15 +01001030 OdrMetrics& metrics,
Nicolas Geoffray5db2fd02021-04-16 15:07:56 +01001031 uint32_t* dex2oat_invocation_count,
Orion Hodson3407fb22021-03-17 14:40:51 +00001032 std::string* error_msg) const {
Orion Hodson957fb152021-04-08 07:52:15 +01001033 ScopedOdrCompilationTimer compilation_timer(metrics);
Orion Hodson4c3ade62021-02-10 14:07:10 +00001034 std::vector<std::string> args;
1035 args.push_back(config_.GetDex2Oat());
1036
1037 AddDex2OatCommonOptions(args);
1038 AddDex2OatConcurrencyArguments(args);
1039 AddDex2OatDebugInfo(args);
1040 AddDex2OatInstructionSet(args, isa);
Victor Hsieha9f80fc2021-05-17 17:28:26 -07001041
1042 std::vector<std::unique_ptr<File>> readonly_files_raii;
Orion Hodson4c3ade62021-02-10 14:07:10 +00001043 const std::string boot_profile_file(GetAndroidRoot() + "/etc/boot-image.prof");
Victor Hsieha9f80fc2021-05-17 17:28:26 -07001044 readonly_files_raii.emplace_back(AddDex2OatProfileAndCompilerFilter(args, boot_profile_file));
Orion Hodson4c3ade62021-02-10 14:07:10 +00001045
1046 // Compile as a single image for fewer files and slightly less memory overhead.
1047 args.emplace_back("--single-image");
1048
1049 // Set boot-image and expectation of compiling boot classpath extensions.
1050 args.emplace_back("--boot-image=" + GetBootImage());
1051
1052 const std::string dirty_image_objects_file(GetAndroidRoot() + "/etc/dirty-image-objects");
1053 if (OS::FileExists(dirty_image_objects_file.c_str())) {
Victor Hsieh4ab59232021-06-10 12:24:02 -07001054 std::unique_ptr<File> file(OS::OpenFileForReading(dirty_image_objects_file.c_str()));
1055 args.emplace_back(android::base::StringPrintf("--dirty-image-objects-fd=%d", file->Fd()));
1056 readonly_files_raii.push_back(std::move(file));
Orion Hodson4c3ade62021-02-10 14:07:10 +00001057 } else {
1058 LOG(WARNING) << "Missing dirty objects file : " << QuotePath(dirty_image_objects_file);
1059 }
1060
1061 // Add boot extensions to compile.
1062 for (const std::string& component : boot_extension_compilable_jars_) {
1063 args.emplace_back("--dex-file=" + component);
Victor Hsieh826e6662021-05-17 15:40:13 -07001064 std::unique_ptr<File> file(OS::OpenFileForReading(component.c_str()));
1065 args.emplace_back(android::base::StringPrintf("--dex-fd=%d", file->Fd()));
1066 readonly_files_raii.push_back(std::move(file));
Orion Hodson4c3ade62021-02-10 14:07:10 +00001067 }
1068
1069 args.emplace_back("--runtime-arg");
1070 args.emplace_back(Concatenate({"-Xbootclasspath:", config_.GetDex2oatBootClasspath()}));
Victor Hsieh0be3da62021-06-14 12:37:03 -07001071 auto bcp_jars = android::base::Split(config_.GetDex2oatBootClasspath(), ":");
1072 if (!AddBootClasspathFds(args, readonly_files_raii, bcp_jars)) {
1073 return false;
1074 }
Orion Hodson4c3ade62021-02-10 14:07:10 +00001075
1076 const std::string image_location = GetBootImageExtensionImagePath(isa);
1077 const OdrArtifacts artifacts = OdrArtifacts::ForBootImageExtension(image_location);
1078 CHECK_EQ(GetApexDataOatFilename(boot_extension_compilable_jars_.front().c_str(), isa),
1079 artifacts.OatPath());
1080
1081 args.emplace_back("--oat-location=" + artifacts.OatPath());
1082 const std::pair<const std::string, const char*> location_kind_pairs[] = {
1083 std::make_pair(artifacts.ImagePath(), "image"),
1084 std::make_pair(artifacts.OatPath(), "oat"),
1085 std::make_pair(artifacts.VdexPath(), "output-vdex")
1086 };
1087
1088 std::vector<std::unique_ptr<File>> staging_files;
1089 for (const auto& location_kind_pair : location_kind_pairs) {
1090 auto& [location, kind] = location_kind_pair;
1091 const std::string staging_location = GetStagingLocation(staging_dir, location);
1092 std::unique_ptr<File> staging_file(OS::CreateEmptyFile(staging_location.c_str()));
1093 if (staging_file == nullptr) {
1094 PLOG(ERROR) << "Failed to create " << kind << " file: " << staging_location;
Orion Hodson957fb152021-04-08 07:52:15 +01001095 metrics.SetStatus(OdrMetrics::Status::kIoError);
Orion Hodson4c3ade62021-02-10 14:07:10 +00001096 EraseFiles(staging_files);
1097 return false;
1098 }
Orion Hodson8f198672021-02-27 22:23:18 +00001099
Orion Hodson3407fb22021-03-17 14:40:51 +00001100 if (fchmod(staging_file->Fd(), S_IRUSR | S_IWUSR) != 0) {
Orion Hodson8f198672021-02-27 22:23:18 +00001101 PLOG(ERROR) << "Could not set file mode on " << QuotePath(staging_location);
Orion Hodson957fb152021-04-08 07:52:15 +01001102 metrics.SetStatus(OdrMetrics::Status::kIoError);
Orion Hodson8f198672021-02-27 22:23:18 +00001103 EraseFiles(staging_files);
1104 return false;
1105 }
1106
Orion Hodson4c3ade62021-02-10 14:07:10 +00001107 args.emplace_back(android::base::StringPrintf("--%s-fd=%d", kind, staging_file->Fd()));
1108 staging_files.emplace_back(std::move(staging_file));
1109 }
1110
1111 const std::string install_location = android::base::Dirname(image_location);
Orion Hodson3407fb22021-03-17 14:40:51 +00001112 if (!EnsureDirectoryExists(install_location)) {
Orion Hodson957fb152021-04-08 07:52:15 +01001113 metrics.SetStatus(OdrMetrics::Status::kIoError);
Orion Hodson3407fb22021-03-17 14:40:51 +00001114 return false;
1115 }
Orion Hodson4c3ade62021-02-10 14:07:10 +00001116
Victor Hsiehb3a4e012021-06-14 12:48:10 -07001117 if (config_.UseCompilationOs()) {
1118 std::vector<std::string> prefix_args = {
1119 "/apex/com.android.compos/bin/pvm_exec",
1120 "--cid=" + config_.GetCompilationOsAddress(),
1121 "--in-fd=" + JoinFilesAsFDs(readonly_files_raii, ','),
1122 "--out-fd=" + JoinFilesAsFDs(staging_files, ','),
1123 "--",
1124 };
1125 args.insert(args.begin(), prefix_args.begin(), prefix_args.end());
1126 }
1127
Orion Hodson4c3ade62021-02-10 14:07:10 +00001128 const time_t timeout = GetSubprocessTimeout();
1129 const std::string cmd_line = android::base::Join(args, ' ');
1130 LOG(INFO) << "Compiling boot extensions (" << isa << "): " << cmd_line
1131 << " [timeout " << timeout << "s]";
1132 if (config_.GetDryRun()) {
1133 LOG(INFO) << "Compilation skipped (dry-run).";
1134 return true;
1135 }
1136
1137 bool timed_out = false;
Orion Hodson957fb152021-04-08 07:52:15 +01001138 int dex2oat_exit_code = ExecAndReturnCode(args, timeout, &timed_out, error_msg);
1139 if (dex2oat_exit_code != 0) {
Orion Hodson4c3ade62021-02-10 14:07:10 +00001140 if (timed_out) {
Orion Hodson957fb152021-04-08 07:52:15 +01001141 metrics.SetStatus(OdrMetrics::Status::kTimeLimitExceeded);
1142 } else {
1143 metrics.SetStatus(OdrMetrics::Status::kDex2OatError);
Orion Hodson4c3ade62021-02-10 14:07:10 +00001144 }
1145 EraseFiles(staging_files);
1146 return false;
1147 }
1148
1149 if (!MoveOrEraseFiles(staging_files, install_location)) {
Orion Hodson957fb152021-04-08 07:52:15 +01001150 metrics.SetStatus(OdrMetrics::Status::kInstallFailed);
Orion Hodson4c3ade62021-02-10 14:07:10 +00001151 return false;
1152 }
1153
Nicolas Geoffray5db2fd02021-04-16 15:07:56 +01001154 *dex2oat_invocation_count = *dex2oat_invocation_count + 1;
1155 ReportNextBootAnimationProgress(*dex2oat_invocation_count);
1156
Orion Hodson4c3ade62021-02-10 14:07:10 +00001157 return true;
1158 }
1159
Orion Hodson3407fb22021-03-17 14:40:51 +00001160 WARN_UNUSED bool CompileSystemServerArtifacts(const std::string& staging_dir,
Orion Hodson957fb152021-04-08 07:52:15 +01001161 OdrMetrics& metrics,
Nicolas Geoffray5db2fd02021-04-16 15:07:56 +01001162 uint32_t* dex2oat_invocation_count,
Orion Hodson3407fb22021-03-17 14:40:51 +00001163 std::string* error_msg) const {
Orion Hodson957fb152021-04-08 07:52:15 +01001164 ScopedOdrCompilationTimer compilation_timer(metrics);
Orion Hodson4c3ade62021-02-10 14:07:10 +00001165 std::vector<std::string> classloader_context;
1166
1167 const std::string dex2oat = config_.GetDex2Oat();
1168 const InstructionSet isa = config_.GetSystemServerIsa();
1169 for (const std::string& jar : systemserver_compilable_jars_) {
Victor Hsieh2835c292021-05-27 15:32:18 -07001170 std::vector<std::unique_ptr<File>> readonly_files_raii;
Orion Hodson4c3ade62021-02-10 14:07:10 +00001171 std::vector<std::string> args;
1172 args.emplace_back(dex2oat);
1173 args.emplace_back("--dex-file=" + jar);
1174
Victor Hsieh826e6662021-05-17 15:40:13 -07001175 std::unique_ptr<File> dex_file(OS::OpenFileForReading(jar.c_str()));
1176 args.emplace_back(android::base::StringPrintf("--dex-fd=%d", dex_file->Fd()));
1177 readonly_files_raii.push_back(std::move(dex_file));
1178
Orion Hodson4c3ade62021-02-10 14:07:10 +00001179 AddDex2OatCommonOptions(args);
1180 AddDex2OatConcurrencyArguments(args);
1181 AddDex2OatDebugInfo(args);
1182 AddDex2OatInstructionSet(args, isa);
1183 const std::string jar_name(android::base::Basename(jar));
1184 const std::string profile = Concatenate({GetAndroidRoot(), "/framework/", jar_name, ".prof"});
Victor Hsieha9f80fc2021-05-17 17:28:26 -07001185 readonly_files_raii.emplace_back(AddDex2OatProfileAndCompilerFilter(args, profile));
Orion Hodson4c3ade62021-02-10 14:07:10 +00001186
1187 const std::string image_location = GetSystemServerImagePath(/*on_system=*/false, jar);
1188 const std::string install_location = android::base::Dirname(image_location);
1189 if (classloader_context.empty()) {
1190 // All images are in the same directory, we only need to check on the first iteration.
Orion Hodson3407fb22021-03-17 14:40:51 +00001191 if (!EnsureDirectoryExists(install_location)) {
Orion Hodson957fb152021-04-08 07:52:15 +01001192 metrics.SetStatus(OdrMetrics::Status::kIoError);
Orion Hodson3407fb22021-03-17 14:40:51 +00001193 return false;
1194 }
Orion Hodson4c3ade62021-02-10 14:07:10 +00001195 }
1196
1197 OdrArtifacts artifacts = OdrArtifacts::ForSystemServer(image_location);
1198 CHECK_EQ(artifacts.OatPath(), GetApexDataOdexFilename(jar.c_str(), isa));
1199
1200 const std::pair<const std::string, const char*> location_kind_pairs[] = {
1201 std::make_pair(artifacts.ImagePath(), "app-image"),
1202 std::make_pair(artifacts.OatPath(), "oat"),
1203 std::make_pair(artifacts.VdexPath(), "output-vdex")
1204 };
1205
1206 std::vector<std::unique_ptr<File>> staging_files;
1207 for (const auto& location_kind_pair : location_kind_pairs) {
1208 auto& [location, kind] = location_kind_pair;
1209 const std::string staging_location = GetStagingLocation(staging_dir, location);
1210 std::unique_ptr<File> staging_file(OS::CreateEmptyFile(staging_location.c_str()));
1211 if (staging_file == nullptr) {
1212 PLOG(ERROR) << "Failed to create " << kind << " file: " << staging_location;
Orion Hodson957fb152021-04-08 07:52:15 +01001213 metrics.SetStatus(OdrMetrics::Status::kIoError);
Orion Hodson4c3ade62021-02-10 14:07:10 +00001214 EraseFiles(staging_files);
1215 return false;
1216 }
1217 args.emplace_back(android::base::StringPrintf("--%s-fd=%d", kind, staging_file->Fd()));
1218 staging_files.emplace_back(std::move(staging_file));
1219 }
1220 args.emplace_back("--oat-location=" + artifacts.OatPath());
1221
1222 if (!config_.GetUpdatableBcpPackagesFile().empty()) {
Orion Hodson816cab32021-05-07 14:14:42 +01001223 const std::string& bcp_packages = config_.GetUpdatableBcpPackagesFile();
1224 if (!OS::FileExists(bcp_packages.c_str())) {
1225 *error_msg = "Cannot compile system_server JARs: missing " + QuotePath(bcp_packages);
1226 metrics.SetStatus(OdrMetrics::Status::kIoError);
1227 EraseFiles(staging_files);
1228 return false;
1229 }
Victor Hsieh4ab59232021-06-10 12:24:02 -07001230 std::unique_ptr<File> file(OS::OpenFileForReading(bcp_packages.c_str()));
1231 args.emplace_back(android::base::StringPrintf("--updatable-bcp-packages-fd=%d", file->Fd()));
1232 readonly_files_raii.push_back(std::move(file));
Orion Hodson4c3ade62021-02-10 14:07:10 +00001233 }
1234
1235 args.emplace_back("--runtime-arg");
1236 args.emplace_back(Concatenate({"-Xbootclasspath:", config_.GetDex2oatBootClasspath()}));
Victor Hsieh0be3da62021-06-14 12:37:03 -07001237 auto bcp_jars = android::base::Split(config_.GetDex2oatBootClasspath(), ":");
1238 if (!AddBootClasspathFds(args, readonly_files_raii, bcp_jars)) {
1239 return false;
1240 }
1241
Orion Hodson4c3ade62021-02-10 14:07:10 +00001242 const std::string context_path = android::base::Join(classloader_context, ':');
1243 args.emplace_back(Concatenate({"--class-loader-context=PCL[", context_path, "]"}));
Victor Hsieh2835c292021-05-27 15:32:18 -07001244 if (!classloader_context.empty()) {
1245 std::vector<int> fds;
1246 for (const std::string& path : classloader_context) {
1247 std::unique_ptr<File> file(OS::OpenFileForReading(path.c_str()));
1248 if (!file->IsValid()) {
1249 PLOG(ERROR) << "Failed to open classloader context " << path;
1250 metrics.SetStatus(OdrMetrics::Status::kIoError);
1251 return false;
1252 }
1253 fds.emplace_back(file->Fd());
1254 readonly_files_raii.emplace_back(std::move(file));
1255 }
1256 const std::string context_fds = android::base::Join(fds, ':');
1257 args.emplace_back(Concatenate({"--class-loader-context-fds=", context_fds}));
1258 }
Orion Hodson4c3ade62021-02-10 14:07:10 +00001259 const std::string extension_image = GetBootImageExtensionImage(/*on_system=*/false);
1260 args.emplace_back(Concatenate({"--boot-image=", GetBootImage(), ":", extension_image}));
1261
Victor Hsiehb3a4e012021-06-14 12:48:10 -07001262 if (config_.UseCompilationOs()) {
1263 std::vector<std::string> prefix_args = {
1264 "/apex/com.android.compos/bin/pvm_exec",
1265 "--cid=" + config_.GetCompilationOsAddress(),
1266 "--in-fd=" + JoinFilesAsFDs(readonly_files_raii, ','),
1267 "--out-fd=" + JoinFilesAsFDs(staging_files, ','),
1268 "--",
1269 };
1270 args.insert(args.begin(), prefix_args.begin(), prefix_args.end());
1271 }
1272
Orion Hodson4c3ade62021-02-10 14:07:10 +00001273 const time_t timeout = GetSubprocessTimeout();
1274 const std::string cmd_line = android::base::Join(args, ' ');
1275 LOG(INFO) << "Compiling " << jar << ": " << cmd_line << " [timeout " << timeout << "s]";
1276 if (config_.GetDryRun()) {
1277 LOG(INFO) << "Compilation skipped (dry-run).";
1278 return true;
1279 }
1280
1281 bool timed_out = false;
Orion Hodson957fb152021-04-08 07:52:15 +01001282 int dex2oat_exit_code = ExecAndReturnCode(args, timeout, &timed_out, error_msg);
1283 if (dex2oat_exit_code != 0) {
Orion Hodson4c3ade62021-02-10 14:07:10 +00001284 if (timed_out) {
Orion Hodson957fb152021-04-08 07:52:15 +01001285 metrics.SetStatus(OdrMetrics::Status::kTimeLimitExceeded);
1286 } else {
1287 metrics.SetStatus(OdrMetrics::Status::kDex2OatError);
Orion Hodson4c3ade62021-02-10 14:07:10 +00001288 }
1289 EraseFiles(staging_files);
1290 return false;
1291 }
1292
1293 if (!MoveOrEraseFiles(staging_files, install_location)) {
Orion Hodson957fb152021-04-08 07:52:15 +01001294 metrics.SetStatus(OdrMetrics::Status::kInstallFailed);
Orion Hodson4c3ade62021-02-10 14:07:10 +00001295 return false;
1296 }
1297
Nicolas Geoffray5db2fd02021-04-16 15:07:56 +01001298 *dex2oat_invocation_count = *dex2oat_invocation_count + 1;
1299 ReportNextBootAnimationProgress(*dex2oat_invocation_count);
Orion Hodson4c3ade62021-02-10 14:07:10 +00001300 classloader_context.emplace_back(jar);
1301 }
1302
1303 return true;
1304 }
1305
Nicolas Geoffray5db2fd02021-04-16 15:07:56 +01001306 void ReportNextBootAnimationProgress(uint32_t current_compilation) const {
1307 uint32_t number_of_compilations =
1308 config_.GetBootExtensionIsas().size() + systemserver_compilable_jars_.size();
Orion Hodson263c39e2021-05-07 10:17:14 +01001309 // We arbitrarily show progress until 90%, expecting that our compilations
Nicolas Geoffray4b3f4d32021-04-20 15:17:28 +01001310 // take a large chunk of boot time.
1311 uint32_t value = (90 * current_compilation) / number_of_compilations;
Nicolas Geoffray5db2fd02021-04-16 15:07:56 +01001312 android::base::SetProperty("service.bootanim.progress", std::to_string(value));
1313 }
1314
Orion Hodson263c39e2021-05-07 10:17:14 +01001315 WARN_UNUSED bool CheckCompilationSpace() const {
1316 // Check the available storage space against an arbitrary threshold because dex2oat does not
1317 // report when it runs out of storage space and we do not want to completely fill
1318 // the users data partition.
1319 //
1320 // We do not have a good way of pre-computing the required space for a compilation step, but
1321 // typically observe 16MB as the largest size of an AOT artifact. Since there are three
1322 // AOT artifacts per compilation step - an image file, executable file, and a verification
1323 // data file - the threshold is three times 16MB.
1324 static constexpr uint64_t kMinimumSpaceForCompilation = 3 * 16 * 1024 * 1024;
1325
1326 uint64_t bytes_available;
1327 const std::string& art_apex_data_path = GetArtApexData();
Greg Kaiser8ba64c22021-05-10 07:16:09 -07001328 if (!GetFreeSpace(art_apex_data_path, &bytes_available)) {
Orion Hodson263c39e2021-05-07 10:17:14 +01001329 return false;
1330 }
1331
1332 if (bytes_available < kMinimumSpaceForCompilation) {
1333 LOG(WARNING) << "Low space for " << QuotePath(art_apex_data_path) << " (" << bytes_available
1334 << " bytes)";
1335 return false;
1336 }
1337
1338 return true;
1339 }
Orion Hodson957fb152021-04-08 07:52:15 +01001340
1341 WARN_UNUSED ExitCode Compile(OdrMetrics& metrics, bool force_compile) const {
Orion Hodson957fb152021-04-08 07:52:15 +01001342 const char* staging_dir = nullptr;
1343 metrics.SetStage(OdrMetrics::Stage::kPreparation);
Orion Hodson4c3ade62021-02-10 14:07:10 +00001344 // Clean-up existing files.
Orion Hodson3407fb22021-03-17 14:40:51 +00001345 if (force_compile && !CleanApexdataDirectory()) {
Orion Hodson957fb152021-04-08 07:52:15 +01001346 metrics.SetStatus(OdrMetrics::Status::kIoError);
1347 return ExitCode::kCleanupFailed;
1348 }
1349
1350 // Create staging area and assign label for generating compilation artifacts.
1351 if (PaletteCreateOdrefreshStagingDirectory(&staging_dir) != PALETTE_STATUS_OK) {
1352 metrics.SetStatus(OdrMetrics::Status::kStagingFailed);
Orion Hodson3407fb22021-03-17 14:40:51 +00001353 return ExitCode::kCleanupFailed;
Orion Hodson4c3ade62021-02-10 14:07:10 +00001354 }
1355
Orion Hodson3407fb22021-03-17 14:40:51 +00001356 // Emit cache info before compiling. This can be used to throttle compilation attempts later.
1357 WriteCacheInfo();
1358
Orion Hodson4c3ade62021-02-10 14:07:10 +00001359 std::string error_msg;
1360
Nicolas Geoffray5db2fd02021-04-16 15:07:56 +01001361 uint32_t dex2oat_invocation_count = 0;
1362 ReportNextBootAnimationProgress(dex2oat_invocation_count);
Orion Hodson957fb152021-04-08 07:52:15 +01001363
1364 const auto& bcp_instruction_sets = config_.GetBootExtensionIsas();
1365 DCHECK(!bcp_instruction_sets.empty() && bcp_instruction_sets.size() <= 2);
1366 for (const InstructionSet isa : bcp_instruction_sets) {
1367 auto stage = (isa == bcp_instruction_sets.front()) ?
1368 OdrMetrics::Stage::kPrimaryBootClasspath :
1369 OdrMetrics::Stage::kSecondaryBootClasspath;
1370 metrics.SetStage(stage);
Orion Hodson947a8502021-03-08 15:40:09 +00001371 if (force_compile || !BootExtensionArtifactsExistOnData(isa, &error_msg)) {
Orion Hodson3407fb22021-03-17 14:40:51 +00001372 // Remove artifacts we are about to generate. Ordinarily these are removed in the checking
1373 // step, but this is not always run (e.g. during manual testing).
1374 if (!RemoveBootExtensionArtifactsFromData(isa)) {
1375 return ExitCode::kCleanupFailed;
1376 }
Orion Hodson263c39e2021-05-07 10:17:14 +01001377
1378 if (!CheckCompilationSpace()) {
1379 metrics.SetStatus(OdrMetrics::Status::kNoSpace);
1380 // Return kOkay so odsign will keep and sign whatever we have been able to compile.
1381 return ExitCode::kOkay;
1382 }
1383
Nicolas Geoffray5db2fd02021-04-16 15:07:56 +01001384 if (!CompileBootExtensionArtifacts(
Orion Hodson957fb152021-04-08 07:52:15 +01001385 isa, staging_dir, metrics, &dex2oat_invocation_count, &error_msg)) {
Orion Hodson947a8502021-03-08 15:40:09 +00001386 LOG(ERROR) << "Compilation of BCP failed: " << error_msg;
Orion Hodsonf96c9162021-04-07 10:43:01 +01001387 if (!config_.GetDryRun() && !CleanDirectory(staging_dir)) {
Orion Hodson3407fb22021-03-17 14:40:51 +00001388 return ExitCode::kCleanupFailed;
1389 }
Orion Hodson4c3ade62021-02-10 14:07:10 +00001390 return ExitCode::kCompilationFailed;
1391 }
1392 }
1393 }
1394
Orion Hodson947a8502021-03-08 15:40:09 +00001395 if (force_compile || !SystemServerArtifactsExistOnData(&error_msg)) {
Orion Hodson957fb152021-04-08 07:52:15 +01001396 metrics.SetStage(OdrMetrics::Stage::kSystemServerClasspath);
Orion Hodson263c39e2021-05-07 10:17:14 +01001397
1398 if (!CheckCompilationSpace()) {
1399 metrics.SetStatus(OdrMetrics::Status::kNoSpace);
1400 // Return kOkay so odsign will keep and sign whatever we have been able to compile.
1401 return ExitCode::kOkay;
1402 }
1403
Orion Hodson957fb152021-04-08 07:52:15 +01001404 if (!CompileSystemServerArtifacts(
1405 staging_dir, metrics, &dex2oat_invocation_count, &error_msg)) {
Orion Hodson947a8502021-03-08 15:40:09 +00001406 LOG(ERROR) << "Compilation of system_server failed: " << error_msg;
Orion Hodsonf96c9162021-04-07 10:43:01 +01001407 if (!config_.GetDryRun() && !CleanDirectory(staging_dir)) {
Orion Hodson3407fb22021-03-17 14:40:51 +00001408 return ExitCode::kCleanupFailed;
1409 }
Orion Hodson4c3ade62021-02-10 14:07:10 +00001410 return ExitCode::kCompilationFailed;
1411 }
1412 }
1413
Orion Hodson957fb152021-04-08 07:52:15 +01001414 metrics.SetStage(OdrMetrics::Stage::kComplete);
Orion Hodsonfcbbdd42021-03-22 17:02:05 +00001415 return ExitCode::kCompilationSuccess;
Orion Hodson4c3ade62021-02-10 14:07:10 +00001416 }
1417
1418 static bool ArgumentMatches(std::string_view argument,
1419 std::string_view prefix,
1420 std::string* value) {
1421 if (StartsWith(argument, prefix)) {
1422 *value = std::string(argument.substr(prefix.size()));
1423 return true;
1424 }
1425 return false;
1426 }
1427
1428 static bool ArgumentEquals(std::string_view argument, std::string_view expected) {
1429 return argument == expected;
1430 }
1431
1432 static bool InitializeCommonConfig(std::string_view argument, OdrConfig* config) {
1433 static constexpr std::string_view kDryRunArgument{"--dry-run"};
1434 if (ArgumentEquals(argument, kDryRunArgument)) {
1435 config->SetDryRun();
1436 return true;
1437 }
1438 return false;
1439 }
1440
1441 static int InitializeHostConfig(int argc, const char** argv, OdrConfig* config) {
1442 __android_log_set_logger(__android_log_stderr_logger);
1443
1444 std::string current_binary;
1445 if (argv[0][0] == '/') {
1446 current_binary = argv[0];
1447 } else {
1448 std::vector<char> buf(PATH_MAX);
1449 if (getcwd(buf.data(), buf.size()) == nullptr) {
1450 PLOG(FATAL) << "Failed getwd()";
1451 }
1452 current_binary = Concatenate({buf.data(), "/", argv[0]});
1453 }
1454 config->SetArtBinDir(android::base::Dirname(current_binary));
1455
1456 int n = 1;
1457 for (; n < argc - 1; ++n) {
1458 const char* arg = argv[n];
1459 std::string value;
1460 if (ArgumentMatches(arg, "--android-root=", &value)) {
1461 setenv("ANDROID_ROOT", value.c_str(), 1);
1462 } else if (ArgumentMatches(arg, "--android-art-root=", &value)) {
1463 setenv("ANDROID_ART_ROOT", value.c_str(), 1);
1464 } else if (ArgumentMatches(arg, "--apex-info-list=", &value)) {
1465 config->SetApexInfoListFile(value);
1466 } else if (ArgumentMatches(arg, "--art-apex-data=", &value)) {
1467 setenv("ART_APEX_DATA", value.c_str(), 1);
1468 } else if (ArgumentMatches(arg, "--dex2oat-bootclasspath=", &value)) {
1469 config->SetDex2oatBootclasspath(value);
1470 } else if (ArgumentMatches(arg, "--isa=", &value)) {
1471 config->SetIsa(GetInstructionSetFromString(value.c_str()));
1472 } else if (ArgumentMatches(arg, "--system-server-classpath=", &value)) {
1473 config->SetSystemServerClasspath(arg);
1474 } else if (ArgumentMatches(arg, "--updatable-bcp-packages-file=", &value)) {
1475 config->SetUpdatableBcpPackagesFile(value);
1476 } else if (ArgumentMatches(arg, "--zygote-arch=", &value)) {
1477 ZygoteKind zygote_kind;
1478 if (!ParseZygoteKind(value.c_str(), &zygote_kind)) {
1479 ArgumentError("Unrecognized zygote kind: '%s'", value.c_str());
1480 }
1481 config->SetZygoteKind(zygote_kind);
1482 } else if (!InitializeCommonConfig(arg, config)) {
1483 UsageError("Unrecognized argument: '%s'", arg);
1484 }
1485 }
1486 return n;
1487 }
1488
1489 static int InitializeTargetConfig(int argc, const char** argv, OdrConfig* config) {
1490 config->SetApexInfoListFile("/apex/apex-info-list.xml");
1491 config->SetArtBinDir(GetArtBinDir());
Orion Hodson35363cf2021-03-18 14:23:13 +00001492 config->SetDex2oatBootclasspath(GetEnvironmentVariableOrDie("DEX2OATBOOTCLASSPATH"));
1493 config->SetSystemServerClasspath(GetEnvironmentVariableOrDie("SYSTEMSERVERCLASSPATH"));
Orion Hodson4c3ade62021-02-10 14:07:10 +00001494 config->SetIsa(kRuntimeISA);
1495
1496 const std::string zygote = android::base::GetProperty("ro.zygote", {});
1497 ZygoteKind zygote_kind;
1498 if (!ParseZygoteKind(zygote.c_str(), &zygote_kind)) {
1499 LOG(FATAL) << "Unknown zygote: " << QuotePath(zygote);
1500 }
1501 config->SetZygoteKind(zygote_kind);
1502
1503 const std::string updatable_packages =
1504 android::base::GetProperty("dalvik.vm.dex2oat-updatable-bcp-packages-file", {});
1505 config->SetUpdatableBcpPackagesFile(updatable_packages);
1506
1507 int n = 1;
1508 for (; n < argc - 1; ++n) {
Victor Hsiehb3a4e012021-06-14 12:48:10 -07001509 const char* arg = argv[n];
1510 std::string value;
1511 if (ArgumentMatches(arg, "--use-compilation-os=", &value)) {
1512 config->SetCompilationOsAddress(value);
1513 } else if (!InitializeCommonConfig(arg, config)) {
1514 UsageError("Unrecognized argument: '%s'", arg);
Orion Hodson4c3ade62021-02-10 14:07:10 +00001515 }
1516 }
1517 return n;
1518 }
1519
1520 static int InitializeConfig(int argc, const char** argv, OdrConfig* config) {
1521 if (kIsTargetBuild) {
1522 return InitializeTargetConfig(argc, argv, config);
1523 } else {
1524 return InitializeHostConfig(argc, argv, config);
1525 }
1526 }
1527
1528 static int main(int argc, const char** argv) {
1529 OdrConfig config(argv[0]);
Orion Hodson4c3ade62021-02-10 14:07:10 +00001530 int n = InitializeConfig(argc, argv, &config);
1531 argv += n;
1532 argc -= n;
Orion Hodson4c3ade62021-02-10 14:07:10 +00001533 if (argc != 1) {
1534 UsageError("Expected 1 argument, but have %d.", argc);
1535 }
1536
Orion Hodson957fb152021-04-08 07:52:15 +01001537 OdrMetrics metrics(kOdrefreshArtifactDirectory);
Orion Hodson4c3ade62021-02-10 14:07:10 +00001538 OnDeviceRefresh odr(config);
1539 for (int i = 0; i < argc; ++i) {
1540 std::string_view action(argv[i]);
1541 if (action == "--check") {
Orion Hodson947a8502021-03-08 15:40:09 +00001542 // Fast determination of whether artifacts are up to date.
Orion Hodson957fb152021-04-08 07:52:15 +01001543 return odr.CheckArtifactsAreUpToDate(metrics);
Orion Hodson4c3ade62021-02-10 14:07:10 +00001544 } else if (action == "--compile") {
Orion Hodson957fb152021-04-08 07:52:15 +01001545 const ExitCode exit_code = odr.CheckArtifactsAreUpToDate(metrics);
Orion Hodsonf761f582021-06-09 10:50:57 +01001546 if (exit_code != ExitCode::kCompilationRequired) {
1547 return exit_code;
Orion Hodson957fb152021-04-08 07:52:15 +01001548 }
Orion Hodsonf761f582021-06-09 10:50:57 +01001549 OdrCompilationLog compilation_log;
1550 if (!compilation_log.ShouldAttemptCompile(metrics.GetApexVersion(), metrics.GetTrigger())) {
1551 return ExitCode::kOkay;
1552 }
1553 ExitCode compile_result = odr.Compile(metrics, /*force_compile=*/false);
1554 compilation_log.Log(metrics.GetApexVersion(), metrics.GetTrigger(), compile_result);
1555 return compile_result;
Orion Hodson4c3ade62021-02-10 14:07:10 +00001556 } else if (action == "--force-compile") {
Orion Hodson957fb152021-04-08 07:52:15 +01001557 return odr.Compile(metrics, /*force_compile=*/true);
Orion Hodson947a8502021-03-08 15:40:09 +00001558 } else if (action == "--verify") {
1559 // Slow determination of whether artifacts are up to date. These are too slow for checking
1560 // during boot (b/181689036).
1561 return odr.VerifyArtifactsAreUpToDate();
Orion Hodson4c3ade62021-02-10 14:07:10 +00001562 } else if (action == "--help") {
1563 UsageHelp(argv[0]);
1564 } else {
1565 UsageError("Unknown argument: ", argv[i]);
1566 }
1567 }
1568 return ExitCode::kOkay;
1569 }
1570
1571 DISALLOW_COPY_AND_ASSIGN(OnDeviceRefresh);
1572};
1573
1574} // namespace odrefresh
1575} // namespace art
1576
1577int main(int argc, const char** argv) {
Orion Hodson8f198672021-02-27 22:23:18 +00001578 // odrefresh is launched by `init` which sets the umask of forked processed to
1579 // 077 (S_IRWXG | S_IRWXO). This blocks the ability to make files and directories readable
1580 // by others and prevents system_server from loading generated artifacts.
1581 umask(S_IWGRP | S_IWOTH);
Orion Hodson4c3ade62021-02-10 14:07:10 +00001582 return art::odrefresh::OnDeviceRefresh::main(argc, argv);
1583}