blob: 0e83fb8db875d0d121cec8aab5a67b70b76fa2da [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
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +000017#include "odrefresh.h"
Orion Hodson4c3ade62021-02-10 14:07:10 +000018
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>
Jiakai Zhang7de49d82021-07-14 11:09:49 +080038#include <iterator>
Orion Hodson4c3ade62021-02-10 14:07:10 +000039#include <memory>
Orion Hodson947a8502021-03-08 15:40:09 +000040#include <optional>
Orion Hodson4c3ade62021-02-10 14:07:10 +000041#include <ostream>
Orion Hodson4c3ade62021-02-10 14:07:10 +000042#include <sstream>
43#include <string>
44#include <string_view>
Orion Hodson947a8502021-03-08 15:40:09 +000045#include <type_traits>
Jiakai Zhang7de49d82021-07-14 11:09:49 +080046#include <unordered_map>
Orion Hodson947a8502021-03-08 15:40:09 +000047#include <utility>
Orion Hodson4c3ade62021-02-10 14:07:10 +000048#include <vector>
49
50#include "android-base/file.h"
51#include "android-base/logging.h"
52#include "android-base/macros.h"
53#include "android-base/properties.h"
54#include "android-base/stringprintf.h"
55#include "android-base/strings.h"
56#include "android/log.h"
57#include "arch/instruction_set.h"
Orion Hodson947a8502021-03-08 15:40:09 +000058#include "base/file_utils.h"
Orion Hodson4c3ade62021-02-10 14:07:10 +000059#include "base/globals.h"
60#include "base/macros.h"
61#include "base/os.h"
62#include "base/string_view_cpp20.h"
63#include "base/unix_file/fd_file.h"
64#include "com_android_apex.h"
Orion Hodson947a8502021-03-08 15:40:09 +000065#include "com_android_art.h"
66#include "dex/art_dex_file_loader.h"
Orion Hodson4c3ade62021-02-10 14:07:10 +000067#include "dexoptanalyzer.h"
68#include "exec_utils.h"
Orion Hodson957fb152021-04-08 07:52:15 +010069#include "log/log.h"
Orion Hodson4c3ade62021-02-10 14:07:10 +000070#include "odr_artifacts.h"
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +000071#include "odr_common.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"
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +000076#include "odrefresh/odrefresh.h"
Jiakai Zhang7de49d82021-07-14 11:09:49 +080077#include "palette/palette.h"
78#include "palette/palette_types.h"
Orion Hodson4c3ade62021-02-10 14:07:10 +000079
80namespace art {
81namespace odrefresh {
Orion Hodson947a8502021-03-08 15:40:09 +000082
83namespace apex = com::android::apex;
84namespace art_apex = com::android::art;
85
Orion Hodson4c3ade62021-02-10 14:07:10 +000086namespace {
87
Orion Hodson947a8502021-03-08 15:40:09 +000088// Name of cache info file in the ART Apex artifact cache.
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +000089constexpr const char* kCacheInfoFile = "cache-info.xml";
Orion Hodson947a8502021-03-08 15:40:09 +000090
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +000091// Maximum execution time for odrefresh from start to end.
92constexpr time_t kMaximumExecutionSeconds = 300;
Orion Hodson4c3ade62021-02-10 14:07:10 +000093
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +000094// Maximum execution time for any child process spawned.
95constexpr time_t kMaxChildProcessSeconds = 90;
Orion Hodson4c3ade62021-02-10 14:07:10 +000096
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +000097void EraseFiles(const std::vector<std::unique_ptr<File>>& files) {
Orion Hodson4c3ade62021-02-10 14:07:10 +000098 for (auto& file : files) {
99 file->Erase(/*unlink=*/true);
100 }
101}
102
103// Moves `files` to the directory `output_directory_path`.
104//
105// If any of the files cannot be moved, then all copies of the files are removed from both
106// the original location and the output location.
107//
108// Returns true if all files are moved, false otherwise.
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +0000109bool MoveOrEraseFiles(const std::vector<std::unique_ptr<File>>& files,
110 std::string_view output_directory_path) {
Orion Hodson4c3ade62021-02-10 14:07:10 +0000111 std::vector<std::unique_ptr<File>> output_files;
112 for (auto& file : files) {
113 const std::string file_basename(android::base::Basename(file->GetPath()));
114 const std::string output_file_path = Concatenate({output_directory_path, "/", file_basename});
115 const std::string input_file_path = file->GetPath();
116
117 output_files.emplace_back(OS::CreateEmptyFileWriteOnly(output_file_path.c_str()));
118 if (output_files.back() == nullptr) {
119 PLOG(ERROR) << "Failed to open " << QuotePath(output_file_path);
120 output_files.pop_back();
121 EraseFiles(output_files);
122 EraseFiles(files);
123 return false;
124 }
125
Orion Hodson8f198672021-02-27 22:23:18 +0000126 static constexpr mode_t kFileMode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
Orion Hodson3407fb22021-03-17 14:40:51 +0000127 if (fchmod(output_files.back()->Fd(), kFileMode) != 0) {
Orion Hodson8f198672021-02-27 22:23:18 +0000128 PLOG(ERROR) << "Could not set file mode on " << QuotePath(output_file_path);
129 EraseFiles(output_files);
130 EraseFiles(files);
131 return false;
132 }
133
Orion Hodson4c3ade62021-02-10 14:07:10 +0000134 const size_t file_bytes = file->GetLength();
135 if (!output_files.back()->Copy(file.get(), /*offset=*/0, file_bytes)) {
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +0000136 PLOG(ERROR) << "Failed to copy " << QuotePath(file->GetPath()) << " to "
137 << QuotePath(output_file_path);
Orion Hodson4c3ade62021-02-10 14:07:10 +0000138 EraseFiles(output_files);
139 EraseFiles(files);
140 return false;
141 }
142
143 if (!file->Erase(/*unlink=*/true)) {
144 PLOG(ERROR) << "Failed to erase " << QuotePath(file->GetPath());
145 EraseFiles(output_files);
146 EraseFiles(files);
147 return false;
148 }
149
150 if (output_files.back()->FlushCloseOrErase() != 0) {
151 PLOG(ERROR) << "Failed to flush and close file " << QuotePath(output_file_path);
152 EraseFiles(output_files);
153 EraseFiles(files);
154 return false;
155 }
156 }
157 return true;
158}
159
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +0000160// Gets the `ApexInfo` associated with the currently active ART APEX.
161std::optional<apex::ApexInfo> GetArtApexInfo(const std::vector<apex::ApexInfo>& info_list) {
162 auto it = std::find_if(info_list.begin(), info_list.end(), [](const apex::ApexInfo& info) {
163 return info.getModuleName() == "com.android.art";
164 });
165 return it != info_list.end() ? std::make_optional(*it) : std::nullopt;
166}
167
168// Returns cache provenance information based on the current APEX version and filesystem
169// information.
170art_apex::ModuleInfo GenerateModuleInfo(const apex::ApexInfo& apex_info) {
171 // The lastUpdateMillis is an addition to ApexInfoList.xsd to support samegrade installs.
172 int64_t last_update_millis =
173 apex_info.hasLastUpdateMillis() ? apex_info.getLastUpdateMillis() : 0;
174 return art_apex::ModuleInfo{apex_info.getModuleName(),
175 apex_info.getVersionCode(),
176 apex_info.getVersionName(),
177 last_update_millis};
178}
179
180// Returns cache provenance information for all APEXes.
181std::vector<art_apex::ModuleInfo> GenerateModuleInfoList(
182 const std::vector<apex::ApexInfo>& apex_info_list) {
183 std::vector<art_apex::ModuleInfo> module_info_list;
184 std::transform(apex_info_list.begin(),
185 apex_info_list.end(),
186 std::back_inserter(module_info_list),
187 GenerateModuleInfo);
188 return module_info_list;
189}
190
191bool CheckComponents(const std::vector<art_apex::Component>& expected_components,
192 const std::vector<art_apex::Component>& actual_components,
193 std::string* error_msg) {
194 if (expected_components.size() != actual_components.size()) {
195 return false;
196 }
197
198 for (size_t i = 0; i < expected_components.size(); ++i) {
199 const art_apex::Component& expected = expected_components[i];
200 const art_apex::Component& actual = actual_components[i];
201
202 if (expected.getFile() != actual.getFile()) {
203 *error_msg = android::base::StringPrintf("Component %zu file differs ('%s' != '%s')",
204 i,
205 expected.getFile().c_str(),
206 actual.getFile().c_str());
207 return false;
208 }
209 if (expected.getSize() != actual.getSize()) {
210 *error_msg =
211 android::base::StringPrintf("Component %zu size differs (%" PRIu64 " != %" PRIu64 ")",
212 i,
213 expected.getSize(),
214 actual.getSize());
215 return false;
216 }
217 if (expected.getChecksums() != actual.getChecksums()) {
218 *error_msg = android::base::StringPrintf("Component %zu checksums differ ('%s' != '%s')",
219 i,
220 expected.getChecksums().c_str(),
221 actual.getChecksums().c_str());
222 return false;
223 }
224 }
225
226 return true;
227}
228
229std::vector<art_apex::Component> GenerateComponents(const std::vector<std::string>& jars) {
230 std::vector<art_apex::Component> components;
231
232 ArtDexFileLoader loader;
233 for (const std::string& path : jars) {
234 struct stat sb;
235 if (stat(path.c_str(), &sb) == -1) {
236 PLOG(ERROR) << "Failed to get component: " << QuotePath(path);
237 return {};
238 }
239
240 std::vector<uint32_t> checksums;
241 std::vector<std::string> dex_locations;
242 std::string error_msg;
243 if (!loader.GetMultiDexChecksums(path.c_str(), &checksums, &dex_locations, &error_msg)) {
244 LOG(ERROR) << "Failed to get components: " << error_msg;
245 return {};
246 }
247
248 std::ostringstream oss;
249 for (size_t i = 0; i < checksums.size(); ++i) {
250 if (i != 0) {
251 oss << ';';
252 }
253 oss << android::base::StringPrintf("%08x", checksums[i]);
254 }
255 const std::string checksum = oss.str();
256
257 components.emplace_back(art_apex::Component{path, static_cast<uint64_t>(sb.st_size), checksum});
258 }
259
260 return components;
261}
262
263// Checks whether a group of artifacts exists. Returns true if all are present, false otherwise.
264bool ArtifactsExist(const OdrArtifacts& artifacts,
265 bool check_art_file,
266 /*out*/ std::string* error_msg) {
267 std::vector<const char*> paths{artifacts.OatPath().c_str(), artifacts.VdexPath().c_str()};
268 if (check_art_file) {
269 paths.push_back(artifacts.ImagePath().c_str());
270 }
271 for (const char* path : paths) {
272 if (!OS::FileExists(path)) {
273 if (errno == EACCES) {
274 PLOG(ERROR) << "Failed to stat() " << path;
275 }
276 *error_msg = "Missing file: " + QuotePath(path);
277 return false;
278 }
279 }
280 return true;
281}
282
283void AddDex2OatCommonOptions(/*inout*/ std::vector<std::string>* args) {
284 args->emplace_back("--android-root=out/empty");
285 args->emplace_back("--abort-on-hard-verifier-error");
286 args->emplace_back("--no-abort-on-soft-verifier-error");
287 args->emplace_back("--compilation-reason=boot");
288 args->emplace_back("--image-format=lz4");
289 args->emplace_back("--force-determinism");
290 args->emplace_back("--resolve-startup-const-strings=true");
291}
292
293void AddDex2OatConcurrencyArguments(/*inout*/ std::vector<std::string>* args) {
294 static constexpr std::pair<const char*, const char*> kPropertyArgPairs[] = {
295 std::make_pair("dalvik.vm.boot-dex2oat-cpu-set", "--cpu-set="),
296 std::make_pair("dalvik.vm.boot-dex2oat-threads", "-j"),
297 };
298 for (auto property_arg_pair : kPropertyArgPairs) {
299 auto [property, arg] = property_arg_pair;
300 std::string value = android::base::GetProperty(property, {});
301 if (!value.empty()) {
302 args->push_back(arg + value);
303 }
304 }
305}
306
307void AddDex2OatDebugInfo(/*inout*/ std::vector<std::string>* args) {
308 args->emplace_back("--generate-mini-debug-info");
309 args->emplace_back("--strip");
310}
311
312void AddDex2OatInstructionSet(/*inout*/ std::vector<std::string>* args, InstructionSet isa) {
313 const char* isa_str = GetInstructionSetString(isa);
314 args->emplace_back(Concatenate({"--instruction-set=", isa_str}));
315}
316
317void AddDex2OatProfileAndCompilerFilter(
318 /*inout*/ std::vector<std::string>* args,
319 /*inout*/ std::vector<std::unique_ptr<File>>* output_files,
320 const std::string& profile_path) {
321 std::unique_ptr<File> profile_file(OS::OpenFileForReading(profile_path.c_str()));
322 if (profile_file && profile_file->IsOpened()) {
323 args->emplace_back(android::base::StringPrintf("--profile-file-fd=%d", profile_file->Fd()));
324 args->emplace_back("--compiler-filter=speed-profile");
325 output_files->push_back(std::move(profile_file));
326 } else {
327 args->emplace_back("--compiler-filter=speed");
328 }
329}
330
331bool AddBootClasspathFds(/*inout*/ std::vector<std::string>& args,
332 /*inout*/ std::vector<std::unique_ptr<File>>& output_files,
333 const std::vector<std::string>& bcp_jars) {
334 auto bcp_fds = std::vector<std::string>();
335 for (const std::string& jar : bcp_jars) {
336 std::unique_ptr<File> jar_file(OS::OpenFileForReading(jar.c_str()));
337 if (!jar_file || !jar_file->IsValid()) {
338 LOG(ERROR) << "Failed to open a BCP jar " << jar;
339 return false;
340 }
341 bcp_fds.push_back(std::to_string(jar_file->Fd()));
342 output_files.push_back(std::move(jar_file));
343 }
344 args.emplace_back("--runtime-arg");
345 args.emplace_back(Concatenate({"-Xbootclasspathfds:", android::base::Join(bcp_fds, ':')}));
346 return true;
347}
348
349void AddCompiledBootClasspathFdsIfAny(
350 /*inout*/ std::vector<std::string>& args,
351 /*inout*/ std::vector<std::unique_ptr<File>>& output_files,
352 const std::vector<std::string>& bcp_jars,
353 const InstructionSet isa) {
354 std::vector<std::string> bcp_image_fds;
355 std::vector<std::string> bcp_oat_fds;
356 std::vector<std::string> bcp_vdex_fds;
357 std::vector<std::unique_ptr<File>> opened_files;
358 bool added_any = false;
359 for (const std::string& jar : bcp_jars) {
360 std::string image_path = GetApexDataBootImage(jar);
361 image_path = image_path.empty() ? "" : GetSystemImageFilename(image_path.c_str(), isa);
362 std::unique_ptr<File> image_file(OS::OpenFileForReading(image_path.c_str()));
363 if (image_file && image_file->IsValid()) {
364 bcp_image_fds.push_back(std::to_string(image_file->Fd()));
365 opened_files.push_back(std::move(image_file));
366 added_any = true;
367 } else {
368 bcp_image_fds.push_back("-1");
369 }
370
371 std::string oat_path = ReplaceFileExtension(image_path, "oat");
372 std::unique_ptr<File> oat_file(OS::OpenFileForReading(oat_path.c_str()));
373 if (oat_file && oat_file->IsValid()) {
374 bcp_oat_fds.push_back(std::to_string(oat_file->Fd()));
375 opened_files.push_back(std::move(oat_file));
376 added_any = true;
377 } else {
378 bcp_oat_fds.push_back("-1");
379 }
380
381 std::string vdex_path = ReplaceFileExtension(image_path, "vdex");
382 std::unique_ptr<File> vdex_file(OS::OpenFileForReading(vdex_path.c_str()));
383 if (vdex_file && vdex_file->IsValid()) {
384 bcp_vdex_fds.push_back(std::to_string(vdex_file->Fd()));
385 opened_files.push_back(std::move(vdex_file));
386 added_any = true;
387 } else {
388 bcp_vdex_fds.push_back("-1");
389 }
390 }
391 // Add same amount of FDs as BCP JARs, or none.
392 if (added_any) {
393 std::move(opened_files.begin(), opened_files.end(), std::back_inserter(output_files));
394
395 args.emplace_back("--runtime-arg");
396 args.emplace_back(
397 Concatenate({"-Xbootclasspathimagefds:", android::base::Join(bcp_image_fds, ':')}));
398 args.emplace_back("--runtime-arg");
399 args.emplace_back(
400 Concatenate({"-Xbootclasspathoatfds:", android::base::Join(bcp_oat_fds, ':')}));
401 args.emplace_back("--runtime-arg");
402 args.emplace_back(
403 Concatenate({"-Xbootclasspathvdexfds:", android::base::Join(bcp_vdex_fds, ':')}));
404 }
405}
406
407std::string GetStagingLocation(const std::string& staging_dir, const std::string& path) {
408 return Concatenate({staging_dir, "/", android::base::Basename(path)});
409}
410
411std::string JoinFilesAsFDs(const std::vector<std::unique_ptr<File>>& files, char delimiter) {
412 std::stringstream output;
413 bool is_first = true;
414 for (const auto& f : files) {
415 if (is_first) {
416 is_first = false;
417 } else {
418 output << delimiter;
419 }
420 output << std::to_string(f->Fd());
421 }
422 return output.str();
423}
424
425WARN_UNUSED bool CheckCompilationSpace() {
426 // Check the available storage space against an arbitrary threshold because dex2oat does not
427 // report when it runs out of storage space and we do not want to completely fill
428 // the users data partition.
429 //
430 // We do not have a good way of pre-computing the required space for a compilation step, but
431 // typically observe 16MB as the largest size of an AOT artifact. Since there are three
432 // AOT artifacts per compilation step - an image file, executable file, and a verification
433 // data file - the threshold is three times 16MB.
434 static constexpr uint64_t kMinimumSpaceForCompilation = 3 * 16 * 1024 * 1024;
435
436 uint64_t bytes_available;
437 const std::string& art_apex_data_path = GetArtApexData();
438 if (!GetFreeSpace(art_apex_data_path, &bytes_available)) {
439 return false;
440 }
441
442 if (bytes_available < kMinimumSpaceForCompilation) {
443 LOG(WARNING) << "Low space for " << QuotePath(art_apex_data_path) << " (" << bytes_available
444 << " bytes)";
445 return false;
446 }
447
448 return true;
449}
450
451std::string GetBootImage() {
452 // Typically "/apex/com.android.art/javalib/boot.art".
453 return GetArtRoot() + "/javalib/boot.art";
454}
455
Orion Hodson4c3ade62021-02-10 14:07:10 +0000456} // namespace
457
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +0000458OnDeviceRefresh::OnDeviceRefresh(const OdrConfig& config)
Jiakai Zhangb91dad22021-08-16 03:20:07 +0000459 : OnDeviceRefresh(config,
460 Concatenate({kOdrefreshArtifactDirectory, "/", kCacheInfoFile}),
461 std::make_unique<ExecUtils>()) {}
462
463OnDeviceRefresh::OnDeviceRefresh(const OdrConfig& config,
464 const std::string& cache_info_filename,
465 std::unique_ptr<ExecUtils> exec_utils)
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +0000466 : config_{config},
Jiakai Zhangb91dad22021-08-16 03:20:07 +0000467 cache_info_filename_{cache_info_filename},
468 start_time_{time(nullptr)},
469 exec_utils_{std::move(exec_utils)} {
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +0000470 for (const std::string& jar : android::base::Split(config_.GetDex2oatBootClasspath(), ":")) {
471 // Boot class path extensions are those not in the ART APEX. Updatable APEXes should not
472 // have DEX files in the DEX2OATBOOTCLASSPATH. At the time of writing i18n is a non-updatable
473 // APEX and so does appear in the DEX2OATBOOTCLASSPATH.
474 if (!LocationIsOnArtModule(jar)) {
475 boot_extension_compilable_jars_.emplace_back(jar);
476 }
477 }
478
479 systemserver_compilable_jars_ = android::base::Split(config_.GetSystemServerClasspath(), ":");
480 boot_classpath_jars_ = android::base::Split(config_.GetBootClasspath(), ":");
481}
482
483time_t OnDeviceRefresh::GetExecutionTimeUsed() const {
484 return time(nullptr) - start_time_;
485}
486
487time_t OnDeviceRefresh::GetExecutionTimeRemaining() const {
488 return kMaximumExecutionSeconds - GetExecutionTimeUsed();
489}
490
491time_t OnDeviceRefresh::GetSubprocessTimeout() const {
492 return std::max(GetExecutionTimeRemaining(), kMaxChildProcessSeconds);
493}
494
495std::optional<std::vector<apex::ApexInfo>> OnDeviceRefresh::GetApexInfoList() const {
496 std::optional<apex::ApexInfoList> info_list =
497 apex::readApexInfoList(config_.GetApexInfoListFile().c_str());
498 if (!info_list.has_value()) {
499 return std::nullopt;
500 }
501
502 std::vector<apex::ApexInfo> filtered_info_list;
503 std::copy_if(info_list->getApexInfo().begin(),
504 info_list->getApexInfo().end(),
505 std::back_inserter(filtered_info_list),
506 [](const apex::ApexInfo& info) { return info.getIsActive(); });
507 return filtered_info_list;
508}
509
510std::optional<art_apex::CacheInfo> OnDeviceRefresh::ReadCacheInfo() const {
511 return art_apex::read(cache_info_filename_.c_str());
512}
513
514void OnDeviceRefresh::WriteCacheInfo() const {
515 if (OS::FileExists(cache_info_filename_.c_str())) {
516 if (unlink(cache_info_filename_.c_str()) != 0) {
517 PLOG(ERROR) << "Failed to unlink() file " << QuotePath(cache_info_filename_);
518 }
519 }
520
521 const std::string dir_name = android::base::Dirname(cache_info_filename_);
522 if (!EnsureDirectoryExists(dir_name)) {
523 LOG(ERROR) << "Could not create directory: " << QuotePath(dir_name);
524 return;
525 }
526
527 std::optional<std::vector<apex::ApexInfo>> apex_info_list = GetApexInfoList();
528 if (!apex_info_list.has_value()) {
529 LOG(ERROR) << "Could not update " << QuotePath(cache_info_filename_) << " : no APEX info";
530 return;
531 }
532
533 std::optional<apex::ApexInfo> art_apex_info = GetArtApexInfo(apex_info_list.value());
534 if (!art_apex_info.has_value()) {
535 LOG(ERROR) << "Could not update " << QuotePath(cache_info_filename_) << " : no ART APEX info";
536 return;
537 }
538
539 art_apex::ModuleInfo art_module_info = GenerateModuleInfo(art_apex_info.value());
540 std::vector<art_apex::ModuleInfo> module_info_list =
541 GenerateModuleInfoList(apex_info_list.value());
542
543 std::optional<std::vector<art_apex::Component>> bcp_components =
544 GenerateBootClasspathComponents();
545 if (!bcp_components.has_value()) {
546 LOG(ERROR) << "No boot classpath components.";
547 return;
548 }
549
550 std::optional<std::vector<art_apex::Component>> bcp_compilable_components =
551 GenerateBootExtensionCompilableComponents();
552 if (!bcp_compilable_components.has_value()) {
553 LOG(ERROR) << "No boot classpath extension compilable components.";
554 return;
555 }
556
557 std::optional<std::vector<art_apex::Component>> system_server_components =
558 GenerateSystemServerComponents();
559 if (!system_server_components.has_value()) {
560 LOG(ERROR) << "No system_server extension components.";
561 return;
562 }
563
564 std::ofstream out(cache_info_filename_.c_str());
565 art_apex::CacheInfo info({art_module_info},
566 {art_apex::ModuleInfoList(module_info_list)},
567 {art_apex::Classpath(bcp_components.value())},
568 {art_apex::Classpath(bcp_compilable_components.value())},
569 {art_apex::Classpath(system_server_components.value())});
570
571 art_apex::write(out, info);
572}
573
574void OnDeviceRefresh::ReportNextBootAnimationProgress(uint32_t current_compilation) const {
575 uint32_t number_of_compilations =
576 config_.GetBootExtensionIsas().size() + systemserver_compilable_jars_.size();
577 // We arbitrarily show progress until 90%, expecting that our compilations
578 // take a large chunk of boot time.
579 uint32_t value = (90 * current_compilation) / number_of_compilations;
580 android::base::SetProperty("service.bootanim.progress", std::to_string(value));
581}
582
583std::vector<art_apex::Component> OnDeviceRefresh::GenerateBootClasspathComponents() const {
584 return GenerateComponents(boot_classpath_jars_);
585}
586
587std::vector<art_apex::Component> OnDeviceRefresh::GenerateBootExtensionCompilableComponents()
588 const {
589 return GenerateComponents(boot_extension_compilable_jars_);
590}
591
592std::vector<art_apex::Component> OnDeviceRefresh::GenerateSystemServerComponents() const {
593 return GenerateComponents(systemserver_compilable_jars_);
594}
595
596std::string OnDeviceRefresh::GetBootImageExtensionImage(bool on_system) const {
597 CHECK(!boot_extension_compilable_jars_.empty());
598 const std::string leading_jar = boot_extension_compilable_jars_[0];
599 if (on_system) {
600 const std::string jar_name = android::base::Basename(leading_jar);
601 const std::string image_name = ReplaceFileExtension(jar_name, "art");
602 // Typically "/system/framework/boot-framework.art".
603 return Concatenate({GetAndroidRoot(), "/framework/boot-", image_name});
604 } else {
605 // Typically "/data/misc/apexdata/com.android.art/dalvik-cache/boot-framework.art".
606 return GetApexDataBootImage(leading_jar);
607 }
608}
609
610std::string OnDeviceRefresh::GetBootImageExtensionImagePath(bool on_system,
611 const InstructionSet isa) const {
612 // Typically "/data/misc/apexdata/com.android.art/dalvik-cache/<isa>/boot-framework.art".
613 return GetSystemImageFilename(GetBootImageExtensionImage(on_system).c_str(), isa);
614}
615
616std::string OnDeviceRefresh::GetSystemServerImagePath(bool on_system,
617 const std::string& jar_path) const {
618 if (on_system) {
619 // TODO(b/194150908): Define a path for "preopted" APEX artifacts.
620 const std::string jar_name = android::base::Basename(jar_path);
621 const std::string image_name = ReplaceFileExtension(jar_name, "art");
622 const char* isa_str = GetInstructionSetString(config_.GetSystemServerIsa());
623 // Typically "/system/framework/oat/<isa>/services.art".
624 return Concatenate({GetAndroidRoot(), "/framework/oat/", isa_str, "/", image_name});
625 } else {
626 // Typically
627 // "/data/misc/apexdata/.../dalvik-cache/<isa>/system@framework@services.jar@classes.art".
628 const std::string image = GetApexDataImage(jar_path.c_str());
629 return GetSystemImageFilename(image.c_str(), config_.GetSystemServerIsa());
630 }
631}
632
633WARN_UNUSED bool OnDeviceRefresh::RemoveBootExtensionArtifactsFromData(InstructionSet isa) const {
634 if (config_.GetDryRun()) {
635 LOG(INFO) << "Removal of bcp extension artifacts on /data skipped (dry-run).";
Orion Hodson4c3ade62021-02-10 14:07:10 +0000636 return true;
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +0000637 }
638
639 const std::string apexdata_image_location =
640 GetBootImageExtensionImagePath(/*on_system=*/false, isa);
641 LOG(INFO) << "Removing boot class path artifacts on /data for "
642 << QuotePath(apexdata_image_location);
643 return RemoveArtifacts(OdrArtifacts::ForBootImageExtension(apexdata_image_location));
644}
645
646WARN_UNUSED bool OnDeviceRefresh::RemoveSystemServerArtifactsFromData() const {
647 if (config_.GetDryRun()) {
648 LOG(INFO) << "Removal of system_server artifacts on /data skipped (dry-run).";
Orion Hodson4c3ade62021-02-10 14:07:10 +0000649 return true;
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +0000650 }
651
652 bool success = true;
653 for (const std::string& jar_path : systemserver_compilable_jars_) {
654 const std::string image_location = GetSystemServerImagePath(/*on_system=*/false, jar_path);
655 const OdrArtifacts artifacts = OdrArtifacts::ForSystemServer(image_location);
656 LOG(INFO) << "Removing system_server artifacts on /data for " << QuotePath(jar_path);
657 success &= RemoveArtifacts(artifacts);
658 }
659 return success;
660}
661
662WARN_UNUSED bool OnDeviceRefresh::RemoveArtifacts(const OdrArtifacts& artifacts) const {
663 bool success = true;
664 for (const auto& location : {artifacts.ImagePath(), artifacts.OatPath(), artifacts.VdexPath()}) {
665 if (config_.GetDryRun()) {
666 LOG(INFO) << "Removing " << QuotePath(location) << " (dry-run).";
667 continue;
668 }
669
670 if (OS::FileExists(location.c_str()) && unlink(location.c_str()) != 0) {
671 PLOG(ERROR) << "Failed to remove: " << QuotePath(location);
672 success = false;
673 }
674 }
675 return success;
676}
677
678WARN_UNUSED bool OnDeviceRefresh::RemoveArtifactsDirectory() const {
679 if (config_.GetDryRun()) {
680 LOG(INFO) << "Directory " << QuotePath(kOdrefreshArtifactDirectory)
681 << " and contents would be removed (dry-run).";
Orion Hodson4c3ade62021-02-10 14:07:10 +0000682 return true;
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +0000683 }
684 return RemoveDirectory(kOdrefreshArtifactDirectory);
685}
686
687WARN_UNUSED bool OnDeviceRefresh::BootExtensionArtifactsExist(
688 bool on_system,
689 const InstructionSet isa,
690 /*out*/ std::string* error_msg) const {
691 const std::string apexdata_image_location = GetBootImageExtensionImagePath(on_system, isa);
692 const OdrArtifacts artifacts = OdrArtifacts::ForBootImageExtension(apexdata_image_location);
693 return ArtifactsExist(artifacts, /*check_art_file=*/true, error_msg);
694}
695
696WARN_UNUSED bool OnDeviceRefresh::SystemServerArtifactsExist(bool on_system,
697 /*out*/ std::string* error_msg) const {
698 for (const std::string& jar_path : systemserver_compilable_jars_) {
699 // Temporarily skip checking APEX jar artifacts on system to prevent compilation on the first
700 // boot. Currently, APEX jar artifacts can never be found on system because we don't preopt
701 // them.
702 // TODO(b/194150908): Preopt APEX jars for system server and put the artifacts on /system.
703 if (on_system && StartsWith(jar_path, "/apex")) {
704 continue;
705 }
706 const std::string image_location = GetSystemServerImagePath(on_system, jar_path);
707 const OdrArtifacts artifacts = OdrArtifacts::ForSystemServer(image_location);
708 // .art files are optional and are not generated for all jars by the build system.
709 const bool check_art_file = !on_system;
710 if (!ArtifactsExist(artifacts, check_art_file, error_msg)) {
711 return false;
712 }
713 }
714 return true;
715}
716
717WARN_UNUSED bool OnDeviceRefresh::CheckBootExtensionArtifactsAreUpToDate(
718 OdrMetrics& metrics,
719 const InstructionSet isa,
720 const apex::ApexInfo& art_apex_info,
721 const std::optional<art_apex::CacheInfo>& cache_info,
722 /*out*/ bool* cleanup_required) const {
723 std::string error_msg;
724
725 if (art_apex_info.getIsFactory()) {
726 LOG(INFO) << "Factory ART APEX mounted.";
727
728 // ART is not updated, so we can use the artifacts on /system. Check if they exist.
729 if (BootExtensionArtifactsExist(/*on_system=*/true, isa, &error_msg)) {
730 // We don't need the artifacts on /data since we can use those on /system.
731 *cleanup_required = true;
732 return true;
733 }
734
735 LOG(INFO) << "Incomplete boot extension artifacts on /system. " << error_msg;
736 LOG(INFO) << "Checking cache.";
737 }
738
739 if (!cache_info.has_value()) {
740 // If the cache info file does not exist, it means on-device compilation has not been done
741 // before.
742 PLOG(INFO) << "No prior cache-info file: " << QuotePath(cache_info_filename_);
743 metrics.SetTrigger(OdrMetrics::Trigger::kMissingArtifacts);
744 *cleanup_required = true;
745 return false;
746 }
747
748 // Check whether the current cache ART module info differs from the current ART module info.
749 const art_apex::ModuleInfo* cached_art_info = cache_info->getFirstArtModuleInfo();
750
751 if (cached_art_info == nullptr) {
752 LOG(INFO) << "Missing ART APEX info from cache-info.";
753 metrics.SetTrigger(OdrMetrics::Trigger::kApexVersionMismatch);
754 *cleanup_required = true;
755 return false;
756 }
757
758 if (cached_art_info->getVersionCode() != art_apex_info.getVersionCode()) {
759 LOG(INFO) << "ART APEX version code mismatch (" << cached_art_info->getVersionCode()
760 << " != " << art_apex_info.getVersionCode() << ").";
761 metrics.SetTrigger(OdrMetrics::Trigger::kApexVersionMismatch);
762 *cleanup_required = true;
763 return false;
764 }
765
766 if (cached_art_info->getVersionName() != art_apex_info.getVersionName()) {
767 LOG(INFO) << "ART APEX version name mismatch (" << cached_art_info->getVersionName()
768 << " != " << art_apex_info.getVersionName() << ").";
769 metrics.SetTrigger(OdrMetrics::Trigger::kApexVersionMismatch);
770 *cleanup_required = true;
771 return false;
772 }
773
774 // Check lastUpdateMillis for samegrade installs. If `cached_art_info` is missing
775 // lastUpdateMillis then it is not current with the schema used by this binary so treat it as a
776 // samegrade update. Otherwise check whether the lastUpdateMillis changed.
777 if (!cached_art_info->hasLastUpdateMillis() ||
778 cached_art_info->getLastUpdateMillis() != art_apex_info.getLastUpdateMillis()) {
779 LOG(INFO) << "ART APEX last update time mismatch (" << cached_art_info->getLastUpdateMillis()
780 << " != " << art_apex_info.getLastUpdateMillis() << ").";
781 metrics.SetTrigger(OdrMetrics::Trigger::kApexVersionMismatch);
782 *cleanup_required = true;
783 return false;
784 }
785
786 // Check boot class components.
787 //
788 // This checks the size and checksums of odrefresh compilable files on the DEX2OATBOOTCLASSPATH
789 // (the Odrefresh constructor determines which files are compilable). If the number of files
790 // there changes, or their size or checksums change then compilation will be triggered.
791 //
792 // The boot class components may change unexpectedly, for example an OTA could update
793 // framework.jar.
794 const std::vector<art_apex::Component> expected_bcp_compilable_components =
795 GenerateBootExtensionCompilableComponents();
796 if (expected_bcp_compilable_components.size() != 0 &&
797 (!cache_info->hasDex2oatBootClasspath() ||
798 !cache_info->getFirstDex2oatBootClasspath()->hasComponent())) {
799 LOG(INFO) << "Missing Dex2oatBootClasspath components.";
800 metrics.SetTrigger(OdrMetrics::Trigger::kDexFilesChanged);
801 *cleanup_required = true;
802 return false;
803 }
804
805 const std::vector<art_apex::Component>& bcp_compilable_components =
806 cache_info->getFirstDex2oatBootClasspath()->getComponent();
807 if (!CheckComponents(expected_bcp_compilable_components, bcp_compilable_components, &error_msg)) {
808 LOG(INFO) << "Dex2OatClasspath components mismatch: " << error_msg;
809 metrics.SetTrigger(OdrMetrics::Trigger::kDexFilesChanged);
810 *cleanup_required = true;
811 return false;
812 }
813
814 // Cache info looks good, check all compilation artifacts exist.
815 if (!BootExtensionArtifactsExist(/*on_system=*/false, isa, &error_msg)) {
816 LOG(INFO) << "Incomplete boot extension artifacts. " << error_msg;
817 metrics.SetTrigger(OdrMetrics::Trigger::kMissingArtifacts);
818 *cleanup_required = true;
819 return false;
820 }
821
822 *cleanup_required = false;
823 return true;
824}
825
826WARN_UNUSED bool OnDeviceRefresh::CheckSystemServerArtifactsAreUpToDate(
827 OdrMetrics& metrics,
828 const std::vector<apex::ApexInfo>& apex_info_list,
829 const std::optional<art_apex::CacheInfo>& cache_info,
830 /*out*/ bool* cleanup_required) const {
831 std::string error_msg;
832
833 if (std::all_of(apex_info_list.begin(),
834 apex_info_list.end(),
835 [](const apex::ApexInfo& apex_info) { return apex_info.getIsFactory(); })) {
836 LOG(INFO) << "Factory APEXes mounted.";
837
838 // APEXes are not updated, so we can use the artifacts on /system. Check if they exist.
839 if (SystemServerArtifactsExist(/*on_system=*/true, &error_msg)) {
840 // We don't need the artifacts on /data since we can use those on /system.
841 *cleanup_required = true;
842 return true;
843 }
844
845 LOG(INFO) << "Incomplete system server artifacts on /system. " << error_msg;
846 LOG(INFO) << "Checking cache.";
847 }
848
849 if (!cache_info.has_value()) {
850 // If the cache info file does not exist, it means on-device compilation has not been done
851 // before.
852 PLOG(INFO) << "No prior cache-info file: " << QuotePath(cache_info_filename_);
853 metrics.SetTrigger(OdrMetrics::Trigger::kMissingArtifacts);
854 *cleanup_required = true;
855 return false;
856 }
857
858 // Check whether the current cached module info differs from the current module info.
859 const art_apex::ModuleInfoList* cached_module_info_list = cache_info->getFirstModuleInfoList();
860
861 if (cached_module_info_list == nullptr) {
862 LOG(INFO) << "Missing APEX info list from cache-info.";
863 metrics.SetTrigger(OdrMetrics::Trigger::kApexVersionMismatch);
864 *cleanup_required = true;
865 return false;
866 }
867
868 std::unordered_map<std::string, const art_apex::ModuleInfo*> cached_module_info_map;
869 for (const art_apex::ModuleInfo& module_info : cached_module_info_list->getModuleInfo()) {
870 if (!module_info.hasName()) {
871 LOG(INFO) << "Unexpected module info from cache-info. Missing module name.";
872 metrics.SetTrigger(OdrMetrics::Trigger::kUnknown);
873 *cleanup_required = true;
874 return false;
875 }
876 cached_module_info_map[module_info.getName()] = &module_info;
877 }
878
879 for (const apex::ApexInfo& current_apex_info : apex_info_list) {
880 auto it = cached_module_info_map.find(current_apex_info.getModuleName());
881 if (it == cached_module_info_map.end()) {
882 LOG(INFO) << "Missing APEX info from cache-info (" << current_apex_info.getModuleName()
883 << ").";
884 metrics.SetTrigger(OdrMetrics::Trigger::kApexVersionMismatch);
885 *cleanup_required = true;
886 return false;
887 }
888
889 const art_apex::ModuleInfo* cached_module_info = it->second;
890
891 if (cached_module_info->getVersionCode() != current_apex_info.getVersionCode()) {
892 LOG(INFO) << "APEX (" << current_apex_info.getModuleName() << ") version code mismatch ("
893 << cached_module_info->getVersionCode()
894 << " != " << current_apex_info.getVersionCode() << ").";
895 metrics.SetTrigger(OdrMetrics::Trigger::kApexVersionMismatch);
896 *cleanup_required = true;
897 return false;
898 }
899
900 if (cached_module_info->getVersionName() != current_apex_info.getVersionName()) {
901 LOG(INFO) << "APEX (" << current_apex_info.getModuleName() << ") version name mismatch ("
902 << cached_module_info->getVersionName()
903 << " != " << current_apex_info.getVersionName() << ").";
904 metrics.SetTrigger(OdrMetrics::Trigger::kApexVersionMismatch);
905 *cleanup_required = true;
906 return false;
907 }
908
909 if (!cached_module_info->hasLastUpdateMillis() ||
910 cached_module_info->getLastUpdateMillis() != current_apex_info.getLastUpdateMillis()) {
911 LOG(INFO) << "APEX (" << current_apex_info.getModuleName() << ") last update time mismatch ("
912 << cached_module_info->getLastUpdateMillis()
913 << " != " << current_apex_info.getLastUpdateMillis() << ").";
914 metrics.SetTrigger(OdrMetrics::Trigger::kApexVersionMismatch);
915 *cleanup_required = true;
916 return false;
917 }
918 }
919
920 // Check system server components.
921 //
922 // This checks the size and checksums of odrefresh compilable files on the
923 // SYSTEMSERVERCLASSPATH (the Odrefresh constructor determines which files are compilable). If
924 // the number of files there changes, or their size or checksums change then compilation will be
925 // triggered.
926 //
927 // The system_server components may change unexpectedly, for example an OTA could update
928 // services.jar.
929 const std::vector<art_apex::Component> expected_system_server_components =
930 GenerateSystemServerComponents();
931 if (expected_system_server_components.size() != 0 &&
932 (!cache_info->hasSystemServerClasspath() ||
933 !cache_info->getFirstSystemServerClasspath()->hasComponent())) {
934 LOG(INFO) << "Missing SystemServerClasspath components.";
935 metrics.SetTrigger(OdrMetrics::Trigger::kDexFilesChanged);
936 *cleanup_required = true;
937 return false;
938 }
939
940 const std::vector<art_apex::Component>& system_server_components =
941 cache_info->getFirstSystemServerClasspath()->getComponent();
942 if (!CheckComponents(expected_system_server_components, system_server_components, &error_msg)) {
943 LOG(INFO) << "SystemServerClasspath components mismatch: " << error_msg;
944 metrics.SetTrigger(OdrMetrics::Trigger::kDexFilesChanged);
945 *cleanup_required = true;
946 return false;
947 }
948
949 const std::vector<art_apex::Component> expected_bcp_components =
950 GenerateBootClasspathComponents();
951 if (expected_bcp_components.size() != 0 &&
952 (!cache_info->hasBootClasspath() || !cache_info->getFirstBootClasspath()->hasComponent())) {
953 LOG(INFO) << "Missing BootClasspath components.";
954 metrics.SetTrigger(OdrMetrics::Trigger::kDexFilesChanged);
955 *cleanup_required = true;
956 return false;
957 }
958
959 const std::vector<art_apex::Component>& bcp_components =
960 cache_info->getFirstBootClasspath()->getComponent();
961 if (!CheckComponents(expected_bcp_components, bcp_components, &error_msg)) {
962 LOG(INFO) << "BootClasspath components mismatch: " << error_msg;
963 metrics.SetTrigger(OdrMetrics::Trigger::kDexFilesChanged);
964 // Boot classpath components can be dependencies of system_server components, so system_server
965 // components need to be recompiled if boot classpath components are changed.
966 *cleanup_required = true;
967 return false;
968 }
969
970 if (!SystemServerArtifactsExist(/*on_system=*/false, &error_msg)) {
971 LOG(INFO) << "Incomplete system_server artifacts. " << error_msg;
972 // No clean-up is required here: we have boot extension artifacts. The method
973 // `SystemServerArtifactsExistOnData()` checks in compilation order so it is possible some of
974 // the artifacts are here. We likely ran out of space compiling the system_server artifacts.
975 // Any artifacts present are usable.
976 metrics.SetTrigger(OdrMetrics::Trigger::kMissingArtifacts);
977 *cleanup_required = false;
978 return false;
979 }
980
981 *cleanup_required = false;
982 return true;
983}
984
985WARN_UNUSED ExitCode OnDeviceRefresh::CheckArtifactsAreUpToDate(
986 OdrMetrics& metrics,
987 /*out*/ std::vector<InstructionSet>* compile_boot_extensions,
988 /*out*/ bool* compile_system_server) const {
989 metrics.SetStage(OdrMetrics::Stage::kCheck);
990
991 // Clean-up helper used to simplify clean-ups and handling failures there.
992 auto cleanup_and_compile_all = [&, this]() {
993 *compile_boot_extensions = config_.GetBootExtensionIsas();
994 *compile_system_server = true;
995 return RemoveArtifactsDirectory() ? ExitCode::kCompilationRequired : ExitCode::kCleanupFailed;
996 };
997
998 std::optional<std::vector<apex::ApexInfo>> apex_info_list = GetApexInfoList();
999 if (!apex_info_list.has_value()) {
1000 // This should never happen, further up-to-date checks are not possible if it does.
1001 LOG(ERROR) << "Could not get APEX info.";
1002 metrics.SetTrigger(OdrMetrics::Trigger::kUnknown);
1003 return cleanup_and_compile_all();
1004 }
1005
1006 std::optional<apex::ApexInfo> art_apex_info = GetArtApexInfo(apex_info_list.value());
1007 if (!art_apex_info.has_value()) {
1008 // This should never happen, further up-to-date checks are not possible if it does.
1009 LOG(ERROR) << "Could not get ART APEX info.";
1010 metrics.SetTrigger(OdrMetrics::Trigger::kUnknown);
1011 return cleanup_and_compile_all();
1012 }
1013
1014 // Record ART APEX version for metrics reporting.
1015 metrics.SetArtApexVersion(art_apex_info->getVersionCode());
1016
1017 // Record ART APEX last update milliseconds (used in compilation log).
1018 metrics.SetArtApexLastUpdateMillis(art_apex_info->getLastUpdateMillis());
1019
1020 std::optional<art_apex::CacheInfo> cache_info = ReadCacheInfo();
1021 if (!cache_info.has_value() && OS::FileExists(cache_info_filename_.c_str())) {
1022 // This should not happen unless odrefresh is updated to a new version that is not
1023 // compatible with an old cache-info file. Further up-to-date checks are not possible if it
1024 // does.
1025 PLOG(ERROR) << "Failed to parse cache-info file: " << QuotePath(cache_info_filename_);
1026 metrics.SetTrigger(OdrMetrics::Trigger::kUnknown);
1027 return cleanup_and_compile_all();
1028 }
1029
1030 InstructionSet system_server_isa = config_.GetSystemServerIsa();
1031 bool cleanup_required;
1032
1033 for (const InstructionSet isa : config_.GetBootExtensionIsas()) {
1034 cleanup_required = false;
1035 if (!CheckBootExtensionArtifactsAreUpToDate(
1036 metrics, isa, art_apex_info.value(), cache_info, &cleanup_required)) {
1037 compile_boot_extensions->push_back(isa);
1038 // system_server artifacts are invalid without valid boot extension artifacts.
1039 if (isa == system_server_isa) {
1040 *compile_system_server = true;
1041 if (!RemoveSystemServerArtifactsFromData()) {
1042 return ExitCode::kCleanupFailed;
1043 }
1044 }
1045 }
1046 if (cleanup_required) {
1047 if (!RemoveBootExtensionArtifactsFromData(isa)) {
1048 return ExitCode::kCleanupFailed;
1049 }
1050 }
1051 }
1052
1053 cleanup_required = false;
1054 if (!*compile_system_server &&
1055 !CheckSystemServerArtifactsAreUpToDate(
1056 metrics, apex_info_list.value(), cache_info, &cleanup_required)) {
1057 *compile_system_server = true;
1058 }
1059 if (cleanup_required) {
1060 if (!RemoveSystemServerArtifactsFromData()) {
1061 return ExitCode::kCleanupFailed;
1062 }
1063 }
1064
1065 return (!compile_boot_extensions->empty() || *compile_system_server) ?
1066 ExitCode::kCompilationRequired :
1067 ExitCode::kOkay;
1068}
1069
1070WARN_UNUSED bool OnDeviceRefresh::VerifyBootExtensionArtifactsAreUpToDate(const InstructionSet isa,
1071 bool on_system) const {
1072 const std::string dex_file = boot_extension_compilable_jars_.front();
1073 const std::string image_location = GetBootImageExtensionImage(on_system);
1074
1075 std::vector<std::string> args;
1076 args.emplace_back(config_.GetDexOptAnalyzer());
1077 args.emplace_back("--validate-bcp");
1078 args.emplace_back(Concatenate({"--image=", GetBootImage(), ":", image_location}));
1079 args.emplace_back(Concatenate({"--isa=", GetInstructionSetString(isa)}));
1080 args.emplace_back("--runtime-arg");
1081 args.emplace_back(Concatenate({"-Xbootclasspath:", config_.GetDex2oatBootClasspath()}));
1082
1083 LOG(INFO) << "Checking " << dex_file << ": " << android::base::Join(args, ' ');
1084
1085 std::string error_msg;
1086 bool timed_out = false;
1087 const time_t timeout = GetSubprocessTimeout();
Jiakai Zhangb91dad22021-08-16 03:20:07 +00001088 const int dexoptanalyzer_result =
1089 exec_utils_->ExecAndReturnCode(args, timeout, &timed_out, &error_msg);
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +00001090 if (dexoptanalyzer_result == -1) {
1091 LOG(ERROR) << "Unexpected exit from dexoptanalyzer: " << error_msg;
1092 if (timed_out) {
1093 // TODO(oth): record metric for timeout.
1094 }
1095 return false;
1096 }
1097 auto rc = static_cast<dexoptanalyzer::ReturnCode>(dexoptanalyzer_result);
1098 if (rc == dexoptanalyzer::ReturnCode::kNoDexOptNeeded) {
Orion Hodson4c3ade62021-02-10 14:07:10 +00001099 return true;
1100 }
1101 return false;
1102}
1103
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +00001104WARN_UNUSED bool OnDeviceRefresh::VerifyBootExtensionArtifactsAreUpToDate(
1105 InstructionSet isa) const {
1106 bool system_ok = VerifyBootExtensionArtifactsAreUpToDate(isa, /*on_system=*/true);
1107 LOG(INFO) << "Boot extension artifacts on /system are " << (system_ok ? "ok" : "stale");
1108 bool data_ok = VerifyBootExtensionArtifactsAreUpToDate(isa, /*on_system=*/false);
1109 LOG(INFO) << "Boot extension artifacts on /data are " << (data_ok ? "ok" : "stale");
1110 return system_ok || data_ok;
1111}
Orion Hodson4c3ade62021-02-10 14:07:10 +00001112
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +00001113WARN_UNUSED bool OnDeviceRefresh::VerifySystemServerArtifactsAreUpToDate(bool on_system) const {
1114 std::vector<std::string> classloader_context;
1115 for (const std::string& jar_path : systemserver_compilable_jars_) {
Orion Hodson4c3ade62021-02-10 14:07:10 +00001116 std::vector<std::string> args;
1117 args.emplace_back(config_.GetDexOptAnalyzer());
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +00001118 args.emplace_back("--dex-file=" + jar_path);
1119
1120 const std::string image_location = GetSystemServerImagePath(on_system, jar_path);
1121
1122 // odrefresh produces app-image files, but these are not guaranteed for those pre-installed
1123 // on /system.
1124 if (!on_system && !OS::FileExists(image_location.c_str(), true)) {
1125 LOG(INFO) << "Missing image file: " << QuotePath(image_location);
1126 return false;
1127 }
1128
1129 // Generate set of artifacts that are output by compilation.
1130 OdrArtifacts artifacts = OdrArtifacts::ForSystemServer(image_location);
1131 if (!on_system) {
1132 CHECK_EQ(artifacts.OatPath(),
1133 GetApexDataOdexFilename(jar_path, config_.GetSystemServerIsa()));
1134 CHECK_EQ(artifacts.ImagePath(),
1135 GetApexDataDalvikCacheFilename(jar_path, config_.GetSystemServerIsa(), "art"));
1136 CHECK_EQ(artifacts.OatPath(),
1137 GetApexDataDalvikCacheFilename(jar_path, config_.GetSystemServerIsa(), "odex"));
1138 CHECK_EQ(artifacts.VdexPath(),
1139 GetApexDataDalvikCacheFilename(jar_path, config_.GetSystemServerIsa(), "vdex"));
1140 }
1141
1142 // Associate inputs and outputs with dexoptanalyzer arguments.
1143 std::pair<const std::string, const char*> location_args[] = {
1144 std::make_pair(artifacts.OatPath(), "--oat-fd="),
1145 std::make_pair(artifacts.VdexPath(), "--vdex-fd="),
1146 std::make_pair(jar_path, "--zip-fd=")};
1147
1148 // Open file descriptors for dexoptanalyzer file inputs and add to the command-line.
1149 std::vector<std::unique_ptr<File>> files;
1150 for (const auto& location_arg : location_args) {
1151 auto& [location, arg] = location_arg;
1152 std::unique_ptr<File> file(OS::OpenFileForReading(location.c_str()));
1153 if (file == nullptr) {
1154 PLOG(ERROR) << "Failed to open \"" << location << "\"";
1155 return false;
1156 }
1157 args.emplace_back(android::base::StringPrintf("%s%d", arg, file->Fd()));
1158 files.emplace_back(file.release());
1159 }
1160
1161 const std::string basename(android::base::Basename(jar_path));
1162 const std::string root = GetAndroidRoot();
1163 const std::string profile_file = Concatenate({root, "/framework/", basename, ".prof"});
1164 if (OS::FileExists(profile_file.c_str())) {
1165 args.emplace_back("--compiler-filter=speed-profile");
1166 } else {
1167 args.emplace_back("--compiler-filter=speed");
1168 }
1169
1170 args.emplace_back(
1171 Concatenate({"--image=", GetBootImage(), ":", GetBootImageExtensionImage(on_system)}));
1172 args.emplace_back(
1173 Concatenate({"--isa=", GetInstructionSetString(config_.GetSystemServerIsa())}));
Orion Hodson4c3ade62021-02-10 14:07:10 +00001174 args.emplace_back("--runtime-arg");
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +00001175 args.emplace_back(Concatenate({"-Xbootclasspath:", config_.GetBootClasspath()}));
1176 args.emplace_back(Concatenate(
1177 {"--class-loader-context=PCL[", android::base::Join(classloader_context, ':'), "]"}));
Orion Hodson4c3ade62021-02-10 14:07:10 +00001178
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +00001179 classloader_context.emplace_back(jar_path);
Orion Hodson4c3ade62021-02-10 14:07:10 +00001180
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +00001181 LOG(INFO) << "Checking " << jar_path << ": " << android::base::Join(args, ' ');
Orion Hodson4c3ade62021-02-10 14:07:10 +00001182 std::string error_msg;
1183 bool timed_out = false;
1184 const time_t timeout = GetSubprocessTimeout();
Jiakai Zhangb91dad22021-08-16 03:20:07 +00001185 const int dexoptanalyzer_result =
1186 exec_utils_->ExecAndReturnCode(args, timeout, &timed_out, &error_msg);
Orion Hodson4c3ade62021-02-10 14:07:10 +00001187 if (dexoptanalyzer_result == -1) {
1188 LOG(ERROR) << "Unexpected exit from dexoptanalyzer: " << error_msg;
1189 if (timed_out) {
1190 // TODO(oth): record metric for timeout.
1191 }
1192 return false;
1193 }
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +00001194 LOG(INFO) << "dexoptanalyzer returned " << dexoptanalyzer_result;
Orion Hodson4c3ade62021-02-10 14:07:10 +00001195
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +00001196 bool unexpected_result = true;
1197 switch (static_cast<dexoptanalyzer::ReturnCode>(dexoptanalyzer_result)) {
1198 case art::dexoptanalyzer::ReturnCode::kNoDexOptNeeded:
1199 unexpected_result = false;
1200 break;
1201
1202 // Recompile needed
1203 case art::dexoptanalyzer::ReturnCode::kDex2OatFromScratch:
1204 case art::dexoptanalyzer::ReturnCode::kDex2OatForBootImageOat:
1205 case art::dexoptanalyzer::ReturnCode::kDex2OatForFilterOat:
1206 case art::dexoptanalyzer::ReturnCode::kDex2OatForBootImageOdex:
1207 case art::dexoptanalyzer::ReturnCode::kDex2OatForFilterOdex:
1208 return false;
1209
1210 // Unexpected issues (note no default-case here to catch missing enum values, but the
1211 // return code from dexoptanalyzer may also be outside expected values, such as a
1212 // process crash.
1213 case art::dexoptanalyzer::ReturnCode::kFlattenClassLoaderContextSuccess:
1214 case art::dexoptanalyzer::ReturnCode::kErrorInvalidArguments:
1215 case art::dexoptanalyzer::ReturnCode::kErrorCannotCreateRuntime:
1216 case art::dexoptanalyzer::ReturnCode::kErrorUnknownDexOptNeeded:
1217 break;
Orion Hodson4c3ade62021-02-10 14:07:10 +00001218 }
Orion Hodson3407fb22021-03-17 14:40:51 +00001219
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +00001220 if (unexpected_result) {
1221 LOG(ERROR) << "Unexpected result from dexoptanalyzer: " << dexoptanalyzer_result;
1222 return false;
Orion Hodson947a8502021-03-08 15:40:09 +00001223 }
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +00001224 }
1225 return true;
1226}
1227
1228WARN_UNUSED bool OnDeviceRefresh::VerifySystemServerArtifactsAreUpToDate() const {
1229 bool system_ok = VerifySystemServerArtifactsAreUpToDate(/*on_system=*/true);
1230 LOG(INFO) << "system_server artifacts on /system are " << (system_ok ? "ok" : "stale");
1231 bool data_ok = VerifySystemServerArtifactsAreUpToDate(/*on_system=*/false);
1232 LOG(INFO) << "system_server artifacts on /data are " << (data_ok ? "ok" : "stale");
1233 return system_ok || data_ok;
1234}
1235
1236WARN_UNUSED ExitCode OnDeviceRefresh::VerifyArtifactsAreUpToDate() const {
1237 ExitCode exit_code = ExitCode::kOkay;
1238 for (const InstructionSet isa : config_.GetBootExtensionIsas()) {
1239 if (!VerifyBootExtensionArtifactsAreUpToDate(isa)) {
1240 // system_server artifacts are invalid without valid boot extension artifacts.
1241 if (!RemoveSystemServerArtifactsFromData() || !RemoveBootExtensionArtifactsFromData(isa)) {
Orion Hodson3407fb22021-03-17 14:40:51 +00001242 return ExitCode::kCleanupFailed;
1243 }
Orion Hodson947a8502021-03-08 15:40:09 +00001244 exit_code = ExitCode::kCompilationRequired;
1245 }
Orion Hodson947a8502021-03-08 15:40:09 +00001246 }
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +00001247 if (!VerifySystemServerArtifactsAreUpToDate()) {
1248 if (!RemoveSystemServerArtifactsFromData()) {
1249 return ExitCode::kCleanupFailed;
Orion Hodsonf96c9162021-04-07 10:43:01 +01001250 }
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +00001251 exit_code = ExitCode::kCompilationRequired;
1252 }
1253 return exit_code;
1254}
1255
1256WARN_UNUSED bool OnDeviceRefresh::CompileBootExtensionArtifacts(const InstructionSet isa,
1257 const std::string& staging_dir,
1258 OdrMetrics& metrics,
1259 uint32_t* dex2oat_invocation_count,
1260 std::string* error_msg) const {
1261 ScopedOdrCompilationTimer compilation_timer(metrics);
1262 std::vector<std::string> args;
1263 args.push_back(config_.GetDex2Oat());
1264
1265 AddDex2OatCommonOptions(&args);
1266 AddDex2OatConcurrencyArguments(&args);
1267 AddDex2OatDebugInfo(&args);
1268 AddDex2OatInstructionSet(&args, isa);
1269
1270 std::vector<std::unique_ptr<File>> readonly_files_raii;
1271 const std::string boot_profile_file(GetAndroidRoot() + "/etc/boot-image.prof");
1272 AddDex2OatProfileAndCompilerFilter(&args, &readonly_files_raii, boot_profile_file);
1273
1274 // Compile as a single image for fewer files and slightly less memory overhead.
1275 args.emplace_back("--single-image");
1276
1277 // Set boot-image and expectation of compiling boot classpath extensions.
1278 args.emplace_back("--boot-image=" + GetBootImage());
1279
1280 const std::string dirty_image_objects_file(GetAndroidRoot() + "/etc/dirty-image-objects");
1281 if (OS::FileExists(dirty_image_objects_file.c_str())) {
1282 std::unique_ptr<File> file(OS::OpenFileForReading(dirty_image_objects_file.c_str()));
1283 args.emplace_back(android::base::StringPrintf("--dirty-image-objects-fd=%d", file->Fd()));
1284 readonly_files_raii.push_back(std::move(file));
1285 } else {
1286 LOG(WARNING) << "Missing dirty objects file : " << QuotePath(dirty_image_objects_file);
Orion Hodson3407fb22021-03-17 14:40:51 +00001287 }
1288
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +00001289 // Add boot extensions to compile.
1290 for (const std::string& component : boot_extension_compilable_jars_) {
1291 args.emplace_back("--dex-file=" + component);
1292 std::unique_ptr<File> file(OS::OpenFileForReading(component.c_str()));
1293 args.emplace_back(android::base::StringPrintf("--dex-fd=%d", file->Fd()));
1294 readonly_files_raii.push_back(std::move(file));
1295 }
Orion Hodson947a8502021-03-08 15:40:09 +00001296
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +00001297 args.emplace_back("--runtime-arg");
1298 args.emplace_back(Concatenate({"-Xbootclasspath:", config_.GetDex2oatBootClasspath()}));
1299 auto bcp_jars = android::base::Split(config_.GetDex2oatBootClasspath(), ":");
1300 if (!AddBootClasspathFds(args, readonly_files_raii, bcp_jars)) {
1301 return false;
1302 }
1303
1304 const std::string image_location = GetBootImageExtensionImagePath(/*on_system=*/false, isa);
1305 const OdrArtifacts artifacts = OdrArtifacts::ForBootImageExtension(image_location);
1306 CHECK_EQ(GetApexDataOatFilename(boot_extension_compilable_jars_.front().c_str(), isa),
1307 artifacts.OatPath());
1308
1309 args.emplace_back("--oat-location=" + artifacts.OatPath());
1310 const std::pair<const std::string, const char*> location_kind_pairs[] = {
1311 std::make_pair(artifacts.ImagePath(), "image"),
1312 std::make_pair(artifacts.OatPath(), "oat"),
1313 std::make_pair(artifacts.VdexPath(), "output-vdex")};
1314
1315 std::vector<std::unique_ptr<File>> staging_files;
1316 for (const auto& location_kind_pair : location_kind_pairs) {
1317 auto& [location, kind] = location_kind_pair;
1318 const std::string staging_location = GetStagingLocation(staging_dir, location);
1319 std::unique_ptr<File> staging_file(OS::CreateEmptyFile(staging_location.c_str()));
1320 if (staging_file == nullptr) {
1321 PLOG(ERROR) << "Failed to create " << kind << " file: " << staging_location;
1322 metrics.SetStatus(OdrMetrics::Status::kIoError);
1323 EraseFiles(staging_files);
1324 return false;
Orion Hodson4c3ade62021-02-10 14:07:10 +00001325 }
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +00001326
1327 if (fchmod(staging_file->Fd(), S_IRUSR | S_IWUSR) != 0) {
1328 PLOG(ERROR) << "Could not set file mode on " << QuotePath(staging_location);
1329 metrics.SetStatus(OdrMetrics::Status::kIoError);
1330 EraseFiles(staging_files);
1331 return false;
1332 }
1333
1334 args.emplace_back(android::base::StringPrintf("--%s-fd=%d", kind, staging_file->Fd()));
1335 staging_files.emplace_back(std::move(staging_file));
Orion Hodson4c3ade62021-02-10 14:07:10 +00001336 }
1337
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +00001338 const std::string install_location = android::base::Dirname(image_location);
1339 if (!EnsureDirectoryExists(install_location)) {
1340 metrics.SetStatus(OdrMetrics::Status::kIoError);
1341 return false;
Orion Hodson4c3ade62021-02-10 14:07:10 +00001342 }
1343
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +00001344 if (config_.UseCompilationOs()) {
1345 std::vector<std::string> prefix_args = {
1346 "/apex/com.android.compos/bin/pvm_exec",
1347 "--cid=" + config_.GetCompilationOsAddress(),
1348 "--in-fd=" + JoinFilesAsFDs(readonly_files_raii, ','),
1349 "--out-fd=" + JoinFilesAsFDs(staging_files, ','),
1350 "--",
1351 };
1352 args.insert(args.begin(), prefix_args.begin(), prefix_args.end());
1353 }
1354
1355 const time_t timeout = GetSubprocessTimeout();
1356 const std::string cmd_line = android::base::Join(args, ' ');
1357 LOG(INFO) << "Compiling boot extensions (" << isa << "): " << cmd_line << " [timeout " << timeout
1358 << "s]";
1359 if (config_.GetDryRun()) {
1360 LOG(INFO) << "Compilation skipped (dry-run).";
1361 return true;
1362 }
1363
1364 bool timed_out = false;
Jiakai Zhangb91dad22021-08-16 03:20:07 +00001365 int dex2oat_exit_code = exec_utils_->ExecAndReturnCode(args, timeout, &timed_out, error_msg);
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +00001366 if (dex2oat_exit_code != 0) {
1367 if (timed_out) {
1368 metrics.SetStatus(OdrMetrics::Status::kTimeLimitExceeded);
Orion Hodson4c3ade62021-02-10 14:07:10 +00001369 } else {
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +00001370 metrics.SetStatus(OdrMetrics::Status::kDex2OatError);
Orion Hodson4c3ade62021-02-10 14:07:10 +00001371 }
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +00001372 EraseFiles(staging_files);
1373 return false;
Orion Hodson4c3ade62021-02-10 14:07:10 +00001374 }
1375
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +00001376 if (!MoveOrEraseFiles(staging_files, install_location)) {
1377 metrics.SetStatus(OdrMetrics::Status::kInstallFailed);
1378 return false;
Orion Hodson4c3ade62021-02-10 14:07:10 +00001379 }
1380
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +00001381 *dex2oat_invocation_count = *dex2oat_invocation_count + 1;
1382 ReportNextBootAnimationProgress(*dex2oat_invocation_count);
Orion Hodson4c3ade62021-02-10 14:07:10 +00001383
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +00001384 return true;
1385}
Orion Hodson4c3ade62021-02-10 14:07:10 +00001386
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +00001387WARN_UNUSED bool OnDeviceRefresh::CompileSystemServerArtifacts(const std::string& staging_dir,
1388 OdrMetrics& metrics,
1389 uint32_t* dex2oat_invocation_count,
1390 std::string* error_msg) const {
1391 ScopedOdrCompilationTimer compilation_timer(metrics);
1392 std::vector<std::string> classloader_context;
Victor Hsiehb3a4e012021-06-14 12:48:10 -07001393
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +00001394 const std::string dex2oat = config_.GetDex2Oat();
1395 const InstructionSet isa = config_.GetSystemServerIsa();
1396 for (const std::string& jar : systemserver_compilable_jars_) {
1397 std::vector<std::unique_ptr<File>> readonly_files_raii;
Orion Hodson4c3ade62021-02-10 14:07:10 +00001398 std::vector<std::string> args;
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +00001399 args.emplace_back(dex2oat);
1400 args.emplace_back("--dex-file=" + jar);
1401
1402 std::unique_ptr<File> dex_file(OS::OpenFileForReading(jar.c_str()));
1403 args.emplace_back(android::base::StringPrintf("--dex-fd=%d", dex_file->Fd()));
1404 readonly_files_raii.push_back(std::move(dex_file));
Orion Hodson4c3ade62021-02-10 14:07:10 +00001405
Orion Hodson71b2cb52021-06-16 20:08:16 +01001406 AddDex2OatCommonOptions(&args);
1407 AddDex2OatConcurrencyArguments(&args);
1408 AddDex2OatDebugInfo(&args);
1409 AddDex2OatInstructionSet(&args, isa);
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +00001410 const std::string jar_name(android::base::Basename(jar));
1411 const std::string profile = Concatenate({GetAndroidRoot(), "/framework/", jar_name, ".prof"});
1412 std::string compiler_filter =
1413 android::base::GetProperty("dalvik.vm.systemservercompilerfilter", "speed");
1414 if (compiler_filter == "speed-profile") {
1415 AddDex2OatProfileAndCompilerFilter(&args, &readonly_files_raii, profile);
Orion Hodson4c3ade62021-02-10 14:07:10 +00001416 } else {
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +00001417 args.emplace_back("--compiler-filter=" + compiler_filter);
Orion Hodson4c3ade62021-02-10 14:07:10 +00001418 }
1419
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +00001420 const std::string image_location = GetSystemServerImagePath(/*on_system=*/false, jar);
1421 const std::string install_location = android::base::Dirname(image_location);
1422 if (classloader_context.empty()) {
1423 // All images are in the same directory, we only need to check on the first iteration.
1424 if (!EnsureDirectoryExists(install_location)) {
1425 metrics.SetStatus(OdrMetrics::Status::kIoError);
1426 return false;
1427 }
Orion Hodson4c3ade62021-02-10 14:07:10 +00001428 }
1429
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +00001430 OdrArtifacts artifacts = OdrArtifacts::ForSystemServer(image_location);
1431 CHECK_EQ(artifacts.OatPath(), GetApexDataOdexFilename(jar.c_str(), isa));
Orion Hodson4c3ade62021-02-10 14:07:10 +00001432
Orion Hodson4c3ade62021-02-10 14:07:10 +00001433 const std::pair<const std::string, const char*> location_kind_pairs[] = {
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +00001434 std::make_pair(artifacts.ImagePath(), "app-image"),
Orion Hodson4c3ade62021-02-10 14:07:10 +00001435 std::make_pair(artifacts.OatPath(), "oat"),
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +00001436 std::make_pair(artifacts.VdexPath(), "output-vdex")};
Orion Hodson4c3ade62021-02-10 14:07:10 +00001437
1438 std::vector<std::unique_ptr<File>> staging_files;
1439 for (const auto& location_kind_pair : location_kind_pairs) {
1440 auto& [location, kind] = location_kind_pair;
1441 const std::string staging_location = GetStagingLocation(staging_dir, location);
1442 std::unique_ptr<File> staging_file(OS::CreateEmptyFile(staging_location.c_str()));
1443 if (staging_file == nullptr) {
1444 PLOG(ERROR) << "Failed to create " << kind << " file: " << staging_location;
Orion Hodson957fb152021-04-08 07:52:15 +01001445 metrics.SetStatus(OdrMetrics::Status::kIoError);
Orion Hodson4c3ade62021-02-10 14:07:10 +00001446 EraseFiles(staging_files);
1447 return false;
1448 }
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +00001449 args.emplace_back(android::base::StringPrintf("--%s-fd=%d", kind, staging_file->Fd()));
1450 staging_files.emplace_back(std::move(staging_file));
1451 }
1452 args.emplace_back("--oat-location=" + artifacts.OatPath());
Orion Hodson8f198672021-02-27 22:23:18 +00001453
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +00001454 if (!config_.GetUpdatableBcpPackagesFile().empty()) {
1455 const std::string& bcp_packages = config_.GetUpdatableBcpPackagesFile();
1456 if (!OS::FileExists(bcp_packages.c_str())) {
1457 *error_msg = "Cannot compile system_server JARs: missing " + QuotePath(bcp_packages);
Orion Hodson957fb152021-04-08 07:52:15 +01001458 metrics.SetStatus(OdrMetrics::Status::kIoError);
Orion Hodson8f198672021-02-27 22:23:18 +00001459 EraseFiles(staging_files);
1460 return false;
1461 }
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +00001462 std::unique_ptr<File> file(OS::OpenFileForReading(bcp_packages.c_str()));
1463 args.emplace_back(android::base::StringPrintf("--updatable-bcp-packages-fd=%d", file->Fd()));
1464 readonly_files_raii.push_back(std::move(file));
Orion Hodson4c3ade62021-02-10 14:07:10 +00001465 }
1466
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +00001467 args.emplace_back("--runtime-arg");
1468 args.emplace_back(Concatenate({"-Xbootclasspath:", config_.GetBootClasspath()}));
1469 auto bcp_jars = android::base::Split(config_.GetBootClasspath(), ":");
1470 if (!AddBootClasspathFds(args, readonly_files_raii, bcp_jars)) {
Orion Hodson3407fb22021-03-17 14:40:51 +00001471 return false;
1472 }
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +00001473 AddCompiledBootClasspathFdsIfAny(args, readonly_files_raii, bcp_jars, isa);
1474
1475 const std::string context_path = android::base::Join(classloader_context, ':');
1476 args.emplace_back(Concatenate({"--class-loader-context=PCL[", context_path, "]"}));
1477 if (!classloader_context.empty()) {
1478 std::vector<int> fds;
1479 for (const std::string& path : classloader_context) {
1480 std::unique_ptr<File> file(OS::OpenFileForReading(path.c_str()));
1481 if (!file->IsValid()) {
1482 PLOG(ERROR) << "Failed to open classloader context " << path;
1483 metrics.SetStatus(OdrMetrics::Status::kIoError);
1484 return false;
1485 }
1486 fds.emplace_back(file->Fd());
1487 readonly_files_raii.emplace_back(std::move(file));
1488 }
1489 const std::string context_fds = android::base::Join(fds, ':');
1490 args.emplace_back(Concatenate({"--class-loader-context-fds=", context_fds}));
1491 }
1492 const std::string extension_image = GetBootImageExtensionImage(/*on_system=*/false);
1493 args.emplace_back(Concatenate({"--boot-image=", GetBootImage(), ":", extension_image}));
Orion Hodson4c3ade62021-02-10 14:07:10 +00001494
Victor Hsiehb3a4e012021-06-14 12:48:10 -07001495 if (config_.UseCompilationOs()) {
1496 std::vector<std::string> prefix_args = {
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +00001497 "/apex/com.android.compos/bin/pvm_exec",
1498 "--cid=" + config_.GetCompilationOsAddress(),
1499 "--in-fd=" + JoinFilesAsFDs(readonly_files_raii, ','),
1500 "--out-fd=" + JoinFilesAsFDs(staging_files, ','),
1501 "--",
Victor Hsiehb3a4e012021-06-14 12:48:10 -07001502 };
1503 args.insert(args.begin(), prefix_args.begin(), prefix_args.end());
1504 }
1505
Orion Hodson4c3ade62021-02-10 14:07:10 +00001506 const time_t timeout = GetSubprocessTimeout();
1507 const std::string cmd_line = android::base::Join(args, ' ');
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +00001508 LOG(INFO) << "Compiling " << jar << ": " << cmd_line << " [timeout " << timeout << "s]";
Orion Hodson4c3ade62021-02-10 14:07:10 +00001509 if (config_.GetDryRun()) {
1510 LOG(INFO) << "Compilation skipped (dry-run).";
1511 return true;
1512 }
1513
1514 bool timed_out = false;
Jiakai Zhangb91dad22021-08-16 03:20:07 +00001515 int dex2oat_exit_code = exec_utils_->ExecAndReturnCode(args, timeout, &timed_out, error_msg);
Orion Hodson957fb152021-04-08 07:52:15 +01001516 if (dex2oat_exit_code != 0) {
Orion Hodson4c3ade62021-02-10 14:07:10 +00001517 if (timed_out) {
Orion Hodson957fb152021-04-08 07:52:15 +01001518 metrics.SetStatus(OdrMetrics::Status::kTimeLimitExceeded);
1519 } else {
1520 metrics.SetStatus(OdrMetrics::Status::kDex2OatError);
Orion Hodson4c3ade62021-02-10 14:07:10 +00001521 }
1522 EraseFiles(staging_files);
1523 return false;
1524 }
1525
1526 if (!MoveOrEraseFiles(staging_files, install_location)) {
Orion Hodson957fb152021-04-08 07:52:15 +01001527 metrics.SetStatus(OdrMetrics::Status::kInstallFailed);
Orion Hodson4c3ade62021-02-10 14:07:10 +00001528 return false;
1529 }
1530
Nicolas Geoffray5db2fd02021-04-16 15:07:56 +01001531 *dex2oat_invocation_count = *dex2oat_invocation_count + 1;
1532 ReportNextBootAnimationProgress(*dex2oat_invocation_count);
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +00001533 classloader_context.emplace_back(jar);
Orion Hodson4c3ade62021-02-10 14:07:10 +00001534 }
1535
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +00001536 return true;
1537}
Orion Hodson4c3ade62021-02-10 14:07:10 +00001538
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +00001539WARN_UNUSED ExitCode
1540OnDeviceRefresh::Compile(OdrMetrics& metrics,
1541 const std::vector<InstructionSet>& compile_boot_extensions,
1542 bool compile_system_server) const {
1543 const char* staging_dir = nullptr;
1544 metrics.SetStage(OdrMetrics::Stage::kPreparation);
Orion Hodson4c3ade62021-02-10 14:07:10 +00001545
Jiakai Zhangb91dad22021-08-16 03:20:07 +00001546 if (!config_.GetStagingDir().empty()) {
1547 staging_dir = config_.GetStagingDir().c_str();
1548 } else {
1549 // Create staging area and assign label for generating compilation artifacts.
1550 if (PaletteCreateOdrefreshStagingDirectory(&staging_dir) != PALETTE_STATUS_OK) {
1551 metrics.SetStatus(OdrMetrics::Status::kStagingFailed);
1552 return ExitCode::kCleanupFailed;
1553 }
Orion Hodson4c3ade62021-02-10 14:07:10 +00001554 }
1555
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +00001556 // Emit cache info before compiling. This can be used to throttle compilation attempts later.
1557 WriteCacheInfo();
Nicolas Geoffray5db2fd02021-04-16 15:07:56 +01001558
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +00001559 std::string error_msg;
Orion Hodson263c39e2021-05-07 10:17:14 +01001560
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +00001561 uint32_t dex2oat_invocation_count = 0;
1562 ReportNextBootAnimationProgress(dex2oat_invocation_count);
1563
1564 const auto& bcp_instruction_sets = config_.GetBootExtensionIsas();
1565 DCHECK(!bcp_instruction_sets.empty() && bcp_instruction_sets.size() <= 2);
1566 for (const InstructionSet isa : compile_boot_extensions) {
1567 auto stage = (isa == bcp_instruction_sets.front()) ? OdrMetrics::Stage::kPrimaryBootClasspath :
1568 OdrMetrics::Stage::kSecondaryBootClasspath;
1569 metrics.SetStage(stage);
1570 if (!CheckCompilationSpace()) {
1571 metrics.SetStatus(OdrMetrics::Status::kNoSpace);
1572 // Return kOkay so odsign will keep and sign whatever we have been able to compile.
1573 return ExitCode::kOkay;
Orion Hodson263c39e2021-05-07 10:17:14 +01001574 }
1575
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +00001576 if (!CompileBootExtensionArtifacts(
1577 isa, staging_dir, metrics, &dex2oat_invocation_count, &error_msg)) {
1578 LOG(ERROR) << "Compilation of BCP failed: " << error_msg;
1579 if (!config_.GetDryRun() && !RemoveDirectory(staging_dir)) {
1580 return ExitCode::kCleanupFailed;
Jiakai Zhang7de49d82021-07-14 11:09:49 +08001581 }
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +00001582 return ExitCode::kCompilationFailed;
Orion Hodson4c3ade62021-02-10 14:07:10 +00001583 }
1584 }
1585
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +00001586 if (compile_system_server) {
1587 metrics.SetStage(OdrMetrics::Stage::kSystemServerClasspath);
1588
1589 if (!CheckCompilationSpace()) {
1590 metrics.SetStatus(OdrMetrics::Status::kNoSpace);
1591 // Return kOkay so odsign will keep and sign whatever we have been able to compile.
1592 return ExitCode::kOkay;
Orion Hodson4c3ade62021-02-10 14:07:10 +00001593 }
1594
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +00001595 if (!CompileSystemServerArtifacts(
1596 staging_dir, metrics, &dex2oat_invocation_count, &error_msg)) {
1597 LOG(ERROR) << "Compilation of system_server failed: " << error_msg;
1598 if (!config_.GetDryRun() && !RemoveDirectory(staging_dir)) {
1599 return ExitCode::kCleanupFailed;
Orion Hodson4c3ade62021-02-10 14:07:10 +00001600 }
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +00001601 return ExitCode::kCompilationFailed;
Orion Hodson4c3ade62021-02-10 14:07:10 +00001602 }
Orion Hodson4c3ade62021-02-10 14:07:10 +00001603 }
1604
Jiakai Zhang3ba3edf2021-08-11 08:25:40 +00001605 metrics.SetStage(OdrMetrics::Stage::kComplete);
1606 return ExitCode::kCompilationSuccess;
1607}
Orion Hodson4c3ade62021-02-10 14:07:10 +00001608
1609} // namespace odrefresh
1610} // namespace art