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