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