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 <fcntl.h>
20 #ifdef __linux__
21 #include <sys/sendfile.h>
22 #else
23 #include <sys/socket.h>
24 #endif
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <unistd.h>
28 
29 #include <set>
30 
31 #include "base/logging.h"
32 #include "base/stringprintf.h"
33 #include "class_linker.h"
34 #include "gc/heap.h"
35 #include "gc/space/image_space.h"
36 #include "image.h"
37 #include "oat.h"
38 #include "os.h"
39 #include "profiler.h"
40 #include "runtime.h"
41 #include "ScopedFd.h"
42 #include "utils.h"
43 
44 namespace art {
45 
OatFileAssistant(const char * dex_location,const InstructionSet isa,bool load_executable)46 OatFileAssistant::OatFileAssistant(const char* dex_location,
47                                    const InstructionSet isa,
48                                    bool load_executable)
49     : OatFileAssistant(dex_location, nullptr, isa, load_executable, nullptr) { }
50 
OatFileAssistant(const char * dex_location,const char * oat_location,const InstructionSet isa,bool load_executable)51 OatFileAssistant::OatFileAssistant(const char* dex_location,
52                                    const char* oat_location,
53                                    const InstructionSet isa,
54                                    bool load_executable)
55     : OatFileAssistant(dex_location, oat_location, isa, load_executable, nullptr) { }
56 
OatFileAssistant(const char * dex_location,const InstructionSet isa,bool load_executable,const char * package_name)57 OatFileAssistant::OatFileAssistant(const char* dex_location,
58                                    const InstructionSet isa,
59                                    bool load_executable,
60                                    const char* package_name)
61     : OatFileAssistant(dex_location, nullptr, isa, load_executable, package_name) { }
62 
OatFileAssistant(const char * dex_location,const char * oat_location,const InstructionSet isa,bool load_executable,const char * package_name)63 OatFileAssistant::OatFileAssistant(const char* dex_location,
64                                    const char* oat_location,
65                                    const InstructionSet isa,
66                                    bool load_executable,
67                                    const char* package_name)
68     : dex_location_(dex_location), isa_(isa),
69       package_name_(package_name), load_executable_(load_executable) {
70   if (load_executable_ && isa != kRuntimeISA) {
71     LOG(WARNING) << "OatFileAssistant: Load executable specified, "
72       << "but isa is not kRuntimeISA. Will not attempt to load executable.";
73     load_executable_ = false;
74   }
75 
76   // If the user gave a target oat location, save that as the cached oat
77   // location now so we won't try to construct the default location later.
78   if (oat_location != nullptr) {
79     cached_oat_file_name_ = std::string(oat_location);
80     cached_oat_file_name_attempted_ = true;
81     cached_oat_file_name_found_ = true;
82   }
83 
84   // If there is no package name given, we will not be able to find any
85   // profiles associated with this dex location. Preemptively mark that to
86   // be the case, rather than trying to find and load the profiles later.
87   // Similarly, if profiling is disabled.
88   if (package_name == nullptr
89       || !Runtime::Current()->GetProfilerOptions().IsEnabled()) {
90     profile_load_attempted_ = true;
91     profile_load_succeeded_ = false;
92     old_profile_load_attempted_ = true;
93     old_profile_load_succeeded_ = false;
94   }
95 }
96 
~OatFileAssistant()97 OatFileAssistant::~OatFileAssistant() {
98   // Clean up the lock file.
99   if (flock_.HasFile()) {
100     TEMP_FAILURE_RETRY(unlink(flock_.GetFile()->GetPath().c_str()));
101   }
102 }
103 
IsInBootClassPath()104 bool OatFileAssistant::IsInBootClassPath() {
105   // Note: We check the current boot class path, regardless of the ISA
106   // specified by the user. This is okay, because the boot class path should
107   // be the same for all ISAs.
108   // TODO: Can we verify the boot class path is the same for all ISAs?
109   Runtime* runtime = Runtime::Current();
110   ClassLinker* class_linker = runtime->GetClassLinker();
111   const auto& boot_class_path = class_linker->GetBootClassPath();
112   for (size_t i = 0; i < boot_class_path.size(); i++) {
113     if (boot_class_path[i]->GetLocation() == std::string(dex_location_)) {
114       VLOG(oat) << "Dex location " << dex_location_ << " is in boot class path";
115       return true;
116     }
117   }
118   return false;
119 }
120 
Lock(std::string * error_msg)121 bool OatFileAssistant::Lock(std::string* error_msg) {
122   CHECK(error_msg != nullptr);
123   CHECK(!flock_.HasFile()) << "OatFileAssistant::Lock already acquired";
124 
125   if (OatFileName() == nullptr) {
126     *error_msg = "Failed to determine lock file";
127     return false;
128   }
129   std::string lock_file_name = *OatFileName() + ".flock";
130 
131   if (!flock_.Init(lock_file_name.c_str(), error_msg)) {
132     TEMP_FAILURE_RETRY(unlink(lock_file_name.c_str()));
133     return false;
134   }
135   return true;
136 }
137 
GetDexOptNeeded()138 OatFileAssistant::DexOptNeeded OatFileAssistant::GetDexOptNeeded() {
139   // TODO: If the profiling code is ever restored, it's worth considering
140   // whether we should check to see if the profile is out of date here.
141 
142   if (OatFileIsUpToDate() || OdexFileIsUpToDate()) {
143     return kNoDexOptNeeded;
144   }
145 
146   if (OdexFileNeedsRelocation()) {
147     return kPatchOatNeeded;
148   }
149 
150   if (OatFileNeedsRelocation()) {
151     return kSelfPatchOatNeeded;
152   }
153 
154   return HasOriginalDexFiles() ? kDex2OatNeeded : kNoDexOptNeeded;
155 }
156 
MakeUpToDate(std::string * error_msg)157 bool OatFileAssistant::MakeUpToDate(std::string* error_msg) {
158   switch (GetDexOptNeeded()) {
159     case kNoDexOptNeeded: return true;
160     case kDex2OatNeeded: return GenerateOatFile(error_msg);
161     case kPatchOatNeeded: return RelocateOatFile(OdexFileName(), error_msg);
162     case kSelfPatchOatNeeded: return RelocateOatFile(OatFileName(), error_msg);
163   }
164   UNREACHABLE();
165 }
166 
GetBestOatFile()167 std::unique_ptr<OatFile> OatFileAssistant::GetBestOatFile() {
168   if (OatFileIsUpToDate()) {
169     oat_file_released_ = true;
170     return std::move(cached_oat_file_);
171   }
172 
173   if (OdexFileIsUpToDate()) {
174     oat_file_released_ = true;
175     return std::move(cached_odex_file_);
176   }
177 
178   if (load_executable_) {
179     VLOG(oat) << "Oat File Assistant: No relocated oat file found,"
180       << " attempting to fall back to interpreting oat file instead.";
181 
182     if (!OatFileIsOutOfDate()) {
183       load_executable_ = false;
184       ClearOatFileCache();
185       if (!OatFileIsOutOfDate()) {
186         oat_file_released_ = true;
187         return std::move(cached_oat_file_);
188       }
189     }
190 
191     if (!OdexFileIsOutOfDate()) {
192       load_executable_ = false;
193       ClearOdexFileCache();
194       if (!OdexFileIsOutOfDate()) {
195         oat_file_released_ = true;
196         return std::move(cached_odex_file_);
197       }
198     }
199   }
200 
201   return std::unique_ptr<OatFile>();
202 }
203 
LoadDexFiles(const OatFile & oat_file,const char * dex_location)204 std::vector<std::unique_ptr<const DexFile>> OatFileAssistant::LoadDexFiles(
205     const OatFile& oat_file, const char* dex_location) {
206   std::vector<std::unique_ptr<const DexFile>> dex_files;
207 
208   // Load the primary dex file.
209   std::string error_msg;
210   const OatFile::OatDexFile* oat_dex_file = oat_file.GetOatDexFile(
211       dex_location, nullptr, false);
212   if (oat_dex_file == nullptr) {
213     LOG(WARNING) << "Attempt to load out-of-date oat file "
214       << oat_file.GetLocation() << " for dex location " << dex_location;
215     return std::vector<std::unique_ptr<const DexFile>>();
216   }
217 
218   std::unique_ptr<const DexFile> dex_file = oat_dex_file->OpenDexFile(&error_msg);
219   if (dex_file.get() == nullptr) {
220     LOG(WARNING) << "Failed to open dex file from oat dex file: " << error_msg;
221     return std::vector<std::unique_ptr<const DexFile>>();
222   }
223   dex_files.push_back(std::move(dex_file));
224 
225   // Load secondary multidex files
226   for (size_t i = 1; ; i++) {
227     std::string secondary_dex_location = DexFile::GetMultiDexLocation(i, dex_location);
228     oat_dex_file = oat_file.GetOatDexFile(secondary_dex_location.c_str(), nullptr, false);
229     if (oat_dex_file == nullptr) {
230       // There are no more secondary dex files to load.
231       break;
232     }
233 
234     dex_file = oat_dex_file->OpenDexFile(&error_msg);
235     if (dex_file.get() == nullptr) {
236       LOG(WARNING) << "Failed to open dex file from oat dex file: " << error_msg;
237       return std::vector<std::unique_ptr<const DexFile>>();
238     }
239     dex_files.push_back(std::move(dex_file));
240   }
241   return dex_files;
242 }
243 
HasOriginalDexFiles()244 bool OatFileAssistant::HasOriginalDexFiles() {
245   // Ensure GetRequiredDexChecksum has been run so that
246   // has_original_dex_files_ is initialized. We don't care about the result of
247   // GetRequiredDexChecksum.
248   GetRequiredDexChecksum();
249   return has_original_dex_files_;
250 }
251 
OdexFileName()252 const std::string* OatFileAssistant::OdexFileName() {
253   if (!cached_odex_file_name_attempted_) {
254     CHECK(dex_location_ != nullptr) << "OatFileAssistant: null dex location";
255     cached_odex_file_name_attempted_ = true;
256 
257     std::string error_msg;
258     cached_odex_file_name_found_ = DexFilenameToOdexFilename(
259         dex_location_, isa_, &cached_odex_file_name_, &error_msg);
260     if (!cached_odex_file_name_found_) {
261       // If we can't figure out the odex file, we treat it as if the odex
262       // file was inaccessible.
263       LOG(WARNING) << "Failed to determine odex file name: " << error_msg;
264     }
265   }
266   return cached_odex_file_name_found_ ? &cached_odex_file_name_ : nullptr;
267 }
268 
OdexFileExists()269 bool OatFileAssistant::OdexFileExists() {
270   return GetOdexFile() != nullptr;
271 }
272 
OdexFileStatus()273 OatFileAssistant::OatStatus OatFileAssistant::OdexFileStatus() {
274   if (OdexFileIsOutOfDate()) {
275     return kOatOutOfDate;
276   }
277   if (OdexFileIsUpToDate()) {
278     return kOatUpToDate;
279   }
280   return kOatNeedsRelocation;
281 }
282 
OdexFileIsOutOfDate()283 bool OatFileAssistant::OdexFileIsOutOfDate() {
284   if (!odex_file_is_out_of_date_attempted_) {
285     odex_file_is_out_of_date_attempted_ = true;
286     const OatFile* odex_file = GetOdexFile();
287     if (odex_file == nullptr) {
288       cached_odex_file_is_out_of_date_ = true;
289     } else {
290       cached_odex_file_is_out_of_date_ = GivenOatFileIsOutOfDate(*odex_file);
291     }
292   }
293   return cached_odex_file_is_out_of_date_;
294 }
295 
OdexFileNeedsRelocation()296 bool OatFileAssistant::OdexFileNeedsRelocation() {
297   return OdexFileStatus() == kOatNeedsRelocation;
298 }
299 
OdexFileIsUpToDate()300 bool OatFileAssistant::OdexFileIsUpToDate() {
301   if (!odex_file_is_up_to_date_attempted_) {
302     odex_file_is_up_to_date_attempted_ = true;
303     const OatFile* odex_file = GetOdexFile();
304     if (odex_file == nullptr) {
305       cached_odex_file_is_up_to_date_ = false;
306     } else {
307       cached_odex_file_is_up_to_date_ = GivenOatFileIsUpToDate(*odex_file);
308     }
309   }
310   return cached_odex_file_is_up_to_date_;
311 }
312 
OatFileName()313 const std::string* OatFileAssistant::OatFileName() {
314   if (!cached_oat_file_name_attempted_) {
315     cached_oat_file_name_attempted_ = true;
316 
317     // Compute the oat file name from the dex location.
318     CHECK(dex_location_ != nullptr) << "OatFileAssistant: null dex location";
319 
320     // TODO: The oat file assistant should be the definitive place for
321     // determining the oat file name from the dex location, not
322     // GetDalvikCacheFilename.
323     std::string cache_dir = StringPrintf("%s%s",
324         DalvikCacheDirectory().c_str(), GetInstructionSetString(isa_));
325     std::string error_msg;
326     cached_oat_file_name_found_ = GetDalvikCacheFilename(dex_location_,
327         cache_dir.c_str(), &cached_oat_file_name_, &error_msg);
328     if (!cached_oat_file_name_found_) {
329       // If we can't determine the oat file name, we treat the oat file as
330       // inaccessible.
331       LOG(WARNING) << "Failed to determine oat file name for dex location "
332         << dex_location_ << ": " << error_msg;
333     }
334   }
335   return cached_oat_file_name_found_ ? &cached_oat_file_name_ : nullptr;
336 }
337 
OatFileExists()338 bool OatFileAssistant::OatFileExists() {
339   return GetOatFile() != nullptr;
340 }
341 
OatFileStatus()342 OatFileAssistant::OatStatus OatFileAssistant::OatFileStatus() {
343   if (OatFileIsOutOfDate()) {
344     return kOatOutOfDate;
345   }
346   if (OatFileIsUpToDate()) {
347     return kOatUpToDate;
348   }
349   return kOatNeedsRelocation;
350 }
351 
OatFileIsOutOfDate()352 bool OatFileAssistant::OatFileIsOutOfDate() {
353   if (!oat_file_is_out_of_date_attempted_) {
354     oat_file_is_out_of_date_attempted_ = true;
355     const OatFile* oat_file = GetOatFile();
356     if (oat_file == nullptr) {
357       cached_oat_file_is_out_of_date_ = true;
358     } else {
359       cached_oat_file_is_out_of_date_ = GivenOatFileIsOutOfDate(*oat_file);
360     }
361   }
362   return cached_oat_file_is_out_of_date_;
363 }
364 
OatFileNeedsRelocation()365 bool OatFileAssistant::OatFileNeedsRelocation() {
366   return OatFileStatus() == kOatNeedsRelocation;
367 }
368 
OatFileIsUpToDate()369 bool OatFileAssistant::OatFileIsUpToDate() {
370   if (!oat_file_is_up_to_date_attempted_) {
371     oat_file_is_up_to_date_attempted_ = true;
372     const OatFile* oat_file = GetOatFile();
373     if (oat_file == nullptr) {
374       cached_oat_file_is_up_to_date_ = false;
375     } else {
376       cached_oat_file_is_up_to_date_ = GivenOatFileIsUpToDate(*oat_file);
377     }
378   }
379   return cached_oat_file_is_up_to_date_;
380 }
381 
GivenOatFileStatus(const OatFile & file)382 OatFileAssistant::OatStatus OatFileAssistant::GivenOatFileStatus(const OatFile& file) {
383   // TODO: This could cause GivenOatFileIsOutOfDate to be called twice, which
384   // is more work than we need to do. If performance becomes a concern, and
385   // this method is actually called, this should be fixed.
386   if (GivenOatFileIsOutOfDate(file)) {
387     return kOatOutOfDate;
388   }
389   if (GivenOatFileIsUpToDate(file)) {
390     return kOatUpToDate;
391   }
392   return kOatNeedsRelocation;
393 }
394 
GivenOatFileIsOutOfDate(const OatFile & file)395 bool OatFileAssistant::GivenOatFileIsOutOfDate(const OatFile& file) {
396   // Verify the dex checksum.
397   // Note: GetOatDexFile will return null if the dex checksum doesn't match
398   // what we provide, which verifies the primary dex checksum for us.
399   const uint32_t* dex_checksum_pointer = GetRequiredDexChecksum();
400   const OatFile::OatDexFile* oat_dex_file = file.GetOatDexFile(
401       dex_location_, dex_checksum_pointer, false);
402   if (oat_dex_file == nullptr) {
403     return true;
404   }
405 
406   // Verify the dex checksums for any secondary multidex files
407   for (size_t i = 1; ; i++) {
408     std::string secondary_dex_location
409       = DexFile::GetMultiDexLocation(i, dex_location_);
410     const OatFile::OatDexFile* secondary_oat_dex_file
411       = file.GetOatDexFile(secondary_dex_location.c_str(), nullptr, false);
412     if (secondary_oat_dex_file == nullptr) {
413       // There are no more secondary dex files to check.
414       break;
415     }
416 
417     std::string error_msg;
418     uint32_t expected_secondary_checksum = 0;
419     if (DexFile::GetChecksum(secondary_dex_location.c_str(),
420           &expected_secondary_checksum, &error_msg)) {
421       uint32_t actual_secondary_checksum
422         = secondary_oat_dex_file->GetDexFileLocationChecksum();
423       if (expected_secondary_checksum != actual_secondary_checksum) {
424         VLOG(oat) << "Dex checksum does not match for secondary dex: "
425           << secondary_dex_location
426           << ". Expected: " << expected_secondary_checksum
427           << ", Actual: " << actual_secondary_checksum;
428         return true;
429       }
430     } else {
431       // If we can't get the checksum for the secondary location, we assume
432       // the dex checksum is up to date for this and all other secondary dex
433       // files.
434       break;
435     }
436   }
437 
438   // Verify the image checksum
439   const ImageInfo* image_info = GetImageInfo();
440   if (image_info == nullptr) {
441     VLOG(oat) << "No image for oat image checksum to match against.";
442     return true;
443   }
444 
445   if (file.GetOatHeader().GetImageFileLocationOatChecksum() != image_info->oat_checksum) {
446     VLOG(oat) << "Oat image checksum does not match image checksum.";
447     return true;
448   }
449 
450   // The checksums are all good; the dex file is not out of date.
451   return false;
452 }
453 
GivenOatFileNeedsRelocation(const OatFile & file)454 bool OatFileAssistant::GivenOatFileNeedsRelocation(const OatFile& file) {
455   return GivenOatFileStatus(file) == kOatNeedsRelocation;
456 }
457 
GivenOatFileIsUpToDate(const OatFile & file)458 bool OatFileAssistant::GivenOatFileIsUpToDate(const OatFile& file) {
459   if (GivenOatFileIsOutOfDate(file)) {
460     return false;
461   }
462 
463   if (file.IsPic()) {
464     return true;
465   }
466 
467   const ImageInfo* image_info = GetImageInfo();
468   if (image_info == nullptr) {
469     VLOG(oat) << "No image to check oat relocation against.";
470     return false;
471   }
472 
473   // Verify the oat_data_begin recorded for the image in the oat file matches
474   // the actual oat_data_begin for boot.oat in the image.
475   const OatHeader& oat_header = file.GetOatHeader();
476   uintptr_t oat_data_begin = oat_header.GetImageFileLocationOatDataBegin();
477   if (oat_data_begin != image_info->oat_data_begin) {
478     VLOG(oat) << file.GetLocation() <<
479       ": Oat file image oat_data_begin (" << oat_data_begin << ")"
480       << " does not match actual image oat_data_begin ("
481       << image_info->oat_data_begin << ")";
482     return false;
483   }
484 
485   // Verify the oat_patch_delta recorded for the image in the oat file matches
486   // the actual oat_patch_delta for the image.
487   int32_t oat_patch_delta = oat_header.GetImagePatchDelta();
488   if (oat_patch_delta != image_info->patch_delta) {
489     VLOG(oat) << file.GetLocation() <<
490       ": Oat file image patch delta (" << oat_patch_delta << ")"
491       << " does not match actual image patch delta ("
492       << image_info->patch_delta << ")";
493     return false;
494   }
495   return true;
496 }
497 
ProfileExists()498 bool OatFileAssistant::ProfileExists() {
499   return GetProfile() != nullptr;
500 }
501 
OldProfileExists()502 bool OatFileAssistant::OldProfileExists() {
503   return GetOldProfile() != nullptr;
504 }
505 
506 // TODO: The IsProfileChangeSignificant implementation was copied from likely
507 // bit-rotted code.
IsProfileChangeSignificant()508 bool OatFileAssistant::IsProfileChangeSignificant() {
509   ProfileFile* profile = GetProfile();
510   if (profile == nullptr) {
511     return false;
512   }
513 
514   ProfileFile* old_profile = GetOldProfile();
515   if (old_profile == nullptr) {
516     return false;
517   }
518 
519   // TODO: The following code to compare two profile files should live with
520   // the rest of the profiler code, not the oat file assistant code.
521 
522   // A change in profile is considered significant if X% (change_thr property)
523   // of the top K% (compile_thr property) samples has changed.
524   const ProfilerOptions& options = Runtime::Current()->GetProfilerOptions();
525   const double top_k_threshold = options.GetTopKThreshold();
526   const double change_threshold = options.GetTopKChangeThreshold();
527   std::set<std::string> top_k, old_top_k;
528   profile->GetTopKSamples(top_k, top_k_threshold);
529   old_profile->GetTopKSamples(old_top_k, top_k_threshold);
530   std::set<std::string> diff;
531   std::set_difference(top_k.begin(), top_k.end(), old_top_k.begin(),
532       old_top_k.end(), std::inserter(diff, diff.end()));
533 
534   // TODO: consider using the usedPercentage instead of the plain diff count.
535   double change_percent = 100.0 * static_cast<double>(diff.size())
536                                 / static_cast<double>(top_k.size());
537   std::set<std::string>::iterator end = diff.end();
538   for (std::set<std::string>::iterator it = diff.begin(); it != end; it++) {
539     VLOG(oat) << "Profile new in topK: " << *it;
540   }
541 
542   if (change_percent > change_threshold) {
543       VLOG(oat) << "Oat File Assistant: Profile for " << dex_location_
544         << "has changed significantly: (top "
545         << top_k_threshold << "% samples changed in proportion of "
546         << change_percent << "%)";
547       return true;
548   }
549   return false;
550 }
551 
552 // TODO: The CopyProfileFile implementation was copied from likely bit-rotted
553 // code.
CopyProfileFile()554 void OatFileAssistant::CopyProfileFile() {
555   if (!ProfileExists()) {
556     return;
557   }
558 
559   std::string profile_name = ProfileFileName();
560   std::string old_profile_name = OldProfileFileName();
561 
562   ScopedFd src(open(old_profile_name.c_str(), O_RDONLY));
563   if (src.get() == -1) {
564     PLOG(WARNING) << "Failed to open profile file " << old_profile_name
565       << ". My uid:gid is " << getuid() << ":" << getgid();
566     return;
567   }
568 
569   struct stat stat_src;
570   if (fstat(src.get(), &stat_src) == -1) {
571     PLOG(WARNING) << "Failed to get stats for profile file  " << old_profile_name
572       << ". My uid:gid is " << getuid() << ":" << getgid();
573     return;
574   }
575 
576   // Create the copy with rw------- (only accessible by system)
577   ScopedFd dst(open(profile_name.c_str(), O_WRONLY|O_CREAT|O_TRUNC, 0600));
578   if (dst.get()  == -1) {
579     PLOG(WARNING) << "Failed to create/write prev profile file " << profile_name
580       << ".  My uid:gid is " << getuid() << ":" << getgid();
581     return;
582   }
583 
584 #ifdef __linux__
585   if (sendfile(dst.get(), src.get(), nullptr, stat_src.st_size) == -1) {
586 #else
587   off_t len;
588   if (sendfile(dst.get(), src.get(), 0, &len, nullptr, 0) == -1) {
589 #endif
590     PLOG(WARNING) << "Failed to copy profile file " << old_profile_name
591       << " to " << profile_name << ". My uid:gid is " << getuid()
592       << ":" << getgid();
593   }
594 }
595 
596 bool OatFileAssistant::RelocateOatFile(const std::string* input_file,
597                                        std::string* error_msg) {
598   CHECK(error_msg != nullptr);
599 
600   if (input_file == nullptr) {
601     *error_msg = "Patching of oat file for dex location "
602       + std::string(dex_location_)
603       + " not attempted because the input file name could not be determined.";
604     return false;
605   }
606   const std::string& input_file_name = *input_file;
607 
608   if (OatFileName() == nullptr) {
609     *error_msg = "Patching of oat file for dex location "
610       + std::string(dex_location_)
611       + " not attempted because the oat file name could not be determined.";
612     return false;
613   }
614   const std::string& oat_file_name = *OatFileName();
615 
616   const ImageInfo* image_info = GetImageInfo();
617   Runtime* runtime = Runtime::Current();
618   if (image_info == nullptr) {
619     *error_msg = "Patching of oat file " + oat_file_name
620       + " not attempted because no image location was found.";
621     return false;
622   }
623 
624   if (!runtime->IsDex2OatEnabled()) {
625     *error_msg = "Patching of oat file " + oat_file_name
626       + " not attempted because dex2oat is disabled";
627     return false;
628   }
629 
630   std::vector<std::string> argv;
631   argv.push_back(runtime->GetPatchoatExecutable());
632   argv.push_back("--instruction-set=" + std::string(GetInstructionSetString(isa_)));
633   argv.push_back("--input-oat-file=" + input_file_name);
634   argv.push_back("--output-oat-file=" + oat_file_name);
635   argv.push_back("--patched-image-location=" + image_info->location);
636 
637   std::string command_line(Join(argv, ' '));
638   if (!Exec(argv, error_msg)) {
639     // Manually delete the file. This ensures there is no garbage left over if
640     // the process unexpectedly died.
641     TEMP_FAILURE_RETRY(unlink(oat_file_name.c_str()));
642     return false;
643   }
644 
645   // Mark that the oat file has changed and we should try to reload.
646   ClearOatFileCache();
647   return true;
648 }
649 
650 bool OatFileAssistant::GenerateOatFile(std::string* error_msg) {
651   CHECK(error_msg != nullptr);
652 
653   if (OatFileName() == nullptr) {
654     *error_msg = "Generation of oat file for dex location "
655       + std::string(dex_location_)
656       + " not attempted because the oat file name could not be determined.";
657     return false;
658   }
659   const std::string& oat_file_name = *OatFileName();
660 
661   Runtime* runtime = Runtime::Current();
662   if (!runtime->IsDex2OatEnabled()) {
663     *error_msg = "Generation of oat file " + oat_file_name
664       + " not attempted because dex2oat is disabled";
665     return false;
666   }
667 
668   std::vector<std::string> args;
669   args.push_back("--dex-file=" + std::string(dex_location_));
670   args.push_back("--oat-file=" + oat_file_name);
671 
672   // dex2oat ignores missing dex files and doesn't report an error.
673   // Check explicitly here so we can detect the error properly.
674   // TODO: Why does dex2oat behave that way?
675   if (!OS::FileExists(dex_location_)) {
676     *error_msg = "Dex location " + std::string(dex_location_) + " does not exists.";
677     return false;
678   }
679 
680   if (!Dex2Oat(args, error_msg)) {
681     // Manually delete the file. This ensures there is no garbage left over if
682     // the process unexpectedly died.
683     TEMP_FAILURE_RETRY(unlink(oat_file_name.c_str()));
684     return false;
685   }
686 
687   // Mark that the oat file has changed and we should try to reload.
688   ClearOatFileCache();
689   return true;
690 }
691 
692 bool OatFileAssistant::Dex2Oat(const std::vector<std::string>& args,
693                                std::string* error_msg) {
694   Runtime* runtime = Runtime::Current();
695   std::string image_location = ImageLocation();
696   if (image_location.empty()) {
697     *error_msg = "No image location found for Dex2Oat.";
698     return false;
699   }
700 
701   ClassLinker* linker = runtime->GetClassLinker();
702   CHECK(linker != nullptr) << "ClassLinker is not created yet";
703   const OatFile* primary_oat_file = linker->GetPrimaryOatFile();
704   const bool debuggable = primary_oat_file != nullptr && primary_oat_file->IsDebuggable();
705 
706   std::vector<std::string> argv;
707   argv.push_back(runtime->GetCompilerExecutable());
708   argv.push_back("--runtime-arg");
709   argv.push_back("-classpath");
710   argv.push_back("--runtime-arg");
711   argv.push_back(runtime->GetClassPathString());
712   if (debuggable) {
713     argv.push_back("--debuggable");
714   }
715   runtime->AddCurrentRuntimeFeaturesAsDex2OatArguments(&argv);
716 
717   if (!runtime->IsVerificationEnabled()) {
718     argv.push_back("--compiler-filter=verify-none");
719   }
720 
721   if (runtime->MustRelocateIfPossible()) {
722     argv.push_back("--runtime-arg");
723     argv.push_back("-Xrelocate");
724   } else {
725     argv.push_back("--runtime-arg");
726     argv.push_back("-Xnorelocate");
727   }
728 
729   if (!kIsTargetBuild) {
730     argv.push_back("--host");
731   }
732 
733   argv.push_back("--boot-image=" + image_location);
734 
735   std::vector<std::string> compiler_options = runtime->GetCompilerOptions();
736   argv.insert(argv.end(), compiler_options.begin(), compiler_options.end());
737 
738   argv.insert(argv.end(), args.begin(), args.end());
739 
740   std::string command_line(Join(argv, ' '));
741   return Exec(argv, error_msg);
742 }
743 
744 bool OatFileAssistant::DexFilenameToOdexFilename(const std::string& location,
745     InstructionSet isa, std::string* odex_filename, std::string* error_msg) {
746   CHECK(odex_filename != nullptr);
747   CHECK(error_msg != nullptr);
748 
749   // The odex file name is formed by replacing the dex_location extension with
750   // .odex and inserting an oat/<isa> directory. For example:
751   //   location = /foo/bar/baz.jar
752   //   odex_location = /foo/bar/oat/<isa>/baz.odex
753 
754   // Find the directory portion of the dex location and add the oat/<isa>
755   // directory.
756   size_t pos = location.rfind('/');
757   if (pos == std::string::npos) {
758     *error_msg = "Dex location " + location + " has no directory.";
759     return false;
760   }
761   std::string dir = location.substr(0, pos+1);
762   dir += "oat/" + std::string(GetInstructionSetString(isa));
763 
764   // Find the file portion of the dex location.
765   std::string file;
766   if (pos == std::string::npos) {
767     file = location;
768   } else {
769     file = location.substr(pos+1);
770   }
771 
772   // Get the base part of the file without the extension.
773   pos = file.rfind('.');
774   if (pos == std::string::npos) {
775     *error_msg = "Dex location " + location + " has no extension.";
776     return false;
777   }
778   std::string base = file.substr(0, pos);
779 
780   *odex_filename = dir + "/" + base + ".odex";
781   return true;
782 }
783 
784 std::string OatFileAssistant::DalvikCacheDirectory() {
785   // Note: We don't cache this, because it will only be called once by
786   // OatFileName, and we don't care about the performance of the profiling
787   // code, which isn't used in practice.
788 
789   // TODO: The work done in GetDalvikCache is overkill for what we need.
790   // Ideally a new API for getting the DalvikCacheDirectory the way we want
791   // (without existence testing, creation, or death) is provided with the rest
792   // of the GetDalvikCache family of functions. Until such an API is in place,
793   // we use GetDalvikCache to avoid duplicating the logic for determining the
794   // dalvik cache directory.
795   std::string result;
796   bool have_android_data;
797   bool dalvik_cache_exists;
798   bool is_global_cache;
799   GetDalvikCache("", false, &result, &have_android_data, &dalvik_cache_exists, &is_global_cache);
800   return result;
801 }
802 
803 std::string OatFileAssistant::ProfileFileName() {
804   if (package_name_ != nullptr) {
805     return DalvikCacheDirectory() + std::string("profiles/") + package_name_;
806   }
807   return "";
808 }
809 
810 std::string OatFileAssistant::OldProfileFileName() {
811   std::string profile_name = ProfileFileName();
812   if (profile_name.empty()) {
813     return "";
814   }
815   return profile_name + "@old";
816 }
817 
818 std::string OatFileAssistant::ImageLocation() {
819   Runtime* runtime = Runtime::Current();
820   const gc::space::ImageSpace* image_space = runtime->GetHeap()->GetImageSpace();
821   if (image_space == nullptr) {
822     return "";
823   }
824   return image_space->GetImageLocation();
825 }
826 
827 const uint32_t* OatFileAssistant::GetRequiredDexChecksum() {
828   if (!required_dex_checksum_attempted_) {
829     required_dex_checksum_attempted_ = true;
830     required_dex_checksum_found_ = false;
831     std::string error_msg;
832     CHECK(dex_location_ != nullptr) << "OatFileAssistant provided no dex location";
833     if (DexFile::GetChecksum(dex_location_, &cached_required_dex_checksum_, &error_msg)) {
834       required_dex_checksum_found_ = true;
835       has_original_dex_files_ = true;
836     } else {
837       // This can happen if the original dex file has been stripped from the
838       // apk.
839       VLOG(oat) << "OatFileAssistant: " << error_msg;
840       has_original_dex_files_ = false;
841 
842       // Get the checksum from the odex if we can.
843       const OatFile* odex_file = GetOdexFile();
844       if (odex_file != nullptr) {
845         const OatFile::OatDexFile* odex_dex_file = odex_file->GetOatDexFile(
846             dex_location_, nullptr, false);
847         if (odex_dex_file != nullptr) {
848           cached_required_dex_checksum_ = odex_dex_file->GetDexFileLocationChecksum();
849           required_dex_checksum_found_ = true;
850         }
851       }
852     }
853   }
854   return required_dex_checksum_found_ ? &cached_required_dex_checksum_ : nullptr;
855 }
856 
857 const OatFile* OatFileAssistant::GetOdexFile() {
858   CHECK(!oat_file_released_) << "OdexFile called after oat file released.";
859   if (!odex_file_load_attempted_) {
860     odex_file_load_attempted_ = true;
861     if (OdexFileName() != nullptr) {
862       const std::string& odex_file_name = *OdexFileName();
863       std::string error_msg;
864       cached_odex_file_.reset(OatFile::Open(odex_file_name.c_str(),
865             odex_file_name.c_str(), nullptr, nullptr, load_executable_,
866             dex_location_, &error_msg));
867       if (cached_odex_file_.get() == nullptr) {
868         VLOG(oat) << "OatFileAssistant test for existing pre-compiled oat file "
869           << odex_file_name << ": " << error_msg;
870       }
871     }
872   }
873   return cached_odex_file_.get();
874 }
875 
876 void OatFileAssistant::ClearOdexFileCache() {
877   odex_file_load_attempted_ = false;
878   cached_odex_file_.reset();
879   odex_file_is_out_of_date_attempted_ = false;
880   odex_file_is_up_to_date_attempted_ = false;
881 }
882 
883 const OatFile* OatFileAssistant::GetOatFile() {
884   CHECK(!oat_file_released_) << "OatFile called after oat file released.";
885   if (!oat_file_load_attempted_) {
886     oat_file_load_attempted_ = true;
887     if (OatFileName() != nullptr) {
888       const std::string& oat_file_name = *OatFileName();
889       std::string error_msg;
890       cached_oat_file_.reset(OatFile::Open(oat_file_name.c_str(),
891             oat_file_name.c_str(), nullptr, nullptr, load_executable_,
892             dex_location_, &error_msg));
893       if (cached_oat_file_.get() == nullptr) {
894         VLOG(oat) << "OatFileAssistant test for existing oat file "
895           << oat_file_name << ": " << error_msg;
896       }
897     }
898   }
899   return cached_oat_file_.get();
900 }
901 
902 void OatFileAssistant::ClearOatFileCache() {
903   oat_file_load_attempted_ = false;
904   cached_oat_file_.reset();
905   oat_file_is_out_of_date_attempted_ = false;
906   oat_file_is_up_to_date_attempted_ = false;
907 }
908 
909 const OatFileAssistant::ImageInfo* OatFileAssistant::GetImageInfo() {
910   if (!image_info_load_attempted_) {
911     image_info_load_attempted_ = true;
912 
913     Runtime* runtime = Runtime::Current();
914     const gc::space::ImageSpace* image_space = runtime->GetHeap()->GetImageSpace();
915     if (image_space != nullptr) {
916       cached_image_info_.location = image_space->GetImageLocation();
917 
918       if (isa_ == kRuntimeISA) {
919         const ImageHeader& image_header = image_space->GetImageHeader();
920         cached_image_info_.oat_checksum = image_header.GetOatChecksum();
921         cached_image_info_.oat_data_begin = reinterpret_cast<uintptr_t>(image_header.GetOatDataBegin());
922         cached_image_info_.patch_delta = image_header.GetPatchDelta();
923       } else {
924         std::unique_ptr<ImageHeader> image_header(
925             gc::space::ImageSpace::ReadImageHeaderOrDie(
926                 cached_image_info_.location.c_str(), isa_));
927         cached_image_info_.oat_checksum = image_header->GetOatChecksum();
928         cached_image_info_.oat_data_begin = reinterpret_cast<uintptr_t>(image_header->GetOatDataBegin());
929         cached_image_info_.patch_delta = image_header->GetPatchDelta();
930       }
931     }
932     image_info_load_succeeded_ = (image_space != nullptr);
933   }
934   return image_info_load_succeeded_ ? &cached_image_info_ : nullptr;
935 }
936 
937 ProfileFile* OatFileAssistant::GetProfile() {
938   if (!profile_load_attempted_) {
939     CHECK(package_name_ != nullptr)
940       << "pakage_name_ is nullptr: "
941       << "profile_load_attempted_ should have been true";
942     profile_load_attempted_ = true;
943     std::string profile_name = ProfileFileName();
944     if (!profile_name.empty()) {
945       profile_load_succeeded_ = cached_profile_.LoadFile(profile_name);
946     }
947   }
948   return profile_load_succeeded_ ? &cached_profile_ : nullptr;
949 }
950 
951 ProfileFile* OatFileAssistant::GetOldProfile() {
952   if (!old_profile_load_attempted_) {
953     CHECK(package_name_ != nullptr)
954       << "pakage_name_ is nullptr: "
955       << "old_profile_load_attempted_ should have been true";
956     old_profile_load_attempted_ = true;
957     std::string old_profile_name = OldProfileFileName();
958     if (!old_profile_name.empty()) {
959       old_profile_load_succeeded_ = cached_old_profile_.LoadFile(old_profile_name);
960     }
961   }
962   return old_profile_load_succeeded_ ? &cached_old_profile_ : nullptr;
963 }
964 
965 }  // namespace art
966 
967