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