image_space.cc revision b6cabc1345ec307559a6e85141fb69b7caa9413c
1/*
2 * Copyright (C) 2011 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 "image_space.h"
18
19#include <random>
20
21#include "base/stl_util.h"
22#include "base/unix_file/fd_file.h"
23#include "base/scoped_flock.h"
24#include "gc/accounting/space_bitmap-inl.h"
25#include "mirror/art_method.h"
26#include "mirror/class-inl.h"
27#include "mirror/object-inl.h"
28#include "oat_file.h"
29#include "os.h"
30#include "space-inl.h"
31#include "utils.h"
32
33namespace art {
34namespace gc {
35namespace space {
36
37Atomic<uint32_t> ImageSpace::bitmap_index_(0);
38
39ImageSpace::ImageSpace(const std::string& image_filename, const char* image_location,
40                       MemMap* mem_map, accounting::ContinuousSpaceBitmap* live_bitmap)
41    : MemMapSpace(image_filename, mem_map, mem_map->Begin(), mem_map->End(), mem_map->End(),
42                  kGcRetentionPolicyNeverCollect),
43      image_location_(image_location) {
44  DCHECK(live_bitmap != nullptr);
45  live_bitmap_.reset(live_bitmap);
46}
47
48static int32_t ChooseRelocationOffsetDelta(int32_t min_delta, int32_t max_delta) {
49  CHECK_ALIGNED(min_delta, kPageSize);
50  CHECK_ALIGNED(max_delta, kPageSize);
51  CHECK_LT(min_delta, max_delta);
52
53  std::default_random_engine generator;
54  generator.seed(NanoTime() * getpid());
55  std::uniform_int_distribution<int32_t> distribution(min_delta, max_delta);
56  int32_t r = distribution(generator);
57  if (r % 2 == 0) {
58    r = RoundUp(r, kPageSize);
59  } else {
60    r = RoundDown(r, kPageSize);
61  }
62  CHECK_LE(min_delta, r);
63  CHECK_GE(max_delta, r);
64  CHECK_ALIGNED(r, kPageSize);
65  return r;
66}
67
68static bool GenerateImage(const std::string& image_filename, std::string* error_msg) {
69  const std::string boot_class_path_string(Runtime::Current()->GetBootClassPathString());
70  std::vector<std::string> boot_class_path;
71  Split(boot_class_path_string, ':', boot_class_path);
72  if (boot_class_path.empty()) {
73    *error_msg = "Failed to generate image because no boot class path specified";
74    return false;
75  }
76
77  std::vector<std::string> arg_vector;
78
79  std::string dex2oat(Runtime::Current()->GetCompilerExecutable());
80  arg_vector.push_back(dex2oat);
81
82  std::string image_option_string("--image=");
83  image_option_string += image_filename;
84  arg_vector.push_back(image_option_string);
85
86  for (size_t i = 0; i < boot_class_path.size(); i++) {
87    arg_vector.push_back(std::string("--dex-file=") + boot_class_path[i]);
88  }
89
90  std::string oat_file_option_string("--oat-file=");
91  oat_file_option_string += image_filename;
92  oat_file_option_string.erase(oat_file_option_string.size() - 3);
93  oat_file_option_string += "oat";
94  arg_vector.push_back(oat_file_option_string);
95
96  Runtime::Current()->AddCurrentRuntimeFeaturesAsDex2OatArguments(&arg_vector);
97
98  int32_t base_offset = ChooseRelocationOffsetDelta(ART_BASE_ADDRESS_MIN_DELTA,
99                                                    ART_BASE_ADDRESS_MAX_DELTA);
100  LOG(INFO) << "Using an offset of 0x" << std::hex << base_offset << " from default "
101            << "art base address of 0x" << std::hex << ART_BASE_ADDRESS;
102  arg_vector.push_back(StringPrintf("--base=0x%x", ART_BASE_ADDRESS + base_offset));
103
104  if (!kIsTargetBuild) {
105    arg_vector.push_back("--host");
106  }
107
108  const std::vector<std::string>& compiler_options = Runtime::Current()->GetImageCompilerOptions();
109  for (size_t i = 0; i < compiler_options.size(); ++i) {
110    arg_vector.push_back(compiler_options[i].c_str());
111  }
112
113  std::string command_line(Join(arg_vector, ' '));
114  LOG(INFO) << "GenerateImage: " << command_line;
115  return Exec(arg_vector, error_msg);
116}
117
118bool ImageSpace::FindImageFilename(const char* image_location,
119                                   const InstructionSet image_isa,
120                                   std::string* system_filename,
121                                   bool* has_system,
122                                   std::string* cache_filename,
123                                   bool* dalvik_cache_exists,
124                                   bool* has_cache) {
125  *has_system = false;
126  *has_cache = false;
127  // image_location = /system/framework/boot.art
128  // system_image_location = /system/framework/<image_isa>/boot.art
129  std::string system_image_filename(GetSystemImageFilename(image_location, image_isa));
130  if (OS::FileExists(system_image_filename.c_str())) {
131    *system_filename = system_image_filename;
132    *has_system = true;
133  }
134
135  bool have_android_data = false;
136  *dalvik_cache_exists = false;
137  std::string dalvik_cache;
138  GetDalvikCache(GetInstructionSetString(image_isa), true, &dalvik_cache,
139                 &have_android_data, dalvik_cache_exists);
140
141  if (have_android_data && *dalvik_cache_exists) {
142    // Always set output location even if it does not exist,
143    // so that the caller knows where to create the image.
144    //
145    // image_location = /system/framework/boot.art
146    // *image_filename = /data/dalvik-cache/<image_isa>/boot.art
147    std::string error_msg;
148    if (!GetDalvikCacheFilename(image_location, dalvik_cache.c_str(), cache_filename, &error_msg)) {
149      LOG(WARNING) << error_msg;
150      return *has_system;
151    }
152    *has_cache = OS::FileExists(cache_filename->c_str());
153  }
154  return *has_system || *has_cache;
155}
156
157static bool ReadSpecificImageHeader(const char* filename, ImageHeader* image_header) {
158    std::unique_ptr<File> image_file(OS::OpenFileForReading(filename));
159    if (image_file.get() == nullptr) {
160      return false;
161    }
162    const bool success = image_file->ReadFully(image_header, sizeof(ImageHeader));
163    if (!success || !image_header->IsValid()) {
164      return false;
165    }
166    return true;
167}
168
169// Relocate the image at image_location to dest_filename and relocate it by a random amount.
170static bool RelocateImage(const char* image_location, const char* dest_filename,
171                               InstructionSet isa, std::string* error_msg) {
172  std::string patchoat(Runtime::Current()->GetPatchoatExecutable());
173
174  std::string input_image_location_arg("--input-image-location=");
175  input_image_location_arg += image_location;
176
177  std::string output_image_filename_arg("--output-image-file=");
178  output_image_filename_arg += dest_filename;
179
180  std::string input_oat_location_arg("--input-oat-location=");
181  input_oat_location_arg += ImageHeader::GetOatLocationFromImageLocation(image_location);
182
183  std::string output_oat_filename_arg("--output-oat-file=");
184  output_oat_filename_arg += ImageHeader::GetOatLocationFromImageLocation(dest_filename);
185
186  std::string instruction_set_arg("--instruction-set=");
187  instruction_set_arg += GetInstructionSetString(isa);
188
189  std::string base_offset_arg("--base-offset-delta=");
190  StringAppendF(&base_offset_arg, "%d", ChooseRelocationOffsetDelta(ART_BASE_ADDRESS_MIN_DELTA,
191                                                                    ART_BASE_ADDRESS_MAX_DELTA));
192
193  std::vector<std::string> argv;
194  argv.push_back(patchoat);
195
196  argv.push_back(input_image_location_arg);
197  argv.push_back(output_image_filename_arg);
198
199  argv.push_back(input_oat_location_arg);
200  argv.push_back(output_oat_filename_arg);
201
202  argv.push_back(instruction_set_arg);
203  argv.push_back(base_offset_arg);
204
205  std::string command_line(Join(argv, ' '));
206  LOG(INFO) << "RelocateImage: " << command_line;
207  return Exec(argv, error_msg);
208}
209
210static ImageHeader* ReadSpecificImageHeaderOrDie(const char* filename) {
211  std::unique_ptr<ImageHeader> hdr(new ImageHeader);
212  if (!ReadSpecificImageHeader(filename, hdr.get())) {
213    LOG(FATAL) << "Unable to read image header for " << filename;
214    return nullptr;
215  }
216  return hdr.release();
217}
218
219ImageHeader* ImageSpace::ReadImageHeaderOrDie(const char* image_location,
220                                              const InstructionSet image_isa) {
221  std::string system_filename;
222  bool has_system = false;
223  std::string cache_filename;
224  bool has_cache = false;
225  bool dalvik_cache_exists = false;
226  if (FindImageFilename(image_location, image_isa, &system_filename, &has_system,
227                        &cache_filename, &dalvik_cache_exists, &has_cache)) {
228    if (Runtime::Current()->ShouldRelocate()) {
229      if (has_system && has_cache) {
230        std::unique_ptr<ImageHeader> sys_hdr(new ImageHeader);
231        std::unique_ptr<ImageHeader> cache_hdr(new ImageHeader);
232        if (!ReadSpecificImageHeader(system_filename.c_str(), sys_hdr.get())) {
233          LOG(FATAL) << "Unable to read image header for " << image_location << " at "
234                     << system_filename;
235          return nullptr;
236        }
237        if (!ReadSpecificImageHeader(cache_filename.c_str(), cache_hdr.get())) {
238          LOG(FATAL) << "Unable to read image header for " << image_location << " at "
239                     << cache_filename;
240          return nullptr;
241        }
242        if (sys_hdr->GetOatChecksum() != cache_hdr->GetOatChecksum()) {
243          LOG(FATAL) << "Unable to find a relocated version of image file " << image_location;
244          return nullptr;
245        }
246        return cache_hdr.release();
247      } else if (!has_cache) {
248        LOG(FATAL) << "Unable to find a relocated version of image file " << image_location;
249        return nullptr;
250      } else if (!has_system && has_cache) {
251        // This can probably just use the cache one.
252        return ReadSpecificImageHeaderOrDie(cache_filename.c_str());
253      }
254    } else {
255      // We don't want to relocate, Just pick the appropriate one if we have it and return.
256      if (has_system && has_cache) {
257        // We want the cache if the checksum matches, otherwise the system.
258        std::unique_ptr<ImageHeader> system(ReadSpecificImageHeaderOrDie(system_filename.c_str()));
259        std::unique_ptr<ImageHeader> cache(ReadSpecificImageHeaderOrDie(cache_filename.c_str()));
260        if (system.get() == nullptr ||
261            (cache.get() != nullptr && cache->GetOatChecksum() == system->GetOatChecksum())) {
262          return cache.release();
263        } else {
264          return system.release();
265        }
266      } else if (has_system) {
267        return ReadSpecificImageHeaderOrDie(system_filename.c_str());
268      } else if (has_cache) {
269        return ReadSpecificImageHeaderOrDie(cache_filename.c_str());
270      }
271    }
272  }
273
274  LOG(FATAL) << "Unable to find image file for: " << image_location;
275  return nullptr;
276}
277
278static bool ChecksumsMatch(const char* image_a, const char* image_b) {
279  ImageHeader hdr_a;
280  ImageHeader hdr_b;
281  return ReadSpecificImageHeader(image_a, &hdr_a) && ReadSpecificImageHeader(image_b, &hdr_b)
282      && hdr_a.GetOatChecksum() == hdr_b.GetOatChecksum();
283}
284
285ImageSpace* ImageSpace::Create(const char* image_location,
286                               const InstructionSet image_isa,
287                               std::string* error_msg) {
288  std::string system_filename;
289  bool has_system = false;
290  std::string cache_filename;
291  bool has_cache = false;
292  bool dalvik_cache_exists = false;
293  const bool found_image = FindImageFilename(image_location, image_isa, &system_filename,
294                                             &has_system, &cache_filename, &dalvik_cache_exists,
295                                             &has_cache);
296
297  ImageSpace* space;
298  bool relocate = Runtime::Current()->ShouldRelocate();
299  bool can_compile = Runtime::Current()->IsImageDex2OatEnabled();
300  if (found_image) {
301    const std::string* image_filename;
302    bool is_system = false;
303    bool relocated_version_used = false;
304    if (relocate) {
305      if (!dalvik_cache_exists) {
306        *error_msg = StringPrintf("Requiring relocation for image '%s' at '%s' but we do not have "
307                                  "any dalvik_cache to find/place it in.",
308                                  image_location, system_filename.c_str());
309        return nullptr;
310      }
311      if (has_system) {
312        if (has_cache && ChecksumsMatch(system_filename.c_str(), cache_filename.c_str())) {
313          // We already have a relocated version
314          image_filename = &cache_filename;
315          relocated_version_used = true;
316        } else {
317          // We cannot have a relocated version, Relocate the system one and use it.
318          if (can_compile && RelocateImage(image_location, cache_filename.c_str(), image_isa,
319                                           error_msg)) {
320            relocated_version_used = true;
321            image_filename = &cache_filename;
322          } else {
323            std::string reason;
324            if (can_compile) {
325              reason = StringPrintf(": %s", error_msg->c_str());
326            } else {
327              reason = " because image dex2oat is disabled.";
328            }
329            *error_msg = StringPrintf("Unable to relocate image '%s' from '%s' to '%s'%s",
330                                      image_location, system_filename.c_str(),
331                                      cache_filename.c_str(), reason.c_str());
332            return nullptr;
333          }
334        }
335      } else {
336        CHECK(has_cache);
337        // We can just use cache's since it should be fine. This might or might not be relocated.
338        image_filename = &cache_filename;
339      }
340    } else {
341      if (has_system && has_cache) {
342        // Check they have the same cksum. If they do use the cache. Otherwise system.
343        if (ChecksumsMatch(system_filename.c_str(), cache_filename.c_str())) {
344          image_filename = &cache_filename;
345          relocated_version_used = true;
346        } else {
347          image_filename = &system_filename;
348          is_system = true;
349        }
350      } else if (has_system) {
351        image_filename = &system_filename;
352        is_system = true;
353      } else {
354        CHECK(has_cache);
355        image_filename = &cache_filename;
356      }
357    }
358    {
359      // Note that we must not use the file descriptor associated with
360      // ScopedFlock::GetFile to Init the image file. We want the file
361      // descriptor (and the associated exclusive lock) to be released when
362      // we leave Create.
363      ScopedFlock image_lock;
364      image_lock.Init(image_filename->c_str(), error_msg);
365      VLOG(startup) << "Using image file " << image_filename->c_str() << " for image location "
366                    << image_location;
367      // If we are in /system we can assume the image is good. We can also
368      // assume this if we are using a relocated image (i.e. image checksum
369      // matches) since this is only different by the offset. We need this to
370      // make sure that host tests continue to work.
371      space = ImageSpace::Init(image_filename->c_str(), image_location,
372                               !(is_system || relocated_version_used), error_msg);
373    }
374    if (space != nullptr) {
375      return space;
376    }
377
378    // If the /system file exists, it should be up-to-date, don't try to generate it. Same if it is
379    // a relocated copy from something in /system (i.e. checksum's match).
380    // Otherwise, log a warning and fall through to GenerateImage.
381    if (relocated_version_used) {
382      LOG(FATAL) << "Attempted to use relocated version of " << image_location << " "
383                 << "at " << cache_filename << " generated from " << system_filename << " "
384                 << "but image failed to load: " << error_msg;
385      return nullptr;
386    } else if (is_system) {
387      *error_msg = StringPrintf("Failed to load /system image '%s': %s",
388                                image_filename->c_str(), error_msg->c_str());
389      return nullptr;
390    } else {
391      LOG(WARNING) << *error_msg;
392    }
393  }
394
395  if (!can_compile) {
396    *error_msg = "Not attempting to compile image because -Xnoimage-dex2oat";
397    return nullptr;
398  } else if (!dalvik_cache_exists) {
399    *error_msg = StringPrintf("No place to put generated image.");
400    return nullptr;
401  } else if (!GenerateImage(cache_filename, error_msg)) {
402    *error_msg = StringPrintf("Failed to generate image '%s': %s",
403                              cache_filename.c_str(), error_msg->c_str());
404    return nullptr;
405  } else {
406    // Note that we must not use the file descriptor associated with
407    // ScopedFlock::GetFile to Init the image file. We want the file
408    // descriptor (and the associated exclusive lock) to be released when
409    // we leave Create.
410    ScopedFlock image_lock;
411    image_lock.Init(cache_filename.c_str(), error_msg);
412    space = ImageSpace::Init(cache_filename.c_str(), image_location, true, error_msg);
413    if (space == nullptr) {
414      *error_msg = StringPrintf("Failed to load generated image '%s': %s",
415                                cache_filename.c_str(), error_msg->c_str());
416    }
417    return space;
418  }
419}
420
421void ImageSpace::VerifyImageAllocations() {
422  byte* current = Begin() + RoundUp(sizeof(ImageHeader), kObjectAlignment);
423  while (current < End()) {
424    DCHECK_ALIGNED(current, kObjectAlignment);
425    mirror::Object* obj = reinterpret_cast<mirror::Object*>(current);
426    CHECK(live_bitmap_->Test(obj));
427    CHECK(obj->GetClass() != nullptr) << "Image object at address " << obj << " has null class";
428    if (kUseBakerOrBrooksReadBarrier) {
429      obj->AssertReadBarrierPointer();
430    }
431    current += RoundUp(obj->SizeOf(), kObjectAlignment);
432  }
433}
434
435ImageSpace* ImageSpace::Init(const char* image_filename, const char* image_location,
436                             bool validate_oat_file, std::string* error_msg) {
437  CHECK(image_filename != nullptr);
438  CHECK(image_location != nullptr);
439
440  uint64_t start_time = 0;
441  if (VLOG_IS_ON(heap) || VLOG_IS_ON(startup)) {
442    start_time = NanoTime();
443    LOG(INFO) << "ImageSpace::Init entering image_filename=" << image_filename;
444  }
445
446  std::unique_ptr<File> file(OS::OpenFileForReading(image_filename));
447  if (file.get() == NULL) {
448    *error_msg = StringPrintf("Failed to open '%s'", image_filename);
449    return nullptr;
450  }
451  ImageHeader image_header;
452  bool success = file->ReadFully(&image_header, sizeof(image_header));
453  if (!success || !image_header.IsValid()) {
454    *error_msg = StringPrintf("Invalid image header in '%s'", image_filename);
455    return nullptr;
456  }
457
458  // Note: The image header is part of the image due to mmap page alignment required of offset.
459  std::unique_ptr<MemMap> map(MemMap::MapFileAtAddress(image_header.GetImageBegin(),
460                                                 image_header.GetImageSize(),
461                                                 PROT_READ | PROT_WRITE,
462                                                 MAP_PRIVATE,
463                                                 file->Fd(),
464                                                 0,
465                                                 false,
466                                                 image_filename,
467                                                 error_msg));
468  if (map.get() == NULL) {
469    DCHECK(!error_msg->empty());
470    return nullptr;
471  }
472  CHECK_EQ(image_header.GetImageBegin(), map->Begin());
473  DCHECK_EQ(0, memcmp(&image_header, map->Begin(), sizeof(ImageHeader)));
474
475  std::unique_ptr<MemMap> image_map(MemMap::MapFileAtAddress(nullptr, image_header.GetImageBitmapSize(),
476                                                       PROT_READ, MAP_PRIVATE,
477                                                       file->Fd(), image_header.GetBitmapOffset(),
478                                                       false,
479                                                       image_filename,
480                                                       error_msg));
481  if (image_map.get() == nullptr) {
482    *error_msg = StringPrintf("Failed to map image bitmap: %s", error_msg->c_str());
483    return nullptr;
484  }
485  uint32_t bitmap_index = bitmap_index_.FetchAndAddSequentiallyConsistent(1);
486  std::string bitmap_name(StringPrintf("imagespace %s live-bitmap %u", image_filename,
487                                       bitmap_index));
488  std::unique_ptr<accounting::ContinuousSpaceBitmap> bitmap(
489      accounting::ContinuousSpaceBitmap::CreateFromMemMap(bitmap_name, image_map.release(),
490                                                          reinterpret_cast<byte*>(map->Begin()),
491                                                          map->Size()));
492  if (bitmap.get() == nullptr) {
493    *error_msg = StringPrintf("Could not create bitmap '%s'", bitmap_name.c_str());
494    return nullptr;
495  }
496
497  std::unique_ptr<ImageSpace> space(new ImageSpace(image_filename, image_location,
498                                             map.release(), bitmap.release()));
499
500  // VerifyImageAllocations() will be called later in Runtime::Init()
501  // as some class roots like ArtMethod::java_lang_reflect_ArtMethod_
502  // and ArtField::java_lang_reflect_ArtField_, which are used from
503  // Object::SizeOf() which VerifyImageAllocations() calls, are not
504  // set yet at this point.
505
506  space->oat_file_.reset(space->OpenOatFile(image_filename, error_msg));
507  if (space->oat_file_.get() == nullptr) {
508    DCHECK(!error_msg->empty());
509    return nullptr;
510  }
511
512  if (validate_oat_file && !space->ValidateOatFile(error_msg)) {
513    DCHECK(!error_msg->empty());
514    return nullptr;
515  }
516
517  Runtime* runtime = Runtime::Current();
518  runtime->SetInstructionSet(space->oat_file_->GetOatHeader().GetInstructionSet());
519
520  mirror::Object* resolution_method = image_header.GetImageRoot(ImageHeader::kResolutionMethod);
521  runtime->SetResolutionMethod(down_cast<mirror::ArtMethod*>(resolution_method));
522  mirror::Object* imt_conflict_method = image_header.GetImageRoot(ImageHeader::kImtConflictMethod);
523  runtime->SetImtConflictMethod(down_cast<mirror::ArtMethod*>(imt_conflict_method));
524  mirror::Object* default_imt = image_header.GetImageRoot(ImageHeader::kDefaultImt);
525  runtime->SetDefaultImt(down_cast<mirror::ObjectArray<mirror::ArtMethod>*>(default_imt));
526
527  mirror::Object* callee_save_method = image_header.GetImageRoot(ImageHeader::kCalleeSaveMethod);
528  runtime->SetCalleeSaveMethod(down_cast<mirror::ArtMethod*>(callee_save_method), Runtime::kSaveAll);
529  callee_save_method = image_header.GetImageRoot(ImageHeader::kRefsOnlySaveMethod);
530  runtime->SetCalleeSaveMethod(down_cast<mirror::ArtMethod*>(callee_save_method), Runtime::kRefsOnly);
531  callee_save_method = image_header.GetImageRoot(ImageHeader::kRefsAndArgsSaveMethod);
532  runtime->SetCalleeSaveMethod(down_cast<mirror::ArtMethod*>(callee_save_method), Runtime::kRefsAndArgs);
533
534  if (VLOG_IS_ON(heap) || VLOG_IS_ON(startup)) {
535    LOG(INFO) << "ImageSpace::Init exiting (" << PrettyDuration(NanoTime() - start_time)
536             << ") " << *space.get();
537  }
538  return space.release();
539}
540
541OatFile* ImageSpace::OpenOatFile(const char* image_path, std::string* error_msg) const {
542  const ImageHeader& image_header = GetImageHeader();
543  std::string oat_filename = ImageHeader::GetOatLocationFromImageLocation(image_path);
544
545  OatFile* oat_file = OatFile::Open(oat_filename, oat_filename, image_header.GetOatDataBegin(),
546                                    !Runtime::Current()->IsCompiler(), error_msg);
547  if (oat_file == NULL) {
548    *error_msg = StringPrintf("Failed to open oat file '%s' referenced from image %s: %s",
549                              oat_filename.c_str(), GetName(), error_msg->c_str());
550    return nullptr;
551  }
552  uint32_t oat_checksum = oat_file->GetOatHeader().GetChecksum();
553  uint32_t image_oat_checksum = image_header.GetOatChecksum();
554  if (oat_checksum != image_oat_checksum) {
555    *error_msg = StringPrintf("Failed to match oat file checksum 0x%x to expected oat checksum 0x%x"
556                              " in image %s", oat_checksum, image_oat_checksum, GetName());
557    return nullptr;
558  }
559  int32_t image_patch_delta = image_header.GetPatchDelta();
560  int32_t oat_patch_delta = oat_file->GetOatHeader().GetImagePatchDelta();
561  if (oat_patch_delta != image_patch_delta) {
562    // We should have already relocated by this point. Bail out.
563    *error_msg = StringPrintf("Failed to match oat file patch delta %d to expected patch delta %d "
564                              "in image %s", oat_patch_delta, image_patch_delta, GetName());
565    return nullptr;
566  }
567
568  return oat_file;
569}
570
571bool ImageSpace::ValidateOatFile(std::string* error_msg) const {
572  CHECK(oat_file_.get() != NULL);
573  for (const OatFile::OatDexFile* oat_dex_file : oat_file_->GetOatDexFiles()) {
574    const std::string& dex_file_location = oat_dex_file->GetDexFileLocation();
575    uint32_t dex_file_location_checksum;
576    if (!DexFile::GetChecksum(dex_file_location.c_str(), &dex_file_location_checksum, error_msg)) {
577      *error_msg = StringPrintf("Failed to get checksum of dex file '%s' referenced by image %s: "
578                                "%s", dex_file_location.c_str(), GetName(), error_msg->c_str());
579      return false;
580    }
581    if (dex_file_location_checksum != oat_dex_file->GetDexFileLocationChecksum()) {
582      *error_msg = StringPrintf("ValidateOatFile found checksum mismatch between oat file '%s' and "
583                                "dex file '%s' (0x%x != 0x%x)",
584                                oat_file_->GetLocation().c_str(), dex_file_location.c_str(),
585                                oat_dex_file->GetDexFileLocationChecksum(),
586                                dex_file_location_checksum);
587      return false;
588    }
589  }
590  return true;
591}
592
593const OatFile* ImageSpace::GetOatFile() const {
594  return oat_file_.get();
595}
596
597OatFile* ImageSpace::ReleaseOatFile() {
598  CHECK(oat_file_.get() != NULL);
599  return oat_file_.release();
600}
601
602void ImageSpace::Dump(std::ostream& os) const {
603  os << GetType()
604      << " begin=" << reinterpret_cast<void*>(Begin())
605      << ",end=" << reinterpret_cast<void*>(End())
606      << ",size=" << PrettySize(Size())
607      << ",name=\"" << GetName() << "\"]";
608}
609
610}  // namespace space
611}  // namespace gc
612}  // namespace art
613