1 /*
2 * Copyright (C) 2014 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 "oat_file_assistant.h"
18
19 #include <sys/stat.h>
20
21 #include <memory>
22 #include <optional>
23 #include <sstream>
24 #include <vector>
25
26 #include "android-base/file.h"
27 #include "android-base/logging.h"
28 #include "android-base/properties.h"
29 #include "android-base/stringprintf.h"
30 #include "android-base/strings.h"
31 #include "arch/instruction_set.h"
32 #include "base/array_ref.h"
33 #include "base/compiler_filter.h"
34 #include "base/file_utils.h"
35 #include "base/globals.h"
36 #include "base/logging.h" // For VLOG.
37 #include "base/macros.h"
38 #include "base/os.h"
39 #include "base/stl_util.h"
40 #include "base/systrace.h"
41 #include "base/utils.h"
42 #include "base/zip_archive.h"
43 #include "class_linker.h"
44 #include "class_loader_context.h"
45 #include "dex/art_dex_file_loader.h"
46 #include "dex/dex_file_loader.h"
47 #include "exec_utils.h"
48 #include "gc/heap.h"
49 #include "gc/space/image_space.h"
50 #include "image.h"
51 #include "oat.h"
52 #include "oat_file_assistant_context.h"
53 #include "runtime.h"
54 #include "scoped_thread_state_change-inl.h"
55 #include "vdex_file.h"
56 #include "zlib.h"
57
58 namespace art HIDDEN {
59
60 using ::android::base::ConsumePrefix;
61 using ::android::base::StringPrintf;
62
63 static constexpr const char* kAnonymousDexPrefix = "Anonymous-DexFile@";
64 static constexpr const char* kVdexExtension = ".vdex";
65 static constexpr const char* kDmExtension = ".dm";
66
operator <<(std::ostream & stream,const OatFileAssistant::OatStatus status)67 std::ostream& operator<<(std::ostream& stream, const OatFileAssistant::OatStatus status) {
68 switch (status) {
69 case OatFileAssistant::kOatCannotOpen:
70 stream << "kOatCannotOpen";
71 break;
72 case OatFileAssistant::kOatDexOutOfDate:
73 stream << "kOatDexOutOfDate";
74 break;
75 case OatFileAssistant::kOatBootImageOutOfDate:
76 stream << "kOatBootImageOutOfDate";
77 break;
78 case OatFileAssistant::kOatUpToDate:
79 stream << "kOatUpToDate";
80 break;
81 case OatFileAssistant::kOatContextOutOfDate:
82 stream << "kOaContextOutOfDate";
83 break;
84 }
85
86 return stream;
87 }
88
OatFileAssistant(const char * dex_location,const InstructionSet isa,ClassLoaderContext * context,bool load_executable,bool only_load_trusted_executable,OatFileAssistantContext * ofa_context)89 OatFileAssistant::OatFileAssistant(const char* dex_location,
90 const InstructionSet isa,
91 ClassLoaderContext* context,
92 bool load_executable,
93 bool only_load_trusted_executable,
94 OatFileAssistantContext* ofa_context)
95 : OatFileAssistant(dex_location,
96 isa,
97 context,
98 load_executable,
99 only_load_trusted_executable,
100 ofa_context,
101 /*vdex_fd=*/-1,
102 /*oat_fd=*/-1,
103 /*zip_fd=*/-1) {}
104
OatFileAssistant(const char * dex_location,const InstructionSet isa,ClassLoaderContext * context,bool load_executable,bool only_load_trusted_executable,OatFileAssistantContext * ofa_context,int vdex_fd,int oat_fd,int zip_fd)105 OatFileAssistant::OatFileAssistant(const char* dex_location,
106 const InstructionSet isa,
107 ClassLoaderContext* context,
108 bool load_executable,
109 bool only_load_trusted_executable,
110 OatFileAssistantContext* ofa_context,
111 int vdex_fd,
112 int oat_fd,
113 int zip_fd)
114 : context_(context),
115 isa_(isa),
116 load_executable_(load_executable),
117 only_load_trusted_executable_(only_load_trusted_executable),
118 odex_(this, /*is_oat_location=*/false),
119 oat_(this, /*is_oat_location=*/true),
120 vdex_for_odex_(this, /*is_oat_location=*/false),
121 vdex_for_oat_(this, /*is_oat_location=*/true),
122 dm_for_odex_(this, /*is_oat_location=*/false),
123 dm_for_oat_(this, /*is_oat_location=*/true),
124 zip_fd_(zip_fd) {
125 CHECK(dex_location != nullptr) << "OatFileAssistant: null dex location";
126 CHECK_IMPLIES(load_executable, context != nullptr) << "Loading executable without a context";
127
128 if (zip_fd < 0) {
129 CHECK_LE(oat_fd, 0) << "zip_fd must be provided with valid oat_fd. zip_fd=" << zip_fd
130 << " oat_fd=" << oat_fd;
131 CHECK_LE(vdex_fd, 0) << "zip_fd must be provided with valid vdex_fd. zip_fd=" << zip_fd
132 << " vdex_fd=" << vdex_fd;
133 CHECK(!UseFdToReadFiles());
134 } else {
135 CHECK(UseFdToReadFiles());
136 }
137
138 dex_location_.assign(dex_location);
139
140 Runtime* runtime = Runtime::Current();
141
142 if (load_executable_ && runtime == nullptr) {
143 LOG(WARNING) << "OatFileAssistant: Load executable specified, "
144 << "but no active runtime is found. Will not attempt to load executable.";
145 load_executable_ = false;
146 }
147
148 if (load_executable_ && isa != kRuntimeISA) {
149 LOG(WARNING) << "OatFileAssistant: Load executable specified, "
150 << "but isa is not kRuntimeISA. Will not attempt to load executable.";
151 load_executable_ = false;
152 }
153
154 if (ofa_context == nullptr) {
155 CHECK(runtime != nullptr) << "runtime_options is not provided, and no active runtime is found.";
156 ofa_context_ = std::make_unique<OatFileAssistantContext>(runtime);
157 } else {
158 ofa_context_ = ofa_context;
159 }
160
161 if (runtime == nullptr) {
162 // We need `MemMap` for mapping files. We don't have to initialize it when there is a runtime
163 // because the runtime initializes it.
164 MemMap::Init();
165 }
166
167 // Get the odex filename.
168 std::string error_msg;
169 std::string odex_file_name;
170 if (DexLocationToOdexFilename(dex_location_, isa_, &odex_file_name, &error_msg)) {
171 odex_.Reset(odex_file_name, UseFdToReadFiles(), zip_fd, vdex_fd, oat_fd);
172 std::string vdex_file_name = GetVdexFilename(odex_file_name);
173 // We dup FDs as the odex_ will claim ownership.
174 vdex_for_odex_.Reset(vdex_file_name,
175 UseFdToReadFiles(),
176 DupCloexec(zip_fd),
177 DupCloexec(vdex_fd),
178 DupCloexec(oat_fd));
179
180 std::string dm_file_name = GetDmFilename(dex_location_);
181 dm_for_odex_.Reset(dm_file_name,
182 UseFdToReadFiles(),
183 DupCloexec(zip_fd),
184 DupCloexec(vdex_fd),
185 DupCloexec(oat_fd));
186 } else {
187 LOG(WARNING) << "Failed to determine odex file name: " << error_msg;
188 }
189
190 if (!UseFdToReadFiles()) {
191 // Get the oat filename.
192 std::string oat_file_name;
193 if (DexLocationToOatFilename(dex_location_,
194 isa_,
195 GetRuntimeOptions().deny_art_apex_data_files,
196 &oat_file_name,
197 &error_msg)) {
198 oat_.Reset(oat_file_name, /*use_fd=*/false);
199 std::string vdex_file_name = GetVdexFilename(oat_file_name);
200 vdex_for_oat_.Reset(vdex_file_name, UseFdToReadFiles(), zip_fd, vdex_fd, oat_fd);
201 std::string dm_file_name = GetDmFilename(dex_location);
202 dm_for_oat_.Reset(dm_file_name, UseFdToReadFiles(), zip_fd, vdex_fd, oat_fd);
203 } else if (kIsTargetAndroid) {
204 // No need to warn on host. We are probably in oatdump, where we only need OatFileAssistant to
205 // validate BCP checksums.
206 LOG(WARNING) << "Failed to determine oat file name for dex location " << dex_location_ << ": "
207 << error_msg;
208 }
209 }
210
211 // Check if the dex directory is writable.
212 // This will be needed in most uses of OatFileAssistant and so it's OK to
213 // compute it eagerly. (the only use which will not make use of it is
214 // OatFileAssistant::GetStatusDump())
215 size_t pos = dex_location_.rfind('/');
216 if (pos == std::string::npos) {
217 LOG(WARNING) << "Failed to determine dex file parent directory: " << dex_location_;
218 } else if (!UseFdToReadFiles()) {
219 // We cannot test for parent access when using file descriptors. That's ok
220 // because in this case we will always pick the odex file anyway.
221 std::string parent = dex_location_.substr(0, pos);
222 if (access(parent.c_str(), W_OK) == 0) {
223 dex_parent_writable_ = true;
224 } else {
225 VLOG(oat) << "Dex parent of " << dex_location_ << " is not writable: " << strerror(errno);
226 }
227 }
228 }
229
Create(const std::string & filename,const std::string & isa_str,const std::optional<std::string> & context_str,bool load_executable,bool only_load_trusted_executable,OatFileAssistantContext * ofa_context,std::unique_ptr<ClassLoaderContext> * context,std::string * error_msg)230 std::unique_ptr<OatFileAssistant> OatFileAssistant::Create(
231 const std::string& filename,
232 const std::string& isa_str,
233 const std::optional<std::string>& context_str,
234 bool load_executable,
235 bool only_load_trusted_executable,
236 OatFileAssistantContext* ofa_context,
237 /*out*/ std::unique_ptr<ClassLoaderContext>* context,
238 /*out*/ std::string* error_msg) {
239 InstructionSet isa = GetInstructionSetFromString(isa_str.c_str());
240 if (isa == InstructionSet::kNone) {
241 *error_msg = StringPrintf("Instruction set '%s' is invalid", isa_str.c_str());
242 return nullptr;
243 }
244
245 std::unique_ptr<ClassLoaderContext> tmp_context = nullptr;
246 if (context_str.has_value()) {
247 tmp_context = ClassLoaderContext::Create(context_str.value());
248 if (tmp_context == nullptr) {
249 *error_msg = StringPrintf("Class loader context '%s' is invalid", context_str->c_str());
250 return nullptr;
251 }
252
253 if (!tmp_context->OpenDexFiles(android::base::Dirname(filename),
254 /*context_fds=*/{},
255 /*only_read_checksums=*/true)) {
256 *error_msg =
257 StringPrintf("Failed to load class loader context files for '%s' with context '%s'",
258 filename.c_str(),
259 context_str->c_str());
260 return nullptr;
261 }
262 }
263
264 auto assistant = std::make_unique<OatFileAssistant>(filename.c_str(),
265 isa,
266 tmp_context.get(),
267 load_executable,
268 only_load_trusted_executable,
269 ofa_context);
270
271 *context = std::move(tmp_context);
272 return assistant;
273 }
274
UseFdToReadFiles()275 bool OatFileAssistant::UseFdToReadFiles() { return zip_fd_ >= 0; }
276
IsInBootClassPath()277 bool OatFileAssistant::IsInBootClassPath() {
278 // Note: We check the current boot class path, regardless of the ISA
279 // specified by the user. This is okay, because the boot class path should
280 // be the same for all ISAs.
281 // TODO: Can we verify the boot class path is the same for all ISAs?
282 for (const std::string& boot_class_path_location :
283 GetRuntimeOptions().boot_class_path_locations) {
284 if (boot_class_path_location == dex_location_) {
285 VLOG(oat) << "Dex location " << dex_location_ << " is in boot class path";
286 return true;
287 }
288 }
289 return false;
290 }
291
GetDexOptTrigger(CompilerFilter::Filter target_compiler_filter,bool profile_changed,bool downgrade)292 OatFileAssistant::DexOptTrigger OatFileAssistant::GetDexOptTrigger(
293 CompilerFilter::Filter target_compiler_filter, bool profile_changed, bool downgrade) {
294 if (downgrade) {
295 // The caller's intention is to downgrade the compiler filter. We should only re-compile if the
296 // target compiler filter is worse than the current one.
297 return DexOptTrigger{.targetFilterIsWorse = true};
298 }
299
300 // This is the usual case. The caller's intention is to see if a better oat file can be generated.
301 DexOptTrigger dexopt_trigger{
302 .targetFilterIsBetter = true, .primaryBootImageBecomesUsable = true, .needExtraction = true};
303 if (profile_changed && CompilerFilter::DependsOnProfile(target_compiler_filter)) {
304 // Since the profile has been changed, we should re-compile even if the compilation does not
305 // make the compiler filter better.
306 dexopt_trigger.targetFilterIsSame = true;
307 }
308 return dexopt_trigger;
309 }
310
GetDexOptNeeded(CompilerFilter::Filter target_compiler_filter,bool profile_changed,bool downgrade)311 int OatFileAssistant::GetDexOptNeeded(CompilerFilter::Filter target_compiler_filter,
312 bool profile_changed,
313 bool downgrade) {
314 OatFileInfo& info = GetBestInfo();
315 if (info.CheckDisableCompactDex()) { // TODO(b/256664509): Clean this up.
316 VLOG(oat) << "Should recompile: disable cdex";
317 return kDex2OatFromScratch;
318 }
319 DexOptNeeded dexopt_needed = info.GetDexOptNeeded(
320 target_compiler_filter, GetDexOptTrigger(target_compiler_filter, profile_changed, downgrade));
321 if (dexopt_needed != kNoDexOptNeeded && (&info == &dm_for_oat_ || &info == &dm_for_odex_)) {
322 // The usable vdex file is in the DM file. This information cannot be encoded in the integer.
323 // Return kDex2OatFromScratch so that neither the vdex in the "oat" location nor the vdex in the
324 // "odex" location will be picked by installd.
325 return kDex2OatFromScratch;
326 }
327 if (info.IsOatLocation() || dexopt_needed == kDex2OatFromScratch) {
328 return dexopt_needed;
329 }
330 return -dexopt_needed;
331 }
332
GetDexOptNeeded(CompilerFilter::Filter target_compiler_filter,DexOptTrigger dexopt_trigger,DexOptStatus * dexopt_status)333 bool OatFileAssistant::GetDexOptNeeded(CompilerFilter::Filter target_compiler_filter,
334 DexOptTrigger dexopt_trigger,
335 /*out*/ DexOptStatus* dexopt_status) {
336 OatFileInfo& info = GetBestInfo();
337 if (info.CheckDisableCompactDex()) { // TODO(b/256664509): Clean this up.
338 dexopt_status->location_ = kLocationNoneOrError;
339 return true;
340 }
341 DexOptNeeded dexopt_needed = info.GetDexOptNeeded(target_compiler_filter, dexopt_trigger);
342 dexopt_status->location_ = GetLocation(info);
343 return dexopt_needed != kNoDexOptNeeded;
344 }
345
IsUpToDate()346 bool OatFileAssistant::IsUpToDate() { return GetBestInfo().Status() == kOatUpToDate; }
347
GetBestOatFile()348 std::unique_ptr<OatFile> OatFileAssistant::GetBestOatFile() {
349 return GetBestInfo().ReleaseFileForUse();
350 }
351
GetStatusDump()352 std::string OatFileAssistant::GetStatusDump() {
353 std::ostringstream status;
354 bool oat_file_exists = false;
355 bool odex_file_exists = false;
356 if (oat_.Status() != kOatCannotOpen) {
357 // If we can open the file, Filename should not return null.
358 CHECK(oat_.Filename() != nullptr);
359
360 oat_file_exists = true;
361 status << *oat_.Filename() << "[status=" << oat_.Status() << ", ";
362 const OatFile* file = oat_.GetFile();
363 if (file == nullptr) {
364 // If the file is null even though the status is not kOatCannotOpen, it
365 // means we must have a vdex file with no corresponding oat file. In
366 // this case we cannot determine the compilation filter. Indicate that
367 // we have only the vdex file instead.
368 status << "vdex-only";
369 } else {
370 status << "compilation_filter=" << CompilerFilter::NameOfFilter(file->GetCompilerFilter());
371 }
372 }
373
374 if (odex_.Status() != kOatCannotOpen) {
375 // If we can open the file, Filename should not return null.
376 CHECK(odex_.Filename() != nullptr);
377
378 odex_file_exists = true;
379 if (oat_file_exists) {
380 status << "] ";
381 }
382 status << *odex_.Filename() << "[status=" << odex_.Status() << ", ";
383 const OatFile* file = odex_.GetFile();
384 if (file == nullptr) {
385 status << "vdex-only";
386 } else {
387 status << "compilation_filter=" << CompilerFilter::NameOfFilter(file->GetCompilerFilter());
388 }
389 }
390
391 if (!oat_file_exists && !odex_file_exists) {
392 status << "invalid[";
393 }
394
395 status << "]";
396 return status.str();
397 }
398
LoadDexFiles(const OatFile & oat_file,const char * dex_location)399 std::vector<std::unique_ptr<const DexFile>> OatFileAssistant::LoadDexFiles(
400 const OatFile& oat_file, const char* dex_location) {
401 std::vector<std::unique_ptr<const DexFile>> dex_files;
402 if (LoadDexFiles(oat_file, dex_location, &dex_files)) {
403 return dex_files;
404 } else {
405 return std::vector<std::unique_ptr<const DexFile>>();
406 }
407 }
408
LoadDexFiles(const OatFile & oat_file,const std::string & dex_location,std::vector<std::unique_ptr<const DexFile>> * out_dex_files)409 bool OatFileAssistant::LoadDexFiles(const OatFile& oat_file,
410 const std::string& dex_location,
411 std::vector<std::unique_ptr<const DexFile>>* out_dex_files) {
412 // Load the main dex file.
413 std::string error_msg;
414 const OatDexFile* oat_dex_file = oat_file.GetOatDexFile(dex_location.c_str(), &error_msg);
415 if (oat_dex_file == nullptr) {
416 LOG(WARNING) << error_msg;
417 return false;
418 }
419
420 std::unique_ptr<const DexFile> dex_file = oat_dex_file->OpenDexFile(&error_msg);
421 if (dex_file.get() == nullptr) {
422 LOG(WARNING) << "Failed to open dex file from oat dex file: " << error_msg;
423 return false;
424 }
425 out_dex_files->push_back(std::move(dex_file));
426
427 // Load the rest of the multidex entries
428 for (size_t i = 1;; i++) {
429 std::string multidex_dex_location = DexFileLoader::GetMultiDexLocation(i, dex_location.c_str());
430 oat_dex_file = oat_file.GetOatDexFile(multidex_dex_location.c_str());
431 if (oat_dex_file == nullptr) {
432 // There are no more multidex entries to load.
433 break;
434 }
435
436 dex_file = oat_dex_file->OpenDexFile(&error_msg);
437 if (dex_file.get() == nullptr) {
438 LOG(WARNING) << "Failed to open dex file from oat dex file: " << error_msg;
439 return false;
440 }
441 out_dex_files->push_back(std::move(dex_file));
442 }
443 return true;
444 }
445
HasDexFiles(std::string * error_msg)446 std::optional<bool> OatFileAssistant::HasDexFiles(std::string* error_msg) {
447 ScopedTrace trace("HasDexFiles");
448 std::optional<std::uint32_t> checksum;
449 if (!GetRequiredDexChecksum(&checksum, error_msg)) {
450 return std::nullopt;
451 }
452 return checksum.has_value();
453 }
454
OdexFileStatus()455 OatFileAssistant::OatStatus OatFileAssistant::OdexFileStatus() { return odex_.Status(); }
456
OatFileStatus()457 OatFileAssistant::OatStatus OatFileAssistant::OatFileStatus() { return oat_.Status(); }
458
DexChecksumUpToDate(const OatFile & file,std::string * error_msg)459 bool OatFileAssistant::DexChecksumUpToDate(const OatFile& file, std::string* error_msg) {
460 if (!file.ContainsDexCode()) {
461 // We've already checked during oat file creation that the dex files loaded
462 // from external files have the same checksums as the ones in the vdex file.
463 return true;
464 }
465 ScopedTrace trace("DexChecksumUpToDate");
466 std::optional<std::uint32_t> dex_checksum;
467 if (!GetRequiredDexChecksum(&dex_checksum, error_msg)) {
468 return false;
469 }
470 if (!dex_checksum.has_value()) {
471 LOG(WARNING) << "Required dex checksums not found. Assuming dex checksums are up to date.";
472 return true;
473 }
474
475 std::vector<const OatDexFile*> oat_dex_files;
476 uint32_t number_of_dex_files = file.GetOatHeader().GetDexFileCount();
477 for (uint32_t i = 0; i < number_of_dex_files; i++) {
478 std::string dex = DexFileLoader::GetMultiDexLocation(i, dex_location_.c_str());
479 const OatDexFile* oat_dex_file = file.GetOatDexFile(dex.c_str());
480 if (oat_dex_file == nullptr) {
481 *error_msg = StringPrintf("failed to find %s in %s", dex.c_str(), file.GetLocation().c_str());
482 return false;
483 }
484 oat_dex_files.push_back(oat_dex_file);
485 }
486 uint32_t oat_checksum = DexFileLoader::GetMultiDexChecksum(oat_dex_files);
487
488 CHECK(dex_checksum.has_value());
489 if (dex_checksum != oat_checksum) {
490 VLOG(oat) << "Checksum does not match: " << std::hex << file.GetLocation() << " ("
491 << oat_checksum << ") vs " << dex_location_ << " (" << *dex_checksum << ")";
492 return false;
493 }
494
495 return true;
496 }
497
GivenOatFileStatus(const OatFile & file)498 OatFileAssistant::OatStatus OatFileAssistant::GivenOatFileStatus(const OatFile& file) {
499 // Verify the ART_USE_READ_BARRIER state.
500 // TODO: Don't fully reject files due to read barrier state. If they contain
501 // compiled code and are otherwise okay, we should return something like
502 // kOatRelocationOutOfDate. If they don't contain compiled code, the read
503 // barrier state doesn't matter.
504 if (file.GetOatHeader().IsConcurrentCopying() != gUseReadBarrier) {
505 return kOatCannotOpen;
506 }
507
508 // Verify the dex checksum.
509 std::string error_msg;
510 if (!DexChecksumUpToDate(file, &error_msg)) {
511 LOG(ERROR) << error_msg;
512 return kOatDexOutOfDate;
513 }
514
515 CompilerFilter::Filter current_compiler_filter = file.GetCompilerFilter();
516
517 // Verify the image checksum
518 if (file.IsBackedByVdexOnly()) {
519 VLOG(oat) << "Image checksum test skipped for vdex file " << file.GetLocation();
520 } else if (CompilerFilter::DependsOnImageChecksum(current_compiler_filter)) {
521 if (!ValidateBootClassPathChecksums(file)) {
522 VLOG(oat) << "Oat image checksum does not match image checksum.";
523 return kOatBootImageOutOfDate;
524 }
525 if (!gc::space::ImageSpace::ValidateApexVersions(
526 file.GetOatHeader(),
527 GetOatFileAssistantContext()->GetApexVersions(),
528 file.GetLocation(),
529 &error_msg)) {
530 VLOG(oat) << error_msg;
531 return kOatBootImageOutOfDate;
532 }
533 } else {
534 VLOG(oat) << "Image checksum test skipped for compiler filter " << current_compiler_filter;
535 }
536
537 // The constraint is only enforced if the zip has uncompressed dex code.
538 if (only_load_trusted_executable_ &&
539 !LocationIsTrusted(file.GetLocation(), !GetRuntimeOptions().deny_art_apex_data_files) &&
540 file.ContainsDexCode() && ZipFileOnlyContainsUncompressedDex()) {
541 LOG(ERROR) << "Not loading " << dex_location_
542 << ": oat file has dex code, but APK has uncompressed dex code";
543 return kOatDexOutOfDate;
544 }
545
546 if (!ClassLoaderContextIsOkay(file)) {
547 return kOatContextOutOfDate;
548 }
549
550 return kOatUpToDate;
551 }
552
AnonymousDexVdexLocation(const std::vector<const DexFile::Header * > & headers,InstructionSet isa,std::string * dex_location,std::string * vdex_filename)553 bool OatFileAssistant::AnonymousDexVdexLocation(const std::vector<const DexFile::Header*>& headers,
554 InstructionSet isa,
555 /* out */ std::string* dex_location,
556 /* out */ std::string* vdex_filename) {
557 // Normally, OatFileAssistant should not assume that there is an active runtime. However, we
558 // reference the runtime here. This is okay because we are in a static function that is unrelated
559 // to other parts of OatFileAssistant.
560 DCHECK(Runtime::Current() != nullptr);
561
562 uint32_t checksum = adler32(0L, Z_NULL, 0);
563 for (const DexFile::Header* header : headers) {
564 checksum = adler32_combine(
565 checksum, header->checksum_, header->file_size_ - DexFile::kNumNonChecksumBytes);
566 }
567
568 const std::string& data_dir = Runtime::Current()->GetProcessDataDirectory();
569 if (data_dir.empty() || Runtime::Current()->IsZygote()) {
570 *dex_location = StringPrintf("%s%u", kAnonymousDexPrefix, checksum);
571 return false;
572 }
573 *dex_location = StringPrintf("%s/%s%u.jar", data_dir.c_str(), kAnonymousDexPrefix, checksum);
574
575 std::string odex_filename;
576 std::string error_msg;
577 if (!DexLocationToOdexFilename(*dex_location, isa, &odex_filename, &error_msg)) {
578 LOG(WARNING) << "Could not get odex filename for " << *dex_location << ": " << error_msg;
579 return false;
580 }
581
582 *vdex_filename = GetVdexFilename(odex_filename);
583 return true;
584 }
585
IsAnonymousVdexBasename(const std::string & basename)586 bool OatFileAssistant::IsAnonymousVdexBasename(const std::string& basename) {
587 DCHECK(basename.find('/') == std::string::npos);
588 // `basename` must have format: <kAnonymousDexPrefix><checksum><kVdexExtension>
589 if (basename.size() < strlen(kAnonymousDexPrefix) + strlen(kVdexExtension) + 1 ||
590 !basename.starts_with(kAnonymousDexPrefix) ||
591 !basename.ends_with(kVdexExtension)) {
592 return false;
593 }
594 // Check that all characters between the prefix and extension are decimal digits.
595 for (size_t i = strlen(kAnonymousDexPrefix); i < basename.size() - strlen(kVdexExtension); ++i) {
596 if (!std::isdigit(basename[i])) {
597 return false;
598 }
599 }
600 return true;
601 }
602
DexLocationToOdexFilename(const std::string & location,InstructionSet isa,std::string * odex_filename,std::string * error_msg)603 bool OatFileAssistant::DexLocationToOdexFilename(const std::string& location,
604 InstructionSet isa,
605 std::string* odex_filename,
606 std::string* error_msg) {
607 CHECK(odex_filename != nullptr);
608 CHECK(error_msg != nullptr);
609
610 // For a DEX file on /apex, check if there is an odex file on /system. If so, and the file exists,
611 // use it.
612 if (LocationIsOnApex(location)) {
613 const std::string system_file = GetSystemOdexFilenameForApex(location, isa);
614 if (OS::FileExists(system_file.c_str(), /*check_file_type=*/true)) {
615 *odex_filename = system_file;
616 return true;
617 } else if (errno != ENOENT) {
618 PLOG(ERROR) << "Could not check odex file " << system_file;
619 }
620 }
621
622 // The odex file name is formed by replacing the dex_location extension with
623 // .odex and inserting an oat/<isa> directory. For example:
624 // location = /foo/bar/baz.jar
625 // odex_location = /foo/bar/oat/<isa>/baz.odex
626
627 // Find the directory portion of the dex location and add the oat/<isa>
628 // directory.
629 size_t pos = location.rfind('/');
630 if (pos == std::string::npos) {
631 *error_msg = "Dex location " + location + " has no directory.";
632 return false;
633 }
634 std::string dir = location.substr(0, pos + 1);
635 // Add the oat directory.
636 dir += "oat";
637
638 // Add the isa directory
639 dir += "/" + std::string(GetInstructionSetString(isa));
640
641 // Get the base part of the file without the extension.
642 std::string file = location.substr(pos + 1);
643 pos = file.rfind('.');
644 std::string base = pos != std::string::npos ? file.substr(0, pos) : file;
645
646 *odex_filename = dir + "/" + base + ".odex";
647 return true;
648 }
649
DexLocationToOatFilename(const std::string & location,InstructionSet isa,std::string * oat_filename,std::string * error_msg)650 bool OatFileAssistant::DexLocationToOatFilename(const std::string& location,
651 InstructionSet isa,
652 std::string* oat_filename,
653 std::string* error_msg) {
654 DCHECK(Runtime::Current() != nullptr);
655 return DexLocationToOatFilename(
656 location, isa, Runtime::Current()->DenyArtApexDataFiles(), oat_filename, error_msg);
657 }
658
DexLocationToOatFilename(const std::string & location,InstructionSet isa,bool deny_art_apex_data_files,std::string * oat_filename,std::string * error_msg)659 bool OatFileAssistant::DexLocationToOatFilename(const std::string& location,
660 InstructionSet isa,
661 bool deny_art_apex_data_files,
662 std::string* oat_filename,
663 std::string* error_msg) {
664 CHECK(oat_filename != nullptr);
665 CHECK(error_msg != nullptr);
666
667 // Check if `location` could have an oat file in the ART APEX data directory. If so, and the
668 // file exists, use it.
669 const std::string apex_data_file = GetApexDataOdexFilename(location, isa);
670 if (!apex_data_file.empty() && !deny_art_apex_data_files) {
671 if (OS::FileExists(apex_data_file.c_str(), /*check_file_type=*/true)) {
672 *oat_filename = apex_data_file;
673 return true;
674 } else if (errno != ENOENT) {
675 PLOG(ERROR) << "Could not check odex file " << apex_data_file;
676 }
677 }
678
679 // If ANDROID_DATA is not set, return false instead of aborting.
680 // This can occur for preopt when using a class loader context.
681 if (GetAndroidDataSafe(error_msg).empty()) {
682 *error_msg = "GetAndroidDataSafe failed: " + *error_msg;
683 return false;
684 }
685
686 std::string dalvik_cache;
687 bool have_android_data = false;
688 bool dalvik_cache_exists = false;
689 bool is_global_cache = false;
690 GetDalvikCache(GetInstructionSetString(isa),
691 /*create_if_absent=*/true,
692 &dalvik_cache,
693 &have_android_data,
694 &dalvik_cache_exists,
695 &is_global_cache);
696 if (!dalvik_cache_exists) {
697 *error_msg = "Dalvik cache directory does not exist";
698 return false;
699 }
700
701 // TODO: The oat file assistant should be the definitive place for
702 // determining the oat file name from the dex location, not
703 // GetDalvikCacheFilename.
704 return GetDalvikCacheFilename(location, dalvik_cache, oat_filename, error_msg);
705 }
706
GetRequiredDexChecksum(std::optional<uint32_t> * checksum,std::string * error)707 bool OatFileAssistant::GetRequiredDexChecksum(std::optional<uint32_t>* checksum,
708 std::string* error) {
709 if (!required_dex_checksums_attempted_) {
710 required_dex_checksums_attempted_ = true;
711
712 File file(zip_fd_, /*check_usage=*/false);
713 ArtDexFileLoader dex_loader(&file, dex_location_);
714 std::optional<uint32_t> checksum2;
715 std::string error2;
716 if (dex_loader.GetMultiDexChecksum(
717 &checksum2, &error2, &zip_file_only_contains_uncompressed_dex_)) {
718 cached_required_dex_checksums_ = checksum2;
719 cached_required_dex_checksums_error_ = std::nullopt;
720 } else {
721 cached_required_dex_checksums_ = std::nullopt;
722 cached_required_dex_checksums_error_ = error2;
723 }
724 file.Release(); // Don't close the file yet (we have only read the checksum).
725 }
726
727 if (cached_required_dex_checksums_error_.has_value()) {
728 *error = cached_required_dex_checksums_error_.value();
729 DCHECK(!error->empty());
730 return false;
731 }
732
733 if (!cached_required_dex_checksums_.has_value()) {
734 // The only valid case here is for APKs without dex files.
735 VLOG(oat) << "No dex file found in " << dex_location_;
736 }
737 *checksum = cached_required_dex_checksums_;
738 return true;
739 }
740
ValidateBootClassPathChecksums(OatFileAssistantContext * ofa_context,InstructionSet isa,std::string_view oat_checksums,std::string_view oat_boot_class_path,std::string * error_msg)741 bool OatFileAssistant::ValidateBootClassPathChecksums(OatFileAssistantContext* ofa_context,
742 InstructionSet isa,
743 std::string_view oat_checksums,
744 std::string_view oat_boot_class_path,
745 /*out*/ std::string* error_msg) {
746 const std::vector<std::string>& bcp_locations =
747 ofa_context->GetRuntimeOptions().boot_class_path_locations;
748
749 if (oat_checksums.empty() || oat_boot_class_path.empty()) {
750 *error_msg = oat_checksums.empty() ? "Empty checksums" : "Empty boot class path";
751 return false;
752 }
753
754 size_t oat_bcp_size = gc::space::ImageSpace::CheckAndCountBCPComponents(
755 oat_boot_class_path, ArrayRef<const std::string>(bcp_locations), error_msg);
756 if (oat_bcp_size == static_cast<size_t>(-1)) {
757 DCHECK(!error_msg->empty());
758 return false;
759 }
760 DCHECK_LE(oat_bcp_size, bcp_locations.size());
761
762 size_t bcp_index = 0;
763 size_t boot_image_index = 0;
764 bool found_d = false;
765
766 while (bcp_index < oat_bcp_size) {
767 static_assert(gc::space::ImageSpace::kImageChecksumPrefix == 'i', "Format prefix check");
768 static_assert(gc::space::ImageSpace::kDexFileChecksumPrefix == 'd', "Format prefix check");
769 if (oat_checksums.starts_with("i") && !found_d) {
770 const std::vector<OatFileAssistantContext::BootImageInfo>& boot_image_info_list =
771 ofa_context->GetBootImageInfoList(isa);
772 if (boot_image_index >= boot_image_info_list.size()) {
773 *error_msg = StringPrintf("Missing boot image for %s, remaining checksums: %s",
774 bcp_locations[bcp_index].c_str(),
775 std::string(oat_checksums).c_str());
776 return false;
777 }
778
779 const OatFileAssistantContext::BootImageInfo& boot_image_info =
780 boot_image_info_list[boot_image_index];
781 if (!ConsumePrefix(&oat_checksums, boot_image_info.checksum)) {
782 *error_msg = StringPrintf("Image checksum mismatch, expected %s to start with %s",
783 std::string(oat_checksums).c_str(),
784 boot_image_info.checksum.c_str());
785 return false;
786 }
787
788 bcp_index += boot_image_info.component_count;
789 boot_image_index++;
790 } else if (oat_checksums.starts_with("d")) {
791 found_d = true;
792 const std::vector<std::string>* bcp_checksums =
793 ofa_context->GetBcpChecksums(bcp_index, error_msg);
794 if (bcp_checksums == nullptr) {
795 return false;
796 }
797 oat_checksums.remove_prefix(1u);
798 for (const std::string& checksum : *bcp_checksums) {
799 if (!ConsumePrefix(&oat_checksums, checksum)) {
800 *error_msg = StringPrintf(
801 "Dex checksum mismatch for bootclasspath file %s, expected %s to start with %s",
802 bcp_locations[bcp_index].c_str(),
803 std::string(oat_checksums).c_str(),
804 checksum.c_str());
805 return false;
806 }
807 }
808
809 bcp_index++;
810 } else {
811 *error_msg = StringPrintf("Unexpected checksums, expected %s to start with %s",
812 std::string(oat_checksums).c_str(),
813 found_d ? "'d'" : "'i' or 'd'");
814 return false;
815 }
816
817 if (bcp_index < oat_bcp_size) {
818 if (!ConsumePrefix(&oat_checksums, ":")) {
819 if (oat_checksums.empty()) {
820 *error_msg =
821 StringPrintf("Checksum too short, missing %zu components", oat_bcp_size - bcp_index);
822 } else {
823 *error_msg = StringPrintf("Missing ':' separator at start of %s",
824 std::string(oat_checksums).c_str());
825 }
826 return false;
827 }
828 }
829 }
830
831 if (!oat_checksums.empty()) {
832 *error_msg =
833 StringPrintf("Checksum too long, unexpected tail: %s", std::string(oat_checksums).c_str());
834 return false;
835 }
836
837 return true;
838 }
839
ValidateBootClassPathChecksums(const OatFile & oat_file)840 bool OatFileAssistant::ValidateBootClassPathChecksums(const OatFile& oat_file) {
841 // Get the checksums and the BCP from the oat file.
842 const char* oat_boot_class_path_checksums =
843 oat_file.GetOatHeader().GetStoreValueByKey(OatHeader::kBootClassPathChecksumsKey);
844 const char* oat_boot_class_path =
845 oat_file.GetOatHeader().GetStoreValueByKey(OatHeader::kBootClassPathKey);
846 if (oat_boot_class_path_checksums == nullptr || oat_boot_class_path == nullptr) {
847 return false;
848 }
849
850 std::string error_msg;
851 bool result = ValidateBootClassPathChecksums(GetOatFileAssistantContext(),
852 isa_,
853 oat_boot_class_path_checksums,
854 oat_boot_class_path,
855 &error_msg);
856 if (!result) {
857 VLOG(oat) << "Failed to verify checksums of oat file " << oat_file.GetLocation()
858 << " error: " << error_msg;
859 return false;
860 }
861
862 return true;
863 }
864
IsPrimaryBootImageUsable()865 bool OatFileAssistant::IsPrimaryBootImageUsable() {
866 return !GetOatFileAssistantContext()->GetBootImageInfoList(isa_).empty();
867 }
868
GetBestInfo()869 OatFileAssistant::OatFileInfo& OatFileAssistant::GetBestInfo() {
870 ScopedTrace trace("GetBestInfo");
871 // TODO(calin): Document the side effects of class loading when
872 // running dalvikvm command line.
873 if (dex_parent_writable_ || UseFdToReadFiles()) {
874 // If the parent of the dex file is writable it means that we can
875 // create the odex file. In this case we unconditionally pick the odex
876 // as the best oat file. This corresponds to the regular use case when
877 // apps gets installed or when they load private, secondary dex file.
878 // For apps on the system partition the odex location will not be
879 // writable and thus the oat location might be more up to date.
880
881 // If the odex is not useable, and we have a useable vdex, return the vdex
882 // instead.
883 VLOG(oat) << ART_FORMAT("GetBestInfo checking odex next to the dex file ({})",
884 odex_.DisplayFilename());
885 if (!odex_.IsUseable()) {
886 VLOG(oat) << ART_FORMAT("GetBestInfo checking vdex next to the dex file ({})",
887 vdex_for_odex_.DisplayFilename());
888 if (vdex_for_odex_.IsUseable()) {
889 return vdex_for_odex_;
890 }
891 VLOG(oat) << ART_FORMAT("GetBestInfo checking dm ({})", dm_for_odex_.DisplayFilename());
892 if (dm_for_odex_.IsUseable()) {
893 return dm_for_odex_;
894 }
895 }
896 return odex_;
897 }
898
899 // We cannot write to the odex location. This must be a system app.
900
901 // If the oat location is useable take it.
902 VLOG(oat) << ART_FORMAT("GetBestInfo checking odex in dalvik-cache ({})", oat_.DisplayFilename());
903 if (oat_.IsUseable()) {
904 return oat_;
905 }
906
907 // The oat file is not useable but the odex file might be up to date.
908 // This is an indication that we are dealing with an up to date prebuilt
909 // (that doesn't need relocation).
910 VLOG(oat) << ART_FORMAT("GetBestInfo checking odex next to the dex file ({})",
911 odex_.DisplayFilename());
912 if (odex_.IsUseable()) {
913 return odex_;
914 }
915
916 // Look for a useable vdex file.
917 VLOG(oat) << ART_FORMAT("GetBestInfo checking vdex in dalvik-cache ({})",
918 vdex_for_oat_.DisplayFilename());
919 if (vdex_for_oat_.IsUseable()) {
920 return vdex_for_oat_;
921 }
922 VLOG(oat) << ART_FORMAT("GetBestInfo checking vdex next to the dex file ({})",
923 vdex_for_odex_.DisplayFilename());
924 if (vdex_for_odex_.IsUseable()) {
925 return vdex_for_odex_;
926 }
927 VLOG(oat) << ART_FORMAT("GetBestInfo checking dm ({})", dm_for_oat_.DisplayFilename());
928 if (dm_for_oat_.IsUseable()) {
929 return dm_for_oat_;
930 }
931 // TODO(jiakaiz): Is this the same as above?
932 VLOG(oat) << ART_FORMAT("GetBestInfo checking dm ({})", dm_for_odex_.DisplayFilename());
933 if (dm_for_odex_.IsUseable()) {
934 return dm_for_odex_;
935 }
936
937 // We got into the worst situation here:
938 // - the oat location is not useable
939 // - the prebuild odex location is not up to date
940 // - the vdex-only file is not useable
941 // - and we don't have the original dex file anymore (stripped).
942 // Pick the odex if it exists, or the oat if not.
943 VLOG(oat) << "GetBestInfo no usable artifacts";
944 return (odex_.Status() == kOatCannotOpen) ? oat_ : odex_;
945 }
946
OpenImageSpace(const OatFile * oat_file)947 std::unique_ptr<gc::space::ImageSpace> OatFileAssistant::OpenImageSpace(const OatFile* oat_file) {
948 DCHECK(oat_file != nullptr);
949 std::string art_file = ReplaceFileExtension(oat_file->GetLocation(), "art");
950 if (art_file.empty()) {
951 return nullptr;
952 }
953 std::string error_msg;
954 ScopedObjectAccess soa(Thread::Current());
955 std::unique_ptr<gc::space::ImageSpace> ret =
956 gc::space::ImageSpace::CreateFromAppImage(art_file.c_str(), oat_file, &error_msg);
957 if (ret == nullptr && (VLOG_IS_ON(image) || OS::FileExists(art_file.c_str()))) {
958 LOG(INFO) << "Failed to open app image " << art_file.c_str() << " " << error_msg;
959 }
960 return ret;
961 }
962
OatFileInfo(OatFileAssistant * oat_file_assistant,bool is_oat_location)963 OatFileAssistant::OatFileInfo::OatFileInfo(OatFileAssistant* oat_file_assistant,
964 bool is_oat_location)
965 : oat_file_assistant_(oat_file_assistant), is_oat_location_(is_oat_location) {}
966
IsOatLocation()967 bool OatFileAssistant::OatFileInfo::IsOatLocation() { return is_oat_location_; }
968
Filename()969 const std::string* OatFileAssistant::OatFileInfo::Filename() {
970 return filename_provided_ ? &filename_ : nullptr;
971 }
972
DisplayFilename()973 const char* OatFileAssistant::OatFileInfo::DisplayFilename() {
974 return filename_provided_ ? filename_.c_str() : "unknown";
975 }
976
IsUseable()977 bool OatFileAssistant::OatFileInfo::IsUseable() {
978 ScopedTrace trace("IsUseable");
979 switch (Status()) {
980 case kOatCannotOpen:
981 case kOatDexOutOfDate:
982 case kOatContextOutOfDate:
983 case kOatBootImageOutOfDate:
984 return false;
985
986 case kOatUpToDate:
987 return true;
988 }
989 }
990
Status()991 OatFileAssistant::OatStatus OatFileAssistant::OatFileInfo::Status() {
992 ScopedTrace trace("Status");
993 if (!status_attempted_) {
994 status_attempted_ = true;
995 const OatFile* file = GetFile();
996 if (file == nullptr) {
997 status_ = kOatCannotOpen;
998 } else {
999 status_ = oat_file_assistant_->GivenOatFileStatus(*file);
1000 VLOG(oat) << file->GetLocation() << " is " << status_ << " with filter "
1001 << file->GetCompilerFilter();
1002 }
1003 }
1004 return status_;
1005 }
1006
GetDexOptNeeded(CompilerFilter::Filter target_compiler_filter,const DexOptTrigger dexopt_trigger)1007 OatFileAssistant::DexOptNeeded OatFileAssistant::OatFileInfo::GetDexOptNeeded(
1008 CompilerFilter::Filter target_compiler_filter, const DexOptTrigger dexopt_trigger) {
1009 if (IsUseable()) {
1010 return ShouldRecompileForFilter(target_compiler_filter, dexopt_trigger) ? kDex2OatForFilter :
1011 kNoDexOptNeeded;
1012 }
1013
1014 // In this case, the oat file is not usable. If the caller doesn't seek for a better compiler
1015 // filter (e.g., the caller wants to downgrade), then we should not recompile.
1016 if (!dexopt_trigger.targetFilterIsBetter) {
1017 return kNoDexOptNeeded;
1018 }
1019
1020 if (Status() == kOatBootImageOutOfDate) {
1021 return kDex2OatForBootImage;
1022 }
1023
1024 std::string error_msg;
1025 std::optional<bool> has_dex_files = oat_file_assistant_->HasDexFiles(&error_msg);
1026 if (has_dex_files.has_value()) {
1027 if (*has_dex_files) {
1028 return kDex2OatFromScratch;
1029 } else {
1030 // No dex file, so there is nothing we need to do.
1031 return kNoDexOptNeeded;
1032 }
1033 } else {
1034 // Unable to open the dex file, so there is nothing we can do.
1035 LOG(WARNING) << error_msg;
1036 return kNoDexOptNeeded;
1037 }
1038 }
1039
GetFile()1040 const OatFile* OatFileAssistant::OatFileInfo::GetFile() {
1041 CHECK(!file_released_) << "GetFile called after oat file released.";
1042 if (load_attempted_) {
1043 return file_.get();
1044 }
1045 load_attempted_ = true;
1046 if (!filename_provided_) {
1047 return nullptr;
1048 }
1049
1050 if (LocationIsOnArtApexData(filename_) &&
1051 oat_file_assistant_->GetRuntimeOptions().deny_art_apex_data_files) {
1052 LOG(WARNING) << "OatFileAssistant rejected file " << filename_
1053 << ": ART apexdata is untrusted.";
1054 return nullptr;
1055 }
1056
1057 std::string error_msg;
1058 bool executable = oat_file_assistant_->load_executable_;
1059 if (filename_.ends_with(kVdexExtension)) {
1060 executable = false;
1061 // Check to see if there is a vdex file we can make use of.
1062 std::unique_ptr<VdexFile> vdex;
1063 if (use_fd_) {
1064 if (vdex_fd_ >= 0) {
1065 struct stat s;
1066 int rc = TEMP_FAILURE_RETRY(fstat(vdex_fd_, &s));
1067 if (rc == -1) {
1068 error_msg = StringPrintf("Failed getting length of the vdex file %s.", strerror(errno));
1069 } else {
1070 vdex = VdexFile::Open(vdex_fd_,
1071 s.st_size,
1072 filename_,
1073 /*writable=*/false,
1074 /*low_4gb=*/false,
1075 &error_msg);
1076 }
1077 }
1078 } else {
1079 vdex = VdexFile::Open(filename_,
1080 /*writable=*/false,
1081 /*low_4gb=*/false,
1082 &error_msg);
1083 }
1084 if (vdex == nullptr) {
1085 VLOG(oat) << "unable to open vdex file " << filename_ << ": " << error_msg;
1086 } else {
1087 file_.reset(OatFile::OpenFromVdex(zip_fd_,
1088 std::move(vdex),
1089 oat_file_assistant_->dex_location_,
1090 oat_file_assistant_->context_,
1091 &error_msg));
1092 }
1093 } else if (filename_.ends_with(kDmExtension)) {
1094 executable = false;
1095 // Check to see if there is a vdex file we can make use of.
1096 std::unique_ptr<ZipArchive> dm_file(ZipArchive::Open(filename_.c_str(), &error_msg));
1097 if (dm_file != nullptr) {
1098 std::unique_ptr<VdexFile> vdex(VdexFile::OpenFromDm(filename_, *dm_file));
1099 if (vdex != nullptr) {
1100 file_.reset(OatFile::OpenFromVdex(zip_fd_,
1101 std::move(vdex),
1102 oat_file_assistant_->dex_location_,
1103 oat_file_assistant_->context_,
1104 &error_msg));
1105 }
1106 }
1107 } else {
1108 if (executable && oat_file_assistant_->only_load_trusted_executable_) {
1109 executable = LocationIsTrusted(filename_, /*trust_art_apex_data_files=*/true);
1110 }
1111 VLOG(oat) << "Loading " << filename_ << " with executable: " << executable;
1112 if (use_fd_) {
1113 if (oat_fd_ >= 0 && vdex_fd_ >= 0) {
1114 ArrayRef<const std::string> dex_locations(&oat_file_assistant_->dex_location_,
1115 /*size=*/1u);
1116 file_.reset(OatFile::Open(zip_fd_,
1117 vdex_fd_,
1118 oat_fd_,
1119 filename_,
1120 executable,
1121 /*low_4gb=*/false,
1122 dex_locations,
1123 /*dex_files=*/{},
1124 /*reservation=*/nullptr,
1125 &error_msg));
1126 }
1127 } else {
1128 file_.reset(OatFile::Open(/*zip_fd=*/-1,
1129 filename_,
1130 filename_,
1131 executable,
1132 /*low_4gb=*/false,
1133 oat_file_assistant_->dex_location_,
1134 &error_msg));
1135 }
1136 }
1137 if (file_.get() == nullptr) {
1138 VLOG(oat) << "OatFileAssistant test for existing oat file " << filename_ << ": " << error_msg;
1139 } else {
1140 VLOG(oat) << "Successfully loaded " << filename_ << " with executable: " << executable;
1141 }
1142 return file_.get();
1143 }
1144
ShouldRecompileForFilter(CompilerFilter::Filter target,const DexOptTrigger dexopt_trigger)1145 bool OatFileAssistant::OatFileInfo::ShouldRecompileForFilter(CompilerFilter::Filter target,
1146 const DexOptTrigger dexopt_trigger) {
1147 const OatFile* file = GetFile();
1148 DCHECK(file != nullptr);
1149
1150 CompilerFilter::Filter current = file->GetCompilerFilter();
1151 if (dexopt_trigger.targetFilterIsBetter && CompilerFilter::IsBetter(target, current)) {
1152 VLOG(oat) << ART_FORMAT("Should recompile: targetFilterIsBetter (current: {}, target: {})",
1153 CompilerFilter::NameOfFilter(current),
1154 CompilerFilter::NameOfFilter(target));
1155 return true;
1156 }
1157 if (dexopt_trigger.targetFilterIsSame && current == target) {
1158 VLOG(oat) << ART_FORMAT("Should recompile: targetFilterIsSame (current: {}, target: {})",
1159 CompilerFilter::NameOfFilter(current),
1160 CompilerFilter::NameOfFilter(target));
1161 return true;
1162 }
1163 if (dexopt_trigger.targetFilterIsWorse && CompilerFilter::IsBetter(current, target)) {
1164 VLOG(oat) << ART_FORMAT("Should recompile: targetFilterIsWorse (current: {}, target: {})",
1165 CompilerFilter::NameOfFilter(current),
1166 CompilerFilter::NameOfFilter(target));
1167 return true;
1168 }
1169
1170 // Don't regress the compiler filter for the triggers handled below.
1171 if (CompilerFilter::IsBetter(current, target)) {
1172 VLOG(oat) << "Should not recompile: current filter is better";
1173 return false;
1174 }
1175
1176 if (dexopt_trigger.primaryBootImageBecomesUsable &&
1177 CompilerFilter::IsAotCompilationEnabled(current)) {
1178 // If the oat file has been compiled without an image, and the runtime is
1179 // now running with an image loaded from disk, return that we need to
1180 // re-compile. The recompilation will generate a better oat file, and with an app
1181 // image for profile guided compilation.
1182 // However, don't recompile for "verify". Although verification depends on the boot image, the
1183 // penalty of being verified without a boot image is low. Consider the case where a dex file
1184 // is verified by "ab-ota", we don't want it to be re-verified by "boot-after-ota".
1185 const char* oat_boot_class_path_checksums =
1186 file->GetOatHeader().GetStoreValueByKey(OatHeader::kBootClassPathChecksumsKey);
1187 if (oat_boot_class_path_checksums != nullptr &&
1188 oat_boot_class_path_checksums[0] != 'i' &&
1189 oat_file_assistant_->IsPrimaryBootImageUsable()) {
1190 DCHECK(!file->GetOatHeader().RequiresImage());
1191 VLOG(oat) << "Should recompile: primaryBootImageBecomesUsable";
1192 return true;
1193 }
1194 }
1195
1196 if (dexopt_trigger.needExtraction && !file->ContainsDexCode() &&
1197 !oat_file_assistant_->ZipFileOnlyContainsUncompressedDex()) {
1198 VLOG(oat) << "Should recompile: needExtraction";
1199 return true;
1200 }
1201
1202 VLOG(oat) << "Should not recompile";
1203 return false;
1204 }
1205
ClassLoaderContextIsOkay(const OatFile & oat_file) const1206 bool OatFileAssistant::ClassLoaderContextIsOkay(const OatFile& oat_file) const {
1207 if (context_ == nullptr) {
1208 // The caller requests to skip the check.
1209 return true;
1210 }
1211
1212 if (oat_file.IsBackedByVdexOnly()) {
1213 // Only a vdex file, we don't depend on the class loader context.
1214 return true;
1215 }
1216
1217 if (!CompilerFilter::IsVerificationEnabled(oat_file.GetCompilerFilter())) {
1218 // If verification is not enabled we don't need to verify the class loader context and we
1219 // assume it's ok.
1220 return true;
1221 }
1222
1223 ClassLoaderContext::VerificationResult matches =
1224 context_->VerifyClassLoaderContextMatch(oat_file.GetClassLoaderContext(),
1225 /*verify_names=*/true,
1226 /*verify_checksums=*/true);
1227 if (matches == ClassLoaderContext::VerificationResult::kMismatch) {
1228 VLOG(oat) << "ClassLoaderContext check failed. Context was " << oat_file.GetClassLoaderContext()
1229 << ". The expected context is "
1230 << context_->EncodeContextForOatFile(android::base::Dirname(dex_location_));
1231 return false;
1232 }
1233 return true;
1234 }
1235
IsExecutable()1236 bool OatFileAssistant::OatFileInfo::IsExecutable() {
1237 const OatFile* file = GetFile();
1238 return (file != nullptr && file->IsExecutable());
1239 }
1240
Reset()1241 void OatFileAssistant::OatFileInfo::Reset() {
1242 load_attempted_ = false;
1243 file_.reset();
1244 status_attempted_ = false;
1245 }
1246
Reset(const std::string & filename,bool use_fd,int zip_fd,int vdex_fd,int oat_fd)1247 void OatFileAssistant::OatFileInfo::Reset(
1248 const std::string& filename, bool use_fd, int zip_fd, int vdex_fd, int oat_fd) {
1249 filename_provided_ = true;
1250 filename_ = filename;
1251 use_fd_ = use_fd;
1252 zip_fd_ = zip_fd;
1253 vdex_fd_ = vdex_fd;
1254 oat_fd_ = oat_fd;
1255 Reset();
1256 }
1257
ReleaseFile()1258 std::unique_ptr<OatFile> OatFileAssistant::OatFileInfo::ReleaseFile() {
1259 file_released_ = true;
1260 return std::move(file_);
1261 }
1262
ReleaseFileForUse()1263 std::unique_ptr<OatFile> OatFileAssistant::OatFileInfo::ReleaseFileForUse() {
1264 ScopedTrace trace("ReleaseFileForUse");
1265 if (Status() == kOatUpToDate) {
1266 return ReleaseFile();
1267 }
1268
1269 return std::unique_ptr<OatFile>();
1270 }
1271
1272 // Check if we should reject vdex containing cdex code as part of the cdex
1273 // deprecation.
1274 // TODO(b/256664509): Clean this up.
CheckDisableCompactDex()1275 bool OatFileAssistant::OatFileInfo::CheckDisableCompactDex() {
1276 const OatFile* oat_file = GetFile();
1277 if (oat_file == nullptr) {
1278 return false;
1279 }
1280 const VdexFile* vdex_file = oat_file->GetVdexFile();
1281 return vdex_file != nullptr && vdex_file->HasDexSection() &&
1282 !vdex_file->HasOnlyStandardDexFiles();
1283 }
1284
1285 // TODO(calin): we could provide a more refined status here
1286 // (e.g. run from uncompressed apk, run with vdex but not oat etc). It will allow us to
1287 // track more experiments but adds extra complexity.
GetOptimizationStatus(const std::string & filename,InstructionSet isa,std::string * out_compilation_filter,std::string * out_compilation_reason,OatFileAssistantContext * ofa_context)1288 void OatFileAssistant::GetOptimizationStatus(const std::string& filename,
1289 InstructionSet isa,
1290 std::string* out_compilation_filter,
1291 std::string* out_compilation_reason,
1292 OatFileAssistantContext* ofa_context) {
1293 // It may not be possible to load an oat file executable (e.g., selinux restrictions). Load
1294 // non-executable and check the status manually.
1295 OatFileAssistant oat_file_assistant(filename.c_str(),
1296 isa,
1297 /*context=*/nullptr,
1298 /*load_executable=*/false,
1299 /*only_load_trusted_executable=*/false,
1300 ofa_context);
1301 std::string out_odex_location; // unused
1302 std::string out_odex_status; // unused
1303 Location out_location; // unused
1304 oat_file_assistant.GetOptimizationStatus(&out_odex_location,
1305 out_compilation_filter,
1306 out_compilation_reason,
1307 &out_odex_status,
1308 &out_location);
1309 }
1310
GetOptimizationStatus(std::string * out_odex_location,std::string * out_compilation_filter,std::string * out_compilation_reason,std::string * out_odex_status,Location * out_location)1311 void OatFileAssistant::GetOptimizationStatus(std::string* out_odex_location,
1312 std::string* out_compilation_filter,
1313 std::string* out_compilation_reason,
1314 std::string* out_odex_status,
1315 Location* out_location) {
1316 OatFileInfo& oat_file_info = GetBestInfo();
1317 const OatFile* oat_file = oat_file_info.GetFile();
1318 *out_location = GetLocation(oat_file_info);
1319
1320 if (oat_file == nullptr) {
1321 std::string error_msg;
1322 std::optional<bool> has_dex_files = HasDexFiles(&error_msg);
1323 if (!has_dex_files.has_value()) {
1324 *out_odex_location = "error";
1325 *out_compilation_filter = "unknown";
1326 *out_compilation_reason = "unknown";
1327 // This happens when we cannot open the APK/JAR.
1328 *out_odex_status = "io-error-no-apk";
1329 } else if (!has_dex_files.value()) {
1330 *out_odex_location = "none";
1331 *out_compilation_filter = "unknown";
1332 *out_compilation_reason = "unknown";
1333 // This happens when the APK/JAR doesn't contain any DEX file.
1334 *out_odex_status = "no-dex-code";
1335 } else {
1336 *out_odex_location = "error";
1337 *out_compilation_filter = "run-from-apk";
1338 *out_compilation_reason = "unknown";
1339 // This mostly happens when we cannot open the oat file.
1340 // Note that it's different than kOatCannotOpen.
1341 // TODO: The design of getting the BestInfo is not ideal, as it's not very clear what's the
1342 // difference between a nullptr and kOatcannotOpen. The logic should be revised and improved.
1343 *out_odex_status = "io-error-no-oat";
1344 }
1345 return;
1346 }
1347
1348 *out_odex_location = oat_file->GetLocation();
1349 OatStatus status = oat_file_info.Status();
1350 const char* reason = oat_file->GetCompilationReason();
1351 *out_compilation_reason = reason == nullptr ? "unknown" : reason;
1352
1353 // If the oat file is invalid, the vdex file will be picked, so the status is `kOatUpToDate`. If
1354 // the vdex file is also invalid, then either `oat_file` is nullptr, or `status` is
1355 // `kOatDexOutOfDate`.
1356 DCHECK(status == kOatUpToDate || status == kOatDexOutOfDate);
1357
1358 switch (status) {
1359 case kOatUpToDate:
1360 *out_compilation_filter = CompilerFilter::NameOfFilter(oat_file->GetCompilerFilter());
1361 *out_odex_status = "up-to-date";
1362 return;
1363
1364 case kOatCannotOpen:
1365 case kOatBootImageOutOfDate:
1366 case kOatContextOutOfDate:
1367 // These should never happen, but be robust.
1368 *out_compilation_filter = "unexpected";
1369 *out_compilation_reason = "unexpected";
1370 *out_odex_status = "unexpected";
1371 return;
1372
1373 case kOatDexOutOfDate:
1374 *out_compilation_filter = "run-from-apk-fallback";
1375 *out_odex_status = "apk-more-recent";
1376 return;
1377 }
1378 LOG(FATAL) << "Unreachable";
1379 UNREACHABLE();
1380 }
1381
ZipFileOnlyContainsUncompressedDex()1382 bool OatFileAssistant::ZipFileOnlyContainsUncompressedDex() {
1383 // zip_file_only_contains_uncompressed_dex_ is only set during fetching the dex checksums.
1384 std::optional<uint32_t> checksum;
1385 std::string error_msg;
1386 if (!GetRequiredDexChecksum(&checksum, &error_msg)) {
1387 LOG(ERROR) << error_msg;
1388 }
1389 return zip_file_only_contains_uncompressed_dex_;
1390 }
1391
GetLocation(OatFileInfo & info)1392 OatFileAssistant::Location OatFileAssistant::GetLocation(OatFileInfo& info) {
1393 if (info.IsUseable()) {
1394 if (&info == &dm_for_oat_ || &info == &dm_for_odex_) {
1395 return kLocationDm;
1396 } else if (info.IsOatLocation()) {
1397 return kLocationOat;
1398 } else {
1399 return kLocationOdex;
1400 }
1401 } else {
1402 return kLocationNoneOrError;
1403 }
1404 }
1405
1406 } // namespace art
1407