oat_file_assistant.cc revision dcdc85bbd569f0ee66c331b4219c19304a616214
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  Runtime* runtime = Runtime::Current();
666  if (!runtime->IsDex2OatEnabled()) {
667    *error_msg = "Generation of oat file for dex location " + dex_location_
668      + " not attempted because dex2oat is disabled.";
669    return false;
670  }
671
672  if (OatFileName() == nullptr) {
673    *error_msg = "Generation of oat file for dex location " + dex_location_
674      + " not attempted because the oat file name could not be determined.";
675    return false;
676  }
677  const std::string& oat_file_name = *OatFileName();
678
679  // dex2oat ignores missing dex files and doesn't report an error.
680  // Check explicitly here so we can detect the error properly.
681  // TODO: Why does dex2oat behave that way?
682  if (!OS::FileExists(dex_location_.c_str())) {
683    *error_msg = "Dex location " + dex_location_ + " does not exists.";
684    return false;
685  }
686
687  std::unique_ptr<File> oat_file;
688  oat_file.reset(OS::CreateEmptyFile(oat_file_name.c_str()));
689  if (oat_file.get() == nullptr) {
690    *error_msg = "Generation of oat file " + oat_file_name
691      + " not attempted because the oat file could not be created.";
692    return false;
693  }
694
695  if (fchmod(oat_file->Fd(), 0644) != 0) {
696    *error_msg = "Generation of oat file " + oat_file_name
697      + " not attempted because the oat file could not be made world readable.";
698    oat_file->Erase();
699    return false;
700  }
701
702  std::vector<std::string> args;
703  args.push_back("--dex-file=" + dex_location_);
704  args.push_back("--oat-fd=" + std::to_string(oat_file->Fd()));
705  args.push_back("--oat-location=" + oat_file_name);
706
707  if (!Dex2Oat(args, error_msg)) {
708    // Manually delete the file. This ensures there is no garbage left over if
709    // the process unexpectedly died.
710    oat_file->Erase();
711    TEMP_FAILURE_RETRY(unlink(oat_file_name.c_str()));
712    return false;
713  }
714
715  if (oat_file->FlushCloseOrErase() != 0) {
716    *error_msg = "Unable to close oat file " + oat_file_name;
717    TEMP_FAILURE_RETRY(unlink(oat_file_name.c_str()));
718    return false;
719  }
720
721  // Mark that the oat file has changed and we should try to reload.
722  ClearOatFileCache();
723  return true;
724}
725
726bool OatFileAssistant::Dex2Oat(const std::vector<std::string>& args,
727                               std::string* error_msg) {
728  Runtime* runtime = Runtime::Current();
729  std::string image_location = ImageLocation();
730  if (image_location.empty()) {
731    *error_msg = "No image location found for Dex2Oat.";
732    return false;
733  }
734
735  std::vector<std::string> argv;
736  argv.push_back(runtime->GetCompilerExecutable());
737  argv.push_back("--runtime-arg");
738  argv.push_back("-classpath");
739  argv.push_back("--runtime-arg");
740  argv.push_back(runtime->GetClassPathString());
741  if (runtime->IsDebuggable()) {
742    argv.push_back("--debuggable");
743  }
744  runtime->AddCurrentRuntimeFeaturesAsDex2OatArguments(&argv);
745
746  if (!runtime->IsVerificationEnabled()) {
747    argv.push_back("--compiler-filter=verify-none");
748  }
749
750  if (runtime->MustRelocateIfPossible()) {
751    argv.push_back("--runtime-arg");
752    argv.push_back("-Xrelocate");
753  } else {
754    argv.push_back("--runtime-arg");
755    argv.push_back("-Xnorelocate");
756  }
757
758  if (!kIsTargetBuild) {
759    argv.push_back("--host");
760  }
761
762  argv.push_back("--boot-image=" + image_location);
763
764  std::vector<std::string> compiler_options = runtime->GetCompilerOptions();
765  argv.insert(argv.end(), compiler_options.begin(), compiler_options.end());
766
767  argv.insert(argv.end(), args.begin(), args.end());
768
769  std::string command_line(Join(argv, ' '));
770  return Exec(argv, error_msg);
771}
772
773bool OatFileAssistant::DexFilenameToOdexFilename(const std::string& location,
774    InstructionSet isa, std::string* odex_filename, std::string* error_msg) {
775  CHECK(odex_filename != nullptr);
776  CHECK(error_msg != nullptr);
777
778  // The odex file name is formed by replacing the dex_location extension with
779  // .odex and inserting an oat/<isa> directory. For example:
780  //   location = /foo/bar/baz.jar
781  //   odex_location = /foo/bar/oat/<isa>/baz.odex
782
783  // Find the directory portion of the dex location and add the oat/<isa>
784  // directory.
785  size_t pos = location.rfind('/');
786  if (pos == std::string::npos) {
787    *error_msg = "Dex location " + location + " has no directory.";
788    return false;
789  }
790  std::string dir = location.substr(0, pos+1);
791  dir += "oat/" + std::string(GetInstructionSetString(isa));
792
793  // Find the file portion of the dex location.
794  std::string file;
795  if (pos == std::string::npos) {
796    file = location;
797  } else {
798    file = location.substr(pos+1);
799  }
800
801  // Get the base part of the file without the extension.
802  pos = file.rfind('.');
803  if (pos == std::string::npos) {
804    *error_msg = "Dex location " + location + " has no extension.";
805    return false;
806  }
807  std::string base = file.substr(0, pos);
808
809  *odex_filename = dir + "/" + base + ".odex";
810  return true;
811}
812
813std::string OatFileAssistant::DalvikCacheDirectory() {
814  // Note: We don't cache this, because it will only be called once by
815  // OatFileName, and we don't care about the performance of the profiling
816  // code, which isn't used in practice.
817
818  // TODO: The work done in GetDalvikCache is overkill for what we need.
819  // Ideally a new API for getting the DalvikCacheDirectory the way we want
820  // (without existence testing, creation, or death) is provided with the rest
821  // of the GetDalvikCache family of functions. Until such an API is in place,
822  // we use GetDalvikCache to avoid duplicating the logic for determining the
823  // dalvik cache directory.
824  std::string result;
825  bool have_android_data;
826  bool dalvik_cache_exists;
827  bool is_global_cache;
828  GetDalvikCache("", false, &result, &have_android_data, &dalvik_cache_exists, &is_global_cache);
829  return result;
830}
831
832std::string OatFileAssistant::ProfileFileName() {
833  if (package_name_ != nullptr) {
834    return DalvikCacheDirectory() + std::string("profiles/") + package_name_;
835  }
836  return "";
837}
838
839std::string OatFileAssistant::OldProfileFileName() {
840  std::string profile_name = ProfileFileName();
841  if (profile_name.empty()) {
842    return "";
843  }
844  return profile_name + "@old";
845}
846
847std::string OatFileAssistant::ImageLocation() {
848  Runtime* runtime = Runtime::Current();
849  return runtime->GetHeap()->GetBootImageSpaces()[0]->GetImageLocation();
850}
851
852const uint32_t* OatFileAssistant::GetRequiredDexChecksum() {
853  if (!required_dex_checksum_attempted_) {
854    required_dex_checksum_attempted_ = true;
855    required_dex_checksum_found_ = false;
856    std::string error_msg;
857    if (DexFile::GetChecksum(dex_location_.c_str(), &cached_required_dex_checksum_, &error_msg)) {
858      required_dex_checksum_found_ = true;
859      has_original_dex_files_ = true;
860    } else {
861      // This can happen if the original dex file has been stripped from the
862      // apk.
863      VLOG(oat) << "OatFileAssistant: " << error_msg;
864      has_original_dex_files_ = false;
865
866      // Get the checksum from the odex if we can.
867      const OatFile* odex_file = GetOdexFile();
868      if (odex_file != nullptr) {
869        const OatFile::OatDexFile* odex_dex_file = odex_file->GetOatDexFile(
870            dex_location_.c_str(), nullptr, false);
871        if (odex_dex_file != nullptr) {
872          cached_required_dex_checksum_ = odex_dex_file->GetDexFileLocationChecksum();
873          required_dex_checksum_found_ = true;
874        }
875      }
876    }
877  }
878  return required_dex_checksum_found_ ? &cached_required_dex_checksum_ : nullptr;
879}
880
881const OatFile* OatFileAssistant::GetOdexFile() {
882  CHECK(!oat_file_released_) << "OdexFile called after oat file released.";
883  if (!odex_file_load_attempted_) {
884    odex_file_load_attempted_ = true;
885    if (OdexFileName() != nullptr) {
886      const std::string& odex_file_name = *OdexFileName();
887      std::string error_msg;
888      cached_odex_file_.reset(OatFile::Open(odex_file_name.c_str(),
889            odex_file_name.c_str(), nullptr, nullptr, load_executable_,
890            dex_location_.c_str(), &error_msg));
891      if (cached_odex_file_.get() == nullptr) {
892        VLOG(oat) << "OatFileAssistant test for existing pre-compiled oat file "
893          << odex_file_name << ": " << error_msg;
894      }
895    }
896  }
897  return cached_odex_file_.get();
898}
899
900bool OatFileAssistant::OdexFileIsExecutable() {
901  const OatFile* odex_file = GetOdexFile();
902  return (odex_file != nullptr && odex_file->IsExecutable());
903}
904
905void OatFileAssistant::ClearOdexFileCache() {
906  odex_file_load_attempted_ = false;
907  cached_odex_file_.reset();
908  odex_file_is_out_of_date_attempted_ = false;
909  odex_file_is_up_to_date_attempted_ = false;
910}
911
912const OatFile* OatFileAssistant::GetOatFile() {
913  CHECK(!oat_file_released_) << "OatFile called after oat file released.";
914  if (!oat_file_load_attempted_) {
915    oat_file_load_attempted_ = true;
916    if (OatFileName() != nullptr) {
917      const std::string& oat_file_name = *OatFileName();
918      std::string error_msg;
919      cached_oat_file_.reset(OatFile::Open(oat_file_name.c_str(),
920            oat_file_name.c_str(), nullptr, nullptr, load_executable_,
921            dex_location_.c_str(), &error_msg));
922      if (cached_oat_file_.get() == nullptr) {
923        VLOG(oat) << "OatFileAssistant test for existing oat file "
924          << oat_file_name << ": " << error_msg;
925      }
926    }
927  }
928  return cached_oat_file_.get();
929}
930
931bool OatFileAssistant::OatFileIsExecutable() {
932  const OatFile* oat_file = GetOatFile();
933  return (oat_file != nullptr && oat_file->IsExecutable());
934}
935
936void OatFileAssistant::ClearOatFileCache() {
937  oat_file_load_attempted_ = false;
938  cached_oat_file_.reset();
939  oat_file_is_out_of_date_attempted_ = false;
940  oat_file_is_up_to_date_attempted_ = false;
941}
942
943const OatFileAssistant::ImageInfo* OatFileAssistant::GetImageInfo() {
944  if (!image_info_load_attempted_) {
945    image_info_load_attempted_ = true;
946
947    Runtime* runtime = Runtime::Current();
948    std::vector<gc::space::ImageSpace*> image_spaces = runtime->GetHeap()->GetBootImageSpaces();
949    if (!image_spaces.empty()) {
950      // TODO: Better support multi-images? b/26317072
951      cached_image_info_.location = image_spaces[0]->GetImageLocation();
952
953      if (isa_ == kRuntimeISA) {
954        const ImageHeader& image_header = image_spaces[0]->GetImageHeader();
955        cached_image_info_.oat_checksum = image_header.GetOatChecksum();
956        cached_image_info_.oat_data_begin = reinterpret_cast<uintptr_t>(
957            image_header.GetOatDataBegin());
958        cached_image_info_.patch_delta = image_header.GetPatchDelta();
959      } else {
960        std::unique_ptr<ImageHeader> image_header(
961            gc::space::ImageSpace::ReadImageHeaderOrDie(
962                cached_image_info_.location.c_str(), isa_));
963        cached_image_info_.oat_checksum = image_header->GetOatChecksum();
964        cached_image_info_.oat_data_begin = reinterpret_cast<uintptr_t>(
965            image_header->GetOatDataBegin());
966        cached_image_info_.patch_delta = image_header->GetPatchDelta();
967      }
968    }
969    image_info_load_succeeded_ = (!image_spaces.empty());
970  }
971  return image_info_load_succeeded_ ? &cached_image_info_ : nullptr;
972}
973
974ProfileFile* OatFileAssistant::GetProfile() {
975  if (!profile_load_attempted_) {
976    CHECK(package_name_ != nullptr)
977      << "pakage_name_ is nullptr: "
978      << "profile_load_attempted_ should have been true";
979    profile_load_attempted_ = true;
980    std::string profile_name = ProfileFileName();
981    if (!profile_name.empty()) {
982      profile_load_succeeded_ = cached_profile_.LoadFile(profile_name);
983    }
984  }
985  return profile_load_succeeded_ ? &cached_profile_ : nullptr;
986}
987
988ProfileFile* OatFileAssistant::GetOldProfile() {
989  if (!old_profile_load_attempted_) {
990    CHECK(package_name_ != nullptr)
991      << "pakage_name_ is nullptr: "
992      << "old_profile_load_attempted_ should have been true";
993    old_profile_load_attempted_ = true;
994    std::string old_profile_name = OldProfileFileName();
995    if (!old_profile_name.empty()) {
996      old_profile_load_succeeded_ = cached_old_profile_.LoadFile(old_profile_name);
997    }
998  }
999  return old_profile_load_succeeded_ ? &cached_old_profile_ : nullptr;
1000}
1001
1002}  // namespace art
1003
1004