Home | History | Annotate | Download | only in space
      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 <lz4.h>
     20 #include <random>
     21 #include <sys/statvfs.h>
     22 #include <sys/types.h>
     23 #include <unistd.h>
     24 
     25 #include "art_method.h"
     26 #include "base/macros.h"
     27 #include "base/stl_util.h"
     28 #include "base/scoped_flock.h"
     29 #include "base/systrace.h"
     30 #include "base/time_utils.h"
     31 #include "gc/accounting/space_bitmap-inl.h"
     32 #include "image-inl.h"
     33 #include "image_space_fs.h"
     34 #include "mirror/class-inl.h"
     35 #include "mirror/object-inl.h"
     36 #include "oat_file.h"
     37 #include "os.h"
     38 #include "space-inl.h"
     39 #include "utils.h"
     40 
     41 namespace art {
     42 namespace gc {
     43 namespace space {
     44 
     45 Atomic<uint32_t> ImageSpace::bitmap_index_(0);
     46 
     47 ImageSpace::ImageSpace(const std::string& image_filename,
     48                        const char* image_location,
     49                        MemMap* mem_map,
     50                        accounting::ContinuousSpaceBitmap* live_bitmap,
     51                        uint8_t* end)
     52     : MemMapSpace(image_filename,
     53                   mem_map,
     54                   mem_map->Begin(),
     55                   end,
     56                   end,
     57                   kGcRetentionPolicyNeverCollect),
     58       oat_file_non_owned_(nullptr),
     59       image_location_(image_location) {
     60   DCHECK(live_bitmap != nullptr);
     61   live_bitmap_.reset(live_bitmap);
     62 }
     63 
     64 static int32_t ChooseRelocationOffsetDelta(int32_t min_delta, int32_t max_delta) {
     65   CHECK_ALIGNED(min_delta, kPageSize);
     66   CHECK_ALIGNED(max_delta, kPageSize);
     67   CHECK_LT(min_delta, max_delta);
     68 
     69   int32_t r = GetRandomNumber<int32_t>(min_delta, max_delta);
     70   if (r % 2 == 0) {
     71     r = RoundUp(r, kPageSize);
     72   } else {
     73     r = RoundDown(r, kPageSize);
     74   }
     75   CHECK_LE(min_delta, r);
     76   CHECK_GE(max_delta, r);
     77   CHECK_ALIGNED(r, kPageSize);
     78   return r;
     79 }
     80 
     81 static bool GenerateImage(const std::string& image_filename, InstructionSet image_isa,
     82                           std::string* error_msg) {
     83   const std::string boot_class_path_string(Runtime::Current()->GetBootClassPathString());
     84   std::vector<std::string> boot_class_path;
     85   Split(boot_class_path_string, ':', &boot_class_path);
     86   if (boot_class_path.empty()) {
     87     *error_msg = "Failed to generate image because no boot class path specified";
     88     return false;
     89   }
     90   // We should clean up so we are more likely to have room for the image.
     91   if (Runtime::Current()->IsZygote()) {
     92     LOG(INFO) << "Pruning dalvik-cache since we are generating an image and will need to recompile";
     93     PruneDalvikCache(image_isa);
     94   }
     95 
     96   std::vector<std::string> arg_vector;
     97 
     98   std::string dex2oat(Runtime::Current()->GetCompilerExecutable());
     99   arg_vector.push_back(dex2oat);
    100 
    101   std::string image_option_string("--image=");
    102   image_option_string += image_filename;
    103   arg_vector.push_back(image_option_string);
    104 
    105   for (size_t i = 0; i < boot_class_path.size(); i++) {
    106     arg_vector.push_back(std::string("--dex-file=") + boot_class_path[i]);
    107   }
    108 
    109   std::string oat_file_option_string("--oat-file=");
    110   oat_file_option_string += ImageHeader::GetOatLocationFromImageLocation(image_filename);
    111   arg_vector.push_back(oat_file_option_string);
    112 
    113   // Note: we do not generate a fully debuggable boot image so we do not pass the
    114   // compiler flag --debuggable here.
    115 
    116   Runtime::Current()->AddCurrentRuntimeFeaturesAsDex2OatArguments(&arg_vector);
    117   CHECK_EQ(image_isa, kRuntimeISA)
    118       << "We should always be generating an image for the current isa.";
    119 
    120   int32_t base_offset = ChooseRelocationOffsetDelta(ART_BASE_ADDRESS_MIN_DELTA,
    121                                                     ART_BASE_ADDRESS_MAX_DELTA);
    122   LOG(INFO) << "Using an offset of 0x" << std::hex << base_offset << " from default "
    123             << "art base address of 0x" << std::hex << ART_BASE_ADDRESS;
    124   arg_vector.push_back(StringPrintf("--base=0x%x", ART_BASE_ADDRESS + base_offset));
    125 
    126   if (!kIsTargetBuild) {
    127     arg_vector.push_back("--host");
    128   }
    129 
    130   const std::vector<std::string>& compiler_options = Runtime::Current()->GetImageCompilerOptions();
    131   for (size_t i = 0; i < compiler_options.size(); ++i) {
    132     arg_vector.push_back(compiler_options[i].c_str());
    133   }
    134 
    135   std::string command_line(Join(arg_vector, ' '));
    136   LOG(INFO) << "GenerateImage: " << command_line;
    137   return Exec(arg_vector, error_msg);
    138 }
    139 
    140 bool ImageSpace::FindImageFilename(const char* image_location,
    141                                    const InstructionSet image_isa,
    142                                    std::string* system_filename,
    143                                    bool* has_system,
    144                                    std::string* cache_filename,
    145                                    bool* dalvik_cache_exists,
    146                                    bool* has_cache,
    147                                    bool* is_global_cache) {
    148   *has_system = false;
    149   *has_cache = false;
    150   // image_location = /system/framework/boot.art
    151   // system_image_location = /system/framework/<image_isa>/boot.art
    152   std::string system_image_filename(GetSystemImageFilename(image_location, image_isa));
    153   if (OS::FileExists(system_image_filename.c_str())) {
    154     *system_filename = system_image_filename;
    155     *has_system = true;
    156   }
    157 
    158   bool have_android_data = false;
    159   *dalvik_cache_exists = false;
    160   std::string dalvik_cache;
    161   GetDalvikCache(GetInstructionSetString(image_isa), true, &dalvik_cache,
    162                  &have_android_data, dalvik_cache_exists, is_global_cache);
    163 
    164   if (have_android_data && *dalvik_cache_exists) {
    165     // Always set output location even if it does not exist,
    166     // so that the caller knows where to create the image.
    167     //
    168     // image_location = /system/framework/boot.art
    169     // *image_filename = /data/dalvik-cache/<image_isa>/boot.art
    170     std::string error_msg;
    171     if (!GetDalvikCacheFilename(image_location, dalvik_cache.c_str(), cache_filename, &error_msg)) {
    172       LOG(WARNING) << error_msg;
    173       return *has_system;
    174     }
    175     *has_cache = OS::FileExists(cache_filename->c_str());
    176   }
    177   return *has_system || *has_cache;
    178 }
    179 
    180 static bool ReadSpecificImageHeader(const char* filename, ImageHeader* image_header) {
    181     std::unique_ptr<File> image_file(OS::OpenFileForReading(filename));
    182     if (image_file.get() == nullptr) {
    183       return false;
    184     }
    185     const bool success = image_file->ReadFully(image_header, sizeof(ImageHeader));
    186     if (!success || !image_header->IsValid()) {
    187       return false;
    188     }
    189     return true;
    190 }
    191 
    192 // Relocate the image at image_location to dest_filename and relocate it by a random amount.
    193 static bool RelocateImage(const char* image_location, const char* dest_filename,
    194                                InstructionSet isa, std::string* error_msg) {
    195   // We should clean up so we are more likely to have room for the image.
    196   if (Runtime::Current()->IsZygote()) {
    197     LOG(INFO) << "Pruning dalvik-cache since we are relocating an image and will need to recompile";
    198     PruneDalvikCache(isa);
    199   }
    200 
    201   std::string patchoat(Runtime::Current()->GetPatchoatExecutable());
    202 
    203   std::string input_image_location_arg("--input-image-location=");
    204   input_image_location_arg += image_location;
    205 
    206   std::string output_image_filename_arg("--output-image-file=");
    207   output_image_filename_arg += dest_filename;
    208 
    209   std::string instruction_set_arg("--instruction-set=");
    210   instruction_set_arg += GetInstructionSetString(isa);
    211 
    212   std::string base_offset_arg("--base-offset-delta=");
    213   StringAppendF(&base_offset_arg, "%d", ChooseRelocationOffsetDelta(ART_BASE_ADDRESS_MIN_DELTA,
    214                                                                     ART_BASE_ADDRESS_MAX_DELTA));
    215 
    216   std::vector<std::string> argv;
    217   argv.push_back(patchoat);
    218 
    219   argv.push_back(input_image_location_arg);
    220   argv.push_back(output_image_filename_arg);
    221 
    222   argv.push_back(instruction_set_arg);
    223   argv.push_back(base_offset_arg);
    224 
    225   std::string command_line(Join(argv, ' '));
    226   LOG(INFO) << "RelocateImage: " << command_line;
    227   return Exec(argv, error_msg);
    228 }
    229 
    230 static ImageHeader* ReadSpecificImageHeader(const char* filename, std::string* error_msg) {
    231   std::unique_ptr<ImageHeader> hdr(new ImageHeader);
    232   if (!ReadSpecificImageHeader(filename, hdr.get())) {
    233     *error_msg = StringPrintf("Unable to read image header for %s", filename);
    234     return nullptr;
    235   }
    236   return hdr.release();
    237 }
    238 
    239 ImageHeader* ImageSpace::ReadImageHeaderOrDie(const char* image_location,
    240                                               const InstructionSet image_isa) {
    241   std::string error_msg;
    242   ImageHeader* image_header = ReadImageHeader(image_location, image_isa, &error_msg);
    243   if (image_header == nullptr) {
    244     LOG(FATAL) << error_msg;
    245   }
    246   return image_header;
    247 }
    248 
    249 ImageHeader* ImageSpace::ReadImageHeader(const char* image_location,
    250                                          const InstructionSet image_isa,
    251                                          std::string* error_msg) {
    252   std::string system_filename;
    253   bool has_system = false;
    254   std::string cache_filename;
    255   bool has_cache = false;
    256   bool dalvik_cache_exists = false;
    257   bool is_global_cache = false;
    258   if (FindImageFilename(image_location, image_isa, &system_filename, &has_system,
    259                         &cache_filename, &dalvik_cache_exists, &has_cache, &is_global_cache)) {
    260     if (Runtime::Current()->ShouldRelocate()) {
    261       if (has_system && has_cache) {
    262         std::unique_ptr<ImageHeader> sys_hdr(new ImageHeader);
    263         std::unique_ptr<ImageHeader> cache_hdr(new ImageHeader);
    264         if (!ReadSpecificImageHeader(system_filename.c_str(), sys_hdr.get())) {
    265           *error_msg = StringPrintf("Unable to read image header for %s at %s",
    266                                     image_location, system_filename.c_str());
    267           return nullptr;
    268         }
    269         if (!ReadSpecificImageHeader(cache_filename.c_str(), cache_hdr.get())) {
    270           *error_msg = StringPrintf("Unable to read image header for %s at %s",
    271                                     image_location, cache_filename.c_str());
    272           return nullptr;
    273         }
    274         if (sys_hdr->GetOatChecksum() != cache_hdr->GetOatChecksum()) {
    275           *error_msg = StringPrintf("Unable to find a relocated version of image file %s",
    276                                     image_location);
    277           return nullptr;
    278         }
    279         return cache_hdr.release();
    280       } else if (!has_cache) {
    281         *error_msg = StringPrintf("Unable to find a relocated version of image file %s",
    282                                   image_location);
    283         return nullptr;
    284       } else if (!has_system && has_cache) {
    285         // This can probably just use the cache one.
    286         return ReadSpecificImageHeader(cache_filename.c_str(), error_msg);
    287       }
    288     } else {
    289       // We don't want to relocate, Just pick the appropriate one if we have it and return.
    290       if (has_system && has_cache) {
    291         // We want the cache if the checksum matches, otherwise the system.
    292         std::unique_ptr<ImageHeader> system(ReadSpecificImageHeader(system_filename.c_str(),
    293                                                                     error_msg));
    294         std::unique_ptr<ImageHeader> cache(ReadSpecificImageHeader(cache_filename.c_str(),
    295                                                                    error_msg));
    296         if (system.get() == nullptr ||
    297             (cache.get() != nullptr && cache->GetOatChecksum() == system->GetOatChecksum())) {
    298           return cache.release();
    299         } else {
    300           return system.release();
    301         }
    302       } else if (has_system) {
    303         return ReadSpecificImageHeader(system_filename.c_str(), error_msg);
    304       } else if (has_cache) {
    305         return ReadSpecificImageHeader(cache_filename.c_str(), error_msg);
    306       }
    307     }
    308   }
    309 
    310   *error_msg = StringPrintf("Unable to find image file for %s", image_location);
    311   return nullptr;
    312 }
    313 
    314 static bool ChecksumsMatch(const char* image_a, const char* image_b) {
    315   ImageHeader hdr_a;
    316   ImageHeader hdr_b;
    317   return ReadSpecificImageHeader(image_a, &hdr_a) && ReadSpecificImageHeader(image_b, &hdr_b)
    318       && hdr_a.GetOatChecksum() == hdr_b.GetOatChecksum();
    319 }
    320 
    321 static bool ImageCreationAllowed(bool is_global_cache, std::string* error_msg) {
    322   // Anyone can write into a "local" cache.
    323   if (!is_global_cache) {
    324     return true;
    325   }
    326 
    327   // Only the zygote is allowed to create the global boot image.
    328   if (Runtime::Current()->IsZygote()) {
    329     return true;
    330   }
    331 
    332   *error_msg = "Only the zygote can create the global boot image.";
    333   return false;
    334 }
    335 
    336 static constexpr uint64_t kLowSpaceValue = 50 * MB;
    337 static constexpr uint64_t kTmpFsSentinelValue = 384 * MB;
    338 
    339 // Read the free space of the cache partition and make a decision whether to keep the generated
    340 // image. This is to try to mitigate situations where the system might run out of space later.
    341 static bool CheckSpace(const std::string& cache_filename, std::string* error_msg) {
    342   // Using statvfs vs statvfs64 because of b/18207376, and it is enough for all practical purposes.
    343   struct statvfs buf;
    344 
    345   int res = TEMP_FAILURE_RETRY(statvfs(cache_filename.c_str(), &buf));
    346   if (res != 0) {
    347     // Could not stat. Conservatively tell the system to delete the image.
    348     *error_msg = "Could not stat the filesystem, assuming low-memory situation.";
    349     return false;
    350   }
    351 
    352   uint64_t fs_overall_size = buf.f_bsize * static_cast<uint64_t>(buf.f_blocks);
    353   // Zygote is privileged, but other things are not. Use bavail.
    354   uint64_t fs_free_size = buf.f_bsize * static_cast<uint64_t>(buf.f_bavail);
    355 
    356   // Take the overall size as an indicator for a tmpfs, which is being used for the decryption
    357   // environment. We do not want to fail quickening the boot image there, as it is beneficial
    358   // for time-to-UI.
    359   if (fs_overall_size > kTmpFsSentinelValue) {
    360     if (fs_free_size < kLowSpaceValue) {
    361       *error_msg = StringPrintf("Low-memory situation: only %4.2f megabytes available after image"
    362                                 " generation, need at least %" PRIu64 ".",
    363                                 static_cast<double>(fs_free_size) / MB,
    364                                 kLowSpaceValue / MB);
    365       return false;
    366     }
    367   }
    368   return true;
    369 }
    370 
    371 ImageSpace* ImageSpace::CreateBootImage(const char* image_location,
    372                                         const InstructionSet image_isa,
    373                                         bool secondary_image,
    374                                         std::string* error_msg) {
    375   ScopedTrace trace(__FUNCTION__);
    376   std::string system_filename;
    377   bool has_system = false;
    378   std::string cache_filename;
    379   bool has_cache = false;
    380   bool dalvik_cache_exists = false;
    381   bool is_global_cache = true;
    382   bool found_image = FindImageFilename(image_location, image_isa, &system_filename,
    383                                        &has_system, &cache_filename, &dalvik_cache_exists,
    384                                        &has_cache, &is_global_cache);
    385 
    386   // If we're starting with the global cache, and we're the zygote, try to see whether there are
    387   // OTA artifacts from the A/B OTA preopting to move over.
    388   // (It is structurally simpler to check this here, instead of complicating the compile/relocate
    389   // logic below.)
    390   const bool is_zygote = Runtime::Current()->IsZygote();
    391   if (is_global_cache && is_zygote) {
    392     VLOG(startup) << "Checking for A/B OTA data.";
    393     TryMoveOTAArtifacts(cache_filename, dalvik_cache_exists);
    394 
    395     // Retry. There are two cases where the old info is outdated:
    396     // * There wasn't a boot image before (e.g., some failure on boot), but now the OTA preopted
    397     //   image has been moved in-place.
    398     // * There was a boot image before, and we tried to move the OTA preopted image, but a failure
    399     //   happened and there is no file anymore.
    400     found_image = FindImageFilename(image_location,
    401                                     image_isa,
    402                                     &system_filename,
    403                                     &has_system,
    404                                     &cache_filename,
    405                                     &dalvik_cache_exists,
    406                                     &has_cache,
    407                                     &is_global_cache);
    408   }
    409 
    410   if (is_zygote && !secondary_image) {
    411     MarkZygoteStart(image_isa, Runtime::Current()->GetZygoteMaxFailedBoots());
    412   }
    413 
    414   ImageSpace* space;
    415   bool relocate = Runtime::Current()->ShouldRelocate();
    416   bool can_compile = Runtime::Current()->IsImageDex2OatEnabled();
    417   if (found_image) {
    418     const std::string* image_filename;
    419     bool is_system = false;
    420     bool relocated_version_used = false;
    421     if (relocate) {
    422       if (!dalvik_cache_exists) {
    423         *error_msg = StringPrintf("Requiring relocation for image '%s' at '%s' but we do not have "
    424                                   "any dalvik_cache to find/place it in.",
    425                                   image_location, system_filename.c_str());
    426         return nullptr;
    427       }
    428       if (has_system) {
    429         if (has_cache && ChecksumsMatch(system_filename.c_str(), cache_filename.c_str())) {
    430           // We already have a relocated version
    431           image_filename = &cache_filename;
    432           relocated_version_used = true;
    433         } else {
    434           // We cannot have a relocated version, Relocate the system one and use it.
    435 
    436           std::string reason;
    437           bool success;
    438 
    439           // Check whether we are allowed to relocate.
    440           if (!can_compile) {
    441             reason = "Image dex2oat disabled by -Xnoimage-dex2oat.";
    442             success = false;
    443           } else if (!ImageCreationAllowed(is_global_cache, &reason)) {
    444             // Whether we can write to the cache.
    445             success = false;
    446           } else if (secondary_image) {
    447             if (is_zygote) {
    448               // Secondary image is out of date. Clear cache and exit to let it retry from scratch.
    449               LOG(ERROR) << "Cannot patch secondary image '" << image_location
    450                          << "', clearing dalvik_cache and restarting zygote.";
    451               PruneDalvikCache(image_isa);
    452               _exit(1);
    453             } else {
    454               reason = "Should not have to patch secondary image.";
    455               success = false;
    456             }
    457           } else {
    458             // Try to relocate.
    459             success = RelocateImage(image_location, cache_filename.c_str(), image_isa, &reason);
    460           }
    461 
    462           if (success) {
    463             relocated_version_used = true;
    464             image_filename = &cache_filename;
    465           } else {
    466             *error_msg = StringPrintf("Unable to relocate image '%s' from '%s' to '%s': %s",
    467                                       image_location, system_filename.c_str(),
    468                                       cache_filename.c_str(), reason.c_str());
    469             // We failed to create files, remove any possibly garbage output.
    470             // Since ImageCreationAllowed was true above, we are the zygote
    471             // and therefore the only process expected to generate these for
    472             // the device.
    473             PruneDalvikCache(image_isa);
    474             return nullptr;
    475           }
    476         }
    477       } else {
    478         CHECK(has_cache);
    479         // We can just use cache's since it should be fine. This might or might not be relocated.
    480         image_filename = &cache_filename;
    481       }
    482     } else {
    483       if (has_system && has_cache) {
    484         // Check they have the same cksum. If they do use the cache. Otherwise system.
    485         if (ChecksumsMatch(system_filename.c_str(), cache_filename.c_str())) {
    486           image_filename = &cache_filename;
    487           relocated_version_used = true;
    488         } else {
    489           image_filename = &system_filename;
    490           is_system = true;
    491         }
    492       } else if (has_system) {
    493         image_filename = &system_filename;
    494         is_system = true;
    495       } else {
    496         CHECK(has_cache);
    497         image_filename = &cache_filename;
    498       }
    499     }
    500     {
    501       // Note that we must not use the file descriptor associated with
    502       // ScopedFlock::GetFile to Init the image file. We want the file
    503       // descriptor (and the associated exclusive lock) to be released when
    504       // we leave Create.
    505       ScopedFlock image_lock;
    506       // Should this be a RDWR lock? This is only a defensive measure, as at
    507       // this point the image should exist.
    508       // However, only the zygote can write into the global dalvik-cache, so
    509       // restrict to zygote processes, or any process that isn't using
    510       // /data/dalvik-cache (which we assume to be allowed to write there).
    511       const bool rw_lock = is_zygote || !is_global_cache;
    512       image_lock.Init(image_filename->c_str(),
    513                       rw_lock ? (O_CREAT | O_RDWR) : O_RDONLY /* flags */,
    514                       true /* block */,
    515                       error_msg);
    516       VLOG(startup) << "Using image file " << image_filename->c_str() << " for image location "
    517                     << image_location;
    518       // If we are in /system we can assume the image is good. We can also
    519       // assume this if we are using a relocated image (i.e. image checksum
    520       // matches) since this is only different by the offset. We need this to
    521       // make sure that host tests continue to work.
    522       // Since we are the boot image, pass null since we load the oat file from the boot image oat
    523       // file name.
    524       space = ImageSpace::Init(image_filename->c_str(),
    525                                image_location,
    526                                !(is_system || relocated_version_used),
    527                                /* oat_file */nullptr,
    528                                error_msg);
    529     }
    530     if (space != nullptr) {
    531       return space;
    532     }
    533 
    534     if (relocated_version_used) {
    535       // Something is wrong with the relocated copy (even though checksums match). Cleanup.
    536       // This can happen if the .oat is corrupt, since the above only checks the .art checksums.
    537       // TODO: Check the oat file validity earlier.
    538       *error_msg = StringPrintf("Attempted to use relocated version of %s at %s generated from %s "
    539                                 "but image failed to load: %s",
    540                                 image_location, cache_filename.c_str(), system_filename.c_str(),
    541                                 error_msg->c_str());
    542       PruneDalvikCache(image_isa);
    543       return nullptr;
    544     } else if (is_system) {
    545       // If the /system file exists, it should be up-to-date, don't try to generate it.
    546       *error_msg = StringPrintf("Failed to load /system image '%s': %s",
    547                                 image_filename->c_str(), error_msg->c_str());
    548       return nullptr;
    549     } else {
    550       // Otherwise, log a warning and fall through to GenerateImage.
    551       LOG(WARNING) << *error_msg;
    552     }
    553   }
    554 
    555   if (!can_compile) {
    556     *error_msg = "Not attempting to compile image because -Xnoimage-dex2oat";
    557     return nullptr;
    558   } else if (!dalvik_cache_exists) {
    559     *error_msg = StringPrintf("No place to put generated image.");
    560     return nullptr;
    561   } else if (!ImageCreationAllowed(is_global_cache, error_msg)) {
    562     return nullptr;
    563   } else if (secondary_image) {
    564     *error_msg = "Cannot compile a secondary image.";
    565     return nullptr;
    566   } else if (!GenerateImage(cache_filename, image_isa, error_msg)) {
    567     *error_msg = StringPrintf("Failed to generate image '%s': %s",
    568                               cache_filename.c_str(), error_msg->c_str());
    569     // We failed to create files, remove any possibly garbage output.
    570     // Since ImageCreationAllowed was true above, we are the zygote
    571     // and therefore the only process expected to generate these for
    572     // the device.
    573     PruneDalvikCache(image_isa);
    574     return nullptr;
    575   } else {
    576     // Check whether there is enough space left over after we have generated the image.
    577     if (!CheckSpace(cache_filename, error_msg)) {
    578       // No. Delete the generated image and try to run out of the dex files.
    579       PruneDalvikCache(image_isa);
    580       return nullptr;
    581     }
    582 
    583     // Note that we must not use the file descriptor associated with
    584     // ScopedFlock::GetFile to Init the image file. We want the file
    585     // descriptor (and the associated exclusive lock) to be released when
    586     // we leave Create.
    587     ScopedFlock image_lock;
    588     image_lock.Init(cache_filename.c_str(), error_msg);
    589     space = ImageSpace::Init(cache_filename.c_str(), image_location, true, nullptr, error_msg);
    590     if (space == nullptr) {
    591       *error_msg = StringPrintf("Failed to load generated image '%s': %s",
    592                                 cache_filename.c_str(), error_msg->c_str());
    593     }
    594     return space;
    595   }
    596 }
    597 
    598 void ImageSpace::VerifyImageAllocations() {
    599   uint8_t* current = Begin() + RoundUp(sizeof(ImageHeader), kObjectAlignment);
    600   while (current < End()) {
    601     CHECK_ALIGNED(current, kObjectAlignment);
    602     auto* obj = reinterpret_cast<mirror::Object*>(current);
    603     CHECK(obj->GetClass() != nullptr) << "Image object at address " << obj << " has null class";
    604     CHECK(live_bitmap_->Test(obj)) << PrettyTypeOf(obj);
    605     if (kUseBakerOrBrooksReadBarrier) {
    606       obj->AssertReadBarrierPointer();
    607     }
    608     current += RoundUp(obj->SizeOf(), kObjectAlignment);
    609   }
    610 }
    611 
    612 // Helper class for relocating from one range of memory to another.
    613 class RelocationRange {
    614  public:
    615   RelocationRange() = default;
    616   RelocationRange(const RelocationRange&) = default;
    617   RelocationRange(uintptr_t source, uintptr_t dest, uintptr_t length)
    618       : source_(source),
    619         dest_(dest),
    620         length_(length) {}
    621 
    622   bool InSource(uintptr_t address) const {
    623     return address - source_ < length_;
    624   }
    625 
    626   bool InDest(uintptr_t address) const {
    627     return address - dest_ < length_;
    628   }
    629 
    630   // Translate a source address to the destination space.
    631   uintptr_t ToDest(uintptr_t address) const {
    632     DCHECK(InSource(address));
    633     return address + Delta();
    634   }
    635 
    636   // Returns the delta between the dest from the source.
    637   uintptr_t Delta() const {
    638     return dest_ - source_;
    639   }
    640 
    641   uintptr_t Source() const {
    642     return source_;
    643   }
    644 
    645   uintptr_t Dest() const {
    646     return dest_;
    647   }
    648 
    649   uintptr_t Length() const {
    650     return length_;
    651   }
    652 
    653  private:
    654   const uintptr_t source_;
    655   const uintptr_t dest_;
    656   const uintptr_t length_;
    657 };
    658 
    659 std::ostream& operator<<(std::ostream& os, const RelocationRange& reloc) {
    660   return os << "(" << reinterpret_cast<const void*>(reloc.Source()) << "-"
    661             << reinterpret_cast<const void*>(reloc.Source() + reloc.Length()) << ")->("
    662             << reinterpret_cast<const void*>(reloc.Dest()) << "-"
    663             << reinterpret_cast<const void*>(reloc.Dest() + reloc.Length()) << ")";
    664 }
    665 
    666 class FixupVisitor : public ValueObject {
    667  public:
    668   FixupVisitor(const RelocationRange& boot_image,
    669                const RelocationRange& boot_oat,
    670                const RelocationRange& app_image,
    671                const RelocationRange& app_oat)
    672       : boot_image_(boot_image),
    673         boot_oat_(boot_oat),
    674         app_image_(app_image),
    675         app_oat_(app_oat) {}
    676 
    677   // Return the relocated address of a heap object.
    678   template <typename T>
    679   ALWAYS_INLINE T* ForwardObject(T* src) const {
    680     const uintptr_t uint_src = reinterpret_cast<uintptr_t>(src);
    681     if (boot_image_.InSource(uint_src)) {
    682       return reinterpret_cast<T*>(boot_image_.ToDest(uint_src));
    683     }
    684     if (app_image_.InSource(uint_src)) {
    685       return reinterpret_cast<T*>(app_image_.ToDest(uint_src));
    686     }
    687     // Since we are fixing up the app image, there should only be pointers to the app image and
    688     // boot image.
    689     DCHECK(src == nullptr) << reinterpret_cast<const void*>(src);
    690     return src;
    691   }
    692 
    693   // Return the relocated address of a code pointer (contained by an oat file).
    694   ALWAYS_INLINE const void* ForwardCode(const void* src) const {
    695     const uintptr_t uint_src = reinterpret_cast<uintptr_t>(src);
    696     if (boot_oat_.InSource(uint_src)) {
    697       return reinterpret_cast<const void*>(boot_oat_.ToDest(uint_src));
    698     }
    699     if (app_oat_.InSource(uint_src)) {
    700       return reinterpret_cast<const void*>(app_oat_.ToDest(uint_src));
    701     }
    702     DCHECK(src == nullptr) << src;
    703     return src;
    704   }
    705 
    706   // Must be called on pointers that already have been relocated to the destination relocation.
    707   ALWAYS_INLINE bool IsInAppImage(mirror::Object* object) const {
    708     return app_image_.InDest(reinterpret_cast<uintptr_t>(object));
    709   }
    710 
    711  protected:
    712   // Source section.
    713   const RelocationRange boot_image_;
    714   const RelocationRange boot_oat_;
    715   const RelocationRange app_image_;
    716   const RelocationRange app_oat_;
    717 };
    718 
    719 // Adapt for mirror::Class::FixupNativePointers.
    720 class FixupObjectAdapter : public FixupVisitor {
    721  public:
    722   template<typename... Args>
    723   explicit FixupObjectAdapter(Args... args) : FixupVisitor(args...) {}
    724 
    725   template <typename T>
    726   T* operator()(T* obj) const {
    727     return ForwardObject(obj);
    728   }
    729 };
    730 
    731 class FixupRootVisitor : public FixupVisitor {
    732  public:
    733   template<typename... Args>
    734   explicit FixupRootVisitor(Args... args) : FixupVisitor(args...) {}
    735 
    736   ALWAYS_INLINE void VisitRootIfNonNull(mirror::CompressedReference<mirror::Object>* root) const
    737       SHARED_REQUIRES(Locks::mutator_lock_) {
    738     if (!root->IsNull()) {
    739       VisitRoot(root);
    740     }
    741   }
    742 
    743   ALWAYS_INLINE void VisitRoot(mirror::CompressedReference<mirror::Object>* root) const
    744       SHARED_REQUIRES(Locks::mutator_lock_) {
    745     mirror::Object* ref = root->AsMirrorPtr();
    746     mirror::Object* new_ref = ForwardObject(ref);
    747     if (ref != new_ref) {
    748       root->Assign(new_ref);
    749     }
    750   }
    751 };
    752 
    753 class FixupObjectVisitor : public FixupVisitor {
    754  public:
    755   template<typename... Args>
    756   explicit FixupObjectVisitor(gc::accounting::ContinuousSpaceBitmap* visited,
    757                               const size_t pointer_size,
    758                               Args... args)
    759       : FixupVisitor(args...),
    760         pointer_size_(pointer_size),
    761         visited_(visited) {}
    762 
    763   // Fix up separately since we also need to fix up method entrypoints.
    764   ALWAYS_INLINE void VisitRootIfNonNull(
    765       mirror::CompressedReference<mirror::Object>* root ATTRIBUTE_UNUSED) const {}
    766 
    767   ALWAYS_INLINE void VisitRoot(mirror::CompressedReference<mirror::Object>* root ATTRIBUTE_UNUSED)
    768       const {}
    769 
    770   ALWAYS_INLINE void operator()(mirror::Object* obj,
    771                                 MemberOffset offset,
    772                                 bool is_static ATTRIBUTE_UNUSED) const
    773       NO_THREAD_SAFETY_ANALYSIS {
    774     // There could be overlap between ranges, we must avoid visiting the same reference twice.
    775     // Avoid the class field since we already fixed it up in FixupClassVisitor.
    776     if (offset.Uint32Value() != mirror::Object::ClassOffset().Uint32Value()) {
    777       // Space is not yet added to the heap, don't do a read barrier.
    778       mirror::Object* ref = obj->GetFieldObject<mirror::Object, kVerifyNone, kWithoutReadBarrier>(
    779           offset);
    780       // Use SetFieldObjectWithoutWriteBarrier to avoid card marking since we are writing to the
    781       // image.
    782       obj->SetFieldObjectWithoutWriteBarrier<false, true, kVerifyNone>(offset, ForwardObject(ref));
    783     }
    784   }
    785 
    786   // Visit a pointer array and forward corresponding native data. Ignores pointer arrays in the
    787   // boot image. Uses the bitmap to ensure the same array is not visited multiple times.
    788   template <typename Visitor>
    789   void UpdatePointerArrayContents(mirror::PointerArray* array, const Visitor& visitor) const
    790       NO_THREAD_SAFETY_ANALYSIS {
    791     DCHECK(array != nullptr);
    792     DCHECK(visitor.IsInAppImage(array));
    793     // The bit for the array contents is different than the bit for the array. Since we may have
    794     // already visited the array as a long / int array from walking the bitmap without knowing it
    795     // was a pointer array.
    796     static_assert(kObjectAlignment == 8u, "array bit may be in another object");
    797     mirror::Object* const contents_bit = reinterpret_cast<mirror::Object*>(
    798         reinterpret_cast<uintptr_t>(array) + kObjectAlignment);
    799     // If the bit is not set then the contents have not yet been updated.
    800     if (!visited_->Test(contents_bit)) {
    801       array->Fixup<kVerifyNone, kWithoutReadBarrier>(array, pointer_size_, visitor);
    802       visited_->Set(contents_bit);
    803     }
    804   }
    805 
    806   // java.lang.ref.Reference visitor.
    807   void operator()(mirror::Class* klass ATTRIBUTE_UNUSED, mirror::Reference* ref) const
    808       SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(Locks::heap_bitmap_lock_) {
    809     mirror::Object* obj = ref->GetReferent<kWithoutReadBarrier>();
    810     ref->SetFieldObjectWithoutWriteBarrier<false, true, kVerifyNone>(
    811         mirror::Reference::ReferentOffset(),
    812         ForwardObject(obj));
    813   }
    814 
    815   void operator()(mirror::Object* obj) const NO_THREAD_SAFETY_ANALYSIS {
    816     if (visited_->Test(obj)) {
    817       // Already visited.
    818       return;
    819     }
    820     visited_->Set(obj);
    821 
    822     // Handle class specially first since we need it to be updated to properly visit the rest of
    823     // the instance fields.
    824     {
    825       mirror::Class* klass = obj->GetClass<kVerifyNone, kWithoutReadBarrier>();
    826       DCHECK(klass != nullptr) << "Null class in image";
    827       // No AsClass since our fields aren't quite fixed up yet.
    828       mirror::Class* new_klass = down_cast<mirror::Class*>(ForwardObject(klass));
    829       if (klass != new_klass) {
    830         obj->SetClass<kVerifyNone>(new_klass);
    831       }
    832       if (new_klass != klass && IsInAppImage(new_klass)) {
    833         // Make sure the klass contents are fixed up since we depend on it to walk the fields.
    834         operator()(new_klass);
    835       }
    836     }
    837 
    838     obj->VisitReferences</*visit native roots*/false, kVerifyNone, kWithoutReadBarrier>(
    839         *this,
    840         *this);
    841     // Note that this code relies on no circular dependencies.
    842     // We want to use our own class loader and not the one in the image.
    843     if (obj->IsClass<kVerifyNone, kWithoutReadBarrier>()) {
    844       mirror::Class* as_klass = obj->AsClass<kVerifyNone, kWithoutReadBarrier>();
    845       FixupObjectAdapter visitor(boot_image_, boot_oat_, app_image_, app_oat_);
    846       as_klass->FixupNativePointers<kVerifyNone, kWithoutReadBarrier>(as_klass,
    847                                                                       pointer_size_,
    848                                                                       visitor);
    849       // Deal with the pointer arrays. Use the helper function since multiple classes can reference
    850       // the same arrays.
    851       mirror::PointerArray* const vtable = as_klass->GetVTable<kVerifyNone, kWithoutReadBarrier>();
    852       if (vtable != nullptr && IsInAppImage(vtable)) {
    853         operator()(vtable);
    854         UpdatePointerArrayContents(vtable, visitor);
    855       }
    856       mirror::IfTable* iftable = as_klass->GetIfTable<kVerifyNone, kWithoutReadBarrier>();
    857       // Ensure iftable arrays are fixed up since we need GetMethodArray to return the valid
    858       // contents.
    859       if (iftable != nullptr && IsInAppImage(iftable)) {
    860         operator()(iftable);
    861         for (int32_t i = 0, count = iftable->Count(); i < count; ++i) {
    862           if (iftable->GetMethodArrayCount<kVerifyNone, kWithoutReadBarrier>(i) > 0) {
    863             mirror::PointerArray* methods =
    864                 iftable->GetMethodArray<kVerifyNone, kWithoutReadBarrier>(i);
    865             if (visitor.IsInAppImage(methods)) {
    866               operator()(methods);
    867               DCHECK(methods != nullptr);
    868               UpdatePointerArrayContents(methods, visitor);
    869             }
    870           }
    871         }
    872       }
    873     }
    874   }
    875 
    876  private:
    877   const size_t pointer_size_;
    878   gc::accounting::ContinuousSpaceBitmap* const visited_;
    879 };
    880 
    881 class ForwardObjectAdapter {
    882  public:
    883   ALWAYS_INLINE ForwardObjectAdapter(const FixupVisitor* visitor) : visitor_(visitor) {}
    884 
    885   template <typename T>
    886   ALWAYS_INLINE T* operator()(T* src) const {
    887     return visitor_->ForwardObject(src);
    888   }
    889 
    890  private:
    891   const FixupVisitor* const visitor_;
    892 };
    893 
    894 class ForwardCodeAdapter {
    895  public:
    896   ALWAYS_INLINE ForwardCodeAdapter(const FixupVisitor* visitor)
    897       : visitor_(visitor) {}
    898 
    899   template <typename T>
    900   ALWAYS_INLINE T* operator()(T* src) const {
    901     return visitor_->ForwardCode(src);
    902   }
    903 
    904  private:
    905   const FixupVisitor* const visitor_;
    906 };
    907 
    908 class FixupArtMethodVisitor : public FixupVisitor, public ArtMethodVisitor {
    909  public:
    910   template<typename... Args>
    911   explicit FixupArtMethodVisitor(bool fixup_heap_objects, size_t pointer_size, Args... args)
    912       : FixupVisitor(args...),
    913         fixup_heap_objects_(fixup_heap_objects),
    914         pointer_size_(pointer_size) {}
    915 
    916   virtual void Visit(ArtMethod* method) NO_THREAD_SAFETY_ANALYSIS {
    917     // TODO: Separate visitor for runtime vs normal methods.
    918     if (UNLIKELY(method->IsRuntimeMethod())) {
    919       ImtConflictTable* table = method->GetImtConflictTable(pointer_size_);
    920       if (table != nullptr) {
    921         ImtConflictTable* new_table = ForwardObject(table);
    922         if (table != new_table) {
    923           method->SetImtConflictTable(new_table, pointer_size_);
    924         }
    925       }
    926       const void* old_code = method->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size_);
    927       const void* new_code = ForwardCode(old_code);
    928       if (old_code != new_code) {
    929         method->SetEntryPointFromQuickCompiledCodePtrSize(new_code, pointer_size_);
    930       }
    931     } else {
    932       if (fixup_heap_objects_) {
    933         method->UpdateObjectsForImageRelocation(ForwardObjectAdapter(this), pointer_size_);
    934       }
    935       method->UpdateEntrypoints<kWithoutReadBarrier>(ForwardCodeAdapter(this), pointer_size_);
    936     }
    937   }
    938 
    939  private:
    940   const bool fixup_heap_objects_;
    941   const size_t pointer_size_;
    942 };
    943 
    944 class FixupArtFieldVisitor : public FixupVisitor, public ArtFieldVisitor {
    945  public:
    946   template<typename... Args>
    947   explicit FixupArtFieldVisitor(Args... args) : FixupVisitor(args...) {}
    948 
    949   virtual void Visit(ArtField* field) NO_THREAD_SAFETY_ANALYSIS {
    950     field->UpdateObjects(ForwardObjectAdapter(this));
    951   }
    952 };
    953 
    954 // Relocate an image space mapped at target_base which possibly used to be at a different base
    955 // address. Only needs a single image space, not one for both source and destination.
    956 // In place means modifying a single ImageSpace in place rather than relocating from one ImageSpace
    957 // to another.
    958 static bool RelocateInPlace(ImageHeader& image_header,
    959                             uint8_t* target_base,
    960                             accounting::ContinuousSpaceBitmap* bitmap,
    961                             const OatFile* app_oat_file,
    962                             std::string* error_msg) {
    963   DCHECK(error_msg != nullptr);
    964   if (!image_header.IsPic()) {
    965     if (image_header.GetImageBegin() == target_base) {
    966       return true;
    967     }
    968     *error_msg = StringPrintf("Cannot relocate non-pic image for oat file %s",
    969                               (app_oat_file != nullptr) ? app_oat_file->GetLocation().c_str() : "");
    970     return false;
    971   }
    972   // Set up sections.
    973   uint32_t boot_image_begin = 0;
    974   uint32_t boot_image_end = 0;
    975   uint32_t boot_oat_begin = 0;
    976   uint32_t boot_oat_end = 0;
    977   const size_t pointer_size = image_header.GetPointerSize();
    978   gc::Heap* const heap = Runtime::Current()->GetHeap();
    979   heap->GetBootImagesSize(&boot_image_begin, &boot_image_end, &boot_oat_begin, &boot_oat_end);
    980   if (boot_image_begin == boot_image_end) {
    981     *error_msg = "Can not relocate app image without boot image space";
    982     return false;
    983   }
    984   if (boot_oat_begin == boot_oat_end) {
    985     *error_msg = "Can not relocate app image without boot oat file";
    986     return false;
    987   }
    988   const uint32_t boot_image_size = boot_image_end - boot_image_begin;
    989   const uint32_t boot_oat_size = boot_oat_end - boot_oat_begin;
    990   const uint32_t image_header_boot_image_size = image_header.GetBootImageSize();
    991   const uint32_t image_header_boot_oat_size = image_header.GetBootOatSize();
    992   if (boot_image_size != image_header_boot_image_size) {
    993     *error_msg = StringPrintf("Boot image size %" PRIu64 " does not match expected size %"
    994                                   PRIu64,
    995                               static_cast<uint64_t>(boot_image_size),
    996                               static_cast<uint64_t>(image_header_boot_image_size));
    997     return false;
    998   }
    999   if (boot_oat_size != image_header_boot_oat_size) {
   1000     *error_msg = StringPrintf("Boot oat size %" PRIu64 " does not match expected size %"
   1001                                   PRIu64,
   1002                               static_cast<uint64_t>(boot_oat_size),
   1003                               static_cast<uint64_t>(image_header_boot_oat_size));
   1004     return false;
   1005   }
   1006   TimingLogger logger(__FUNCTION__, true, false);
   1007   RelocationRange boot_image(image_header.GetBootImageBegin(),
   1008                              boot_image_begin,
   1009                              boot_image_size);
   1010   RelocationRange boot_oat(image_header.GetBootOatBegin(),
   1011                            boot_oat_begin,
   1012                            boot_oat_size);
   1013   RelocationRange app_image(reinterpret_cast<uintptr_t>(image_header.GetImageBegin()),
   1014                             reinterpret_cast<uintptr_t>(target_base),
   1015                             image_header.GetImageSize());
   1016   // Use the oat data section since this is where the OatFile::Begin is.
   1017   RelocationRange app_oat(reinterpret_cast<uintptr_t>(image_header.GetOatDataBegin()),
   1018                           // Not necessarily in low 4GB.
   1019                           reinterpret_cast<uintptr_t>(app_oat_file->Begin()),
   1020                           image_header.GetOatDataEnd() - image_header.GetOatDataBegin());
   1021   VLOG(image) << "App image " << app_image;
   1022   VLOG(image) << "App oat " << app_oat;
   1023   VLOG(image) << "Boot image " << boot_image;
   1024   VLOG(image) << "Boot oat " << boot_oat;
   1025   // True if we need to fixup any heap pointers, otherwise only code pointers.
   1026   const bool fixup_image = boot_image.Delta() != 0 || app_image.Delta() != 0;
   1027   const bool fixup_code = boot_oat.Delta() != 0 || app_oat.Delta() != 0;
   1028   if (!fixup_image && !fixup_code) {
   1029     // Nothing to fix up.
   1030     return true;
   1031   }
   1032   ScopedDebugDisallowReadBarriers sddrb(Thread::Current());
   1033   // Need to update the image to be at the target base.
   1034   const ImageSection& objects_section = image_header.GetImageSection(ImageHeader::kSectionObjects);
   1035   uintptr_t objects_begin = reinterpret_cast<uintptr_t>(target_base + objects_section.Offset());
   1036   uintptr_t objects_end = reinterpret_cast<uintptr_t>(target_base + objects_section.End());
   1037   FixupObjectAdapter fixup_adapter(boot_image, boot_oat, app_image, app_oat);
   1038   if (fixup_image) {
   1039     // Two pass approach, fix up all classes first, then fix up non class-objects.
   1040     // The visited bitmap is used to ensure that pointer arrays are not forwarded twice.
   1041     std::unique_ptr<gc::accounting::ContinuousSpaceBitmap> visited_bitmap(
   1042         gc::accounting::ContinuousSpaceBitmap::Create("Relocate bitmap",
   1043                                                       target_base,
   1044                                                       image_header.GetImageSize()));
   1045     FixupObjectVisitor fixup_object_visitor(visited_bitmap.get(),
   1046                                             pointer_size,
   1047                                             boot_image,
   1048                                             boot_oat,
   1049                                             app_image,
   1050                                             app_oat);
   1051     TimingLogger::ScopedTiming timing("Fixup classes", &logger);
   1052     // Fixup objects may read fields in the boot image, use the mutator lock here for sanity. Though
   1053     // its probably not required.
   1054     ScopedObjectAccess soa(Thread::Current());
   1055     timing.NewTiming("Fixup objects");
   1056     bitmap->VisitMarkedRange(objects_begin, objects_end, fixup_object_visitor);
   1057     // Fixup image roots.
   1058     CHECK(app_image.InSource(reinterpret_cast<uintptr_t>(
   1059         image_header.GetImageRoots<kWithoutReadBarrier>())));
   1060     image_header.RelocateImageObjects(app_image.Delta());
   1061     CHECK_EQ(image_header.GetImageBegin(), target_base);
   1062     // Fix up dex cache DexFile pointers.
   1063     auto* dex_caches = image_header.GetImageRoot<kWithoutReadBarrier>(ImageHeader::kDexCaches)->
   1064         AsObjectArray<mirror::DexCache, kVerifyNone, kWithoutReadBarrier>();
   1065     for (int32_t i = 0, count = dex_caches->GetLength(); i < count; ++i) {
   1066       mirror::DexCache* dex_cache = dex_caches->Get<kVerifyNone, kWithoutReadBarrier>(i);
   1067       // Fix up dex cache pointers.
   1068       GcRoot<mirror::String>* strings = dex_cache->GetStrings();
   1069       if (strings != nullptr) {
   1070         GcRoot<mirror::String>* new_strings = fixup_adapter.ForwardObject(strings);
   1071         if (strings != new_strings) {
   1072           dex_cache->SetStrings(new_strings);
   1073         }
   1074         dex_cache->FixupStrings<kWithoutReadBarrier>(new_strings, fixup_adapter);
   1075       }
   1076       GcRoot<mirror::Class>* types = dex_cache->GetResolvedTypes();
   1077       if (types != nullptr) {
   1078         GcRoot<mirror::Class>* new_types = fixup_adapter.ForwardObject(types);
   1079         if (types != new_types) {
   1080           dex_cache->SetResolvedTypes(new_types);
   1081         }
   1082         dex_cache->FixupResolvedTypes<kWithoutReadBarrier>(new_types, fixup_adapter);
   1083       }
   1084       ArtMethod** methods = dex_cache->GetResolvedMethods();
   1085       if (methods != nullptr) {
   1086         ArtMethod** new_methods = fixup_adapter.ForwardObject(methods);
   1087         if (methods != new_methods) {
   1088           dex_cache->SetResolvedMethods(new_methods);
   1089         }
   1090         for (size_t j = 0, num = dex_cache->NumResolvedMethods(); j != num; ++j) {
   1091           ArtMethod* orig = mirror::DexCache::GetElementPtrSize(new_methods, j, pointer_size);
   1092           ArtMethod* copy = fixup_adapter.ForwardObject(orig);
   1093           if (orig != copy) {
   1094             mirror::DexCache::SetElementPtrSize(new_methods, j, copy, pointer_size);
   1095           }
   1096         }
   1097       }
   1098       ArtField** fields = dex_cache->GetResolvedFields();
   1099       if (fields != nullptr) {
   1100         ArtField** new_fields = fixup_adapter.ForwardObject(fields);
   1101         if (fields != new_fields) {
   1102           dex_cache->SetResolvedFields(new_fields);
   1103         }
   1104         for (size_t j = 0, num = dex_cache->NumResolvedFields(); j != num; ++j) {
   1105           ArtField* orig = mirror::DexCache::GetElementPtrSize(new_fields, j, pointer_size);
   1106           ArtField* copy = fixup_adapter.ForwardObject(orig);
   1107           if (orig != copy) {
   1108             mirror::DexCache::SetElementPtrSize(new_fields, j, copy, pointer_size);
   1109           }
   1110         }
   1111       }
   1112     }
   1113   }
   1114   {
   1115     // Only touches objects in the app image, no need for mutator lock.
   1116     TimingLogger::ScopedTiming timing("Fixup methods", &logger);
   1117     FixupArtMethodVisitor method_visitor(fixup_image,
   1118                                          pointer_size,
   1119                                          boot_image,
   1120                                          boot_oat,
   1121                                          app_image,
   1122                                          app_oat);
   1123     image_header.VisitPackedArtMethods(&method_visitor, target_base, pointer_size);
   1124   }
   1125   if (fixup_image) {
   1126     {
   1127       // Only touches objects in the app image, no need for mutator lock.
   1128       TimingLogger::ScopedTiming timing("Fixup fields", &logger);
   1129       FixupArtFieldVisitor field_visitor(boot_image, boot_oat, app_image, app_oat);
   1130       image_header.VisitPackedArtFields(&field_visitor, target_base);
   1131     }
   1132     {
   1133       TimingLogger::ScopedTiming timing("Fixup conflict tables", &logger);
   1134       image_header.VisitPackedImtConflictTables(fixup_adapter, target_base, pointer_size);
   1135     }
   1136     // In the app image case, the image methods are actually in the boot image.
   1137     image_header.RelocateImageMethods(boot_image.Delta());
   1138     const auto& class_table_section = image_header.GetImageSection(ImageHeader::kSectionClassTable);
   1139     if (class_table_section.Size() > 0u) {
   1140       // Note that we require that ReadFromMemory does not make an internal copy of the elements.
   1141       // This also relies on visit roots not doing any verification which could fail after we update
   1142       // the roots to be the image addresses.
   1143       ScopedObjectAccess soa(Thread::Current());
   1144       WriterMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
   1145       ClassTable temp_table;
   1146       temp_table.ReadFromMemory(target_base + class_table_section.Offset());
   1147       FixupRootVisitor root_visitor(boot_image, boot_oat, app_image, app_oat);
   1148       temp_table.VisitRoots(root_visitor);
   1149     }
   1150   }
   1151   if (VLOG_IS_ON(image)) {
   1152     logger.Dump(LOG(INFO));
   1153   }
   1154   return true;
   1155 }
   1156 
   1157 ImageSpace* ImageSpace::Init(const char* image_filename,
   1158                              const char* image_location,
   1159                              bool validate_oat_file,
   1160                              const OatFile* oat_file,
   1161                              std::string* error_msg) {
   1162   CHECK(image_filename != nullptr);
   1163   CHECK(image_location != nullptr);
   1164 
   1165   TimingLogger logger(__PRETTY_FUNCTION__, true, VLOG_IS_ON(image));
   1166   VLOG(image) << "ImageSpace::Init entering image_filename=" << image_filename;
   1167 
   1168   std::unique_ptr<File> file;
   1169   {
   1170     TimingLogger::ScopedTiming timing("OpenImageFile", &logger);
   1171     file.reset(OS::OpenFileForReading(image_filename));
   1172     if (file == nullptr) {
   1173       *error_msg = StringPrintf("Failed to open '%s'", image_filename);
   1174       return nullptr;
   1175     }
   1176   }
   1177   ImageHeader temp_image_header;
   1178   ImageHeader* image_header = &temp_image_header;
   1179   {
   1180     TimingLogger::ScopedTiming timing("ReadImageHeader", &logger);
   1181     bool success = file->ReadFully(image_header, sizeof(*image_header));
   1182     if (!success || !image_header->IsValid()) {
   1183       *error_msg = StringPrintf("Invalid image header in '%s'", image_filename);
   1184       return nullptr;
   1185     }
   1186   }
   1187   // Check that the file is larger or equal to the header size + data size.
   1188   const uint64_t image_file_size = static_cast<uint64_t>(file->GetLength());
   1189   if (image_file_size < sizeof(ImageHeader) + image_header->GetDataSize()) {
   1190     *error_msg = StringPrintf("Image file truncated: %" PRIu64 " vs. %" PRIu64 ".",
   1191                               image_file_size,
   1192                               sizeof(ImageHeader) + image_header->GetDataSize());
   1193     return nullptr;
   1194   }
   1195 
   1196   if (oat_file != nullptr) {
   1197     // If we have an oat file, check the oat file checksum. The oat file is only non-null for the
   1198     // app image case. Otherwise, we open the oat file after the image and check the checksum there.
   1199     const uint32_t oat_checksum = oat_file->GetOatHeader().GetChecksum();
   1200     const uint32_t image_oat_checksum = image_header->GetOatChecksum();
   1201     if (oat_checksum != image_oat_checksum) {
   1202       *error_msg = StringPrintf("Oat checksum 0x%x does not match the image one 0x%x in image %s",
   1203                                 oat_checksum,
   1204                                 image_oat_checksum,
   1205                                 image_filename);
   1206       return nullptr;
   1207     }
   1208   }
   1209 
   1210   if (VLOG_IS_ON(startup)) {
   1211     LOG(INFO) << "Dumping image sections";
   1212     for (size_t i = 0; i < ImageHeader::kSectionCount; ++i) {
   1213       const auto section_idx = static_cast<ImageHeader::ImageSections>(i);
   1214       auto& section = image_header->GetImageSection(section_idx);
   1215       LOG(INFO) << section_idx << " start="
   1216                 << reinterpret_cast<void*>(image_header->GetImageBegin() + section.Offset()) << " "
   1217                 << section;
   1218     }
   1219   }
   1220 
   1221   const auto& bitmap_section = image_header->GetImageSection(ImageHeader::kSectionImageBitmap);
   1222   // The location we want to map from is the first aligned page after the end of the stored
   1223   // (possibly compressed) data.
   1224   const size_t image_bitmap_offset = RoundUp(sizeof(ImageHeader) + image_header->GetDataSize(),
   1225                                              kPageSize);
   1226   const size_t end_of_bitmap = image_bitmap_offset + bitmap_section.Size();
   1227   if (end_of_bitmap != image_file_size) {
   1228     *error_msg = StringPrintf(
   1229         "Image file size does not equal end of bitmap: size=%" PRIu64 " vs. %zu.", image_file_size,
   1230         end_of_bitmap);
   1231     return nullptr;
   1232   }
   1233 
   1234   // The preferred address to map the image, null specifies any address. If we manage to map the
   1235   // image at the image begin, the amount of fixup work required is minimized.
   1236   std::vector<uint8_t*> addresses(1, image_header->GetImageBegin());
   1237   if (image_header->IsPic()) {
   1238     // Can also map at a random low_4gb address since we can relocate in-place.
   1239     addresses.push_back(nullptr);
   1240   }
   1241 
   1242   // Note: The image header is part of the image due to mmap page alignment required of offset.
   1243   std::unique_ptr<MemMap> map;
   1244   std::string temp_error_msg;
   1245   for (uint8_t* address : addresses) {
   1246     TimingLogger::ScopedTiming timing("MapImageFile", &logger);
   1247     // Only care about the error message for the last address in addresses. We want to avoid the
   1248     // overhead of printing the process maps if we can relocate.
   1249     std::string* out_error_msg = (address == addresses.back()) ? &temp_error_msg : nullptr;
   1250     const ImageHeader::StorageMode storage_mode = image_header->GetStorageMode();
   1251     if (storage_mode == ImageHeader::kStorageModeUncompressed) {
   1252       map.reset(MemMap::MapFileAtAddress(address,
   1253                                          image_header->GetImageSize(),
   1254                                          PROT_READ | PROT_WRITE,
   1255                                          MAP_PRIVATE,
   1256                                          file->Fd(),
   1257                                          0,
   1258                                          /*low_4gb*/true,
   1259                                          /*reuse*/false,
   1260                                          image_filename,
   1261                                          /*out*/out_error_msg));
   1262     } else {
   1263       if (storage_mode != ImageHeader::kStorageModeLZ4 &&
   1264           storage_mode != ImageHeader::kStorageModeLZ4HC) {
   1265         *error_msg = StringPrintf("Invalid storage mode in image header %d",
   1266                                   static_cast<int>(storage_mode));
   1267         return nullptr;
   1268       }
   1269       // Reserve output and decompress into it.
   1270       map.reset(MemMap::MapAnonymous(image_location,
   1271                                      address,
   1272                                      image_header->GetImageSize(),
   1273                                      PROT_READ | PROT_WRITE,
   1274                                      /*low_4gb*/true,
   1275                                      /*reuse*/false,
   1276                                      /*out*/out_error_msg));
   1277       if (map != nullptr) {
   1278         const size_t stored_size = image_header->GetDataSize();
   1279         const size_t decompress_offset = sizeof(ImageHeader);  // Skip the header.
   1280         std::unique_ptr<MemMap> temp_map(MemMap::MapFile(sizeof(ImageHeader) + stored_size,
   1281                                                          PROT_READ,
   1282                                                          MAP_PRIVATE,
   1283                                                          file->Fd(),
   1284                                                          /*offset*/0,
   1285                                                          /*low_4gb*/false,
   1286                                                          image_filename,
   1287                                                          out_error_msg));
   1288         if (temp_map == nullptr) {
   1289           DCHECK(!out_error_msg->empty());
   1290           return nullptr;
   1291         }
   1292         memcpy(map->Begin(), image_header, sizeof(ImageHeader));
   1293         const uint64_t start = NanoTime();
   1294         // LZ4HC and LZ4 have same internal format, both use LZ4_decompress.
   1295         TimingLogger::ScopedTiming timing2("LZ4 decompress image", &logger);
   1296         const size_t decompressed_size = LZ4_decompress_safe(
   1297             reinterpret_cast<char*>(temp_map->Begin()) + sizeof(ImageHeader),
   1298             reinterpret_cast<char*>(map->Begin()) + decompress_offset,
   1299             stored_size,
   1300             map->Size() - decompress_offset);
   1301         VLOG(image) << "Decompressing image took " << PrettyDuration(NanoTime() - start);
   1302         if (decompressed_size + sizeof(ImageHeader) != image_header->GetImageSize()) {
   1303           *error_msg = StringPrintf(
   1304               "Decompressed size does not match expected image size %zu vs %zu",
   1305               decompressed_size + sizeof(ImageHeader),
   1306               image_header->GetImageSize());
   1307           return nullptr;
   1308         }
   1309       }
   1310     }
   1311     if (map != nullptr) {
   1312       break;
   1313     }
   1314   }
   1315 
   1316   if (map == nullptr) {
   1317     DCHECK(!temp_error_msg.empty());
   1318     *error_msg = temp_error_msg;
   1319     return nullptr;
   1320   }
   1321   DCHECK_EQ(0, memcmp(image_header, map->Begin(), sizeof(ImageHeader)));
   1322 
   1323   std::unique_ptr<MemMap> image_bitmap_map(MemMap::MapFileAtAddress(nullptr,
   1324                                                                     bitmap_section.Size(),
   1325                                                                     PROT_READ, MAP_PRIVATE,
   1326                                                                     file->Fd(),
   1327                                                                     image_bitmap_offset,
   1328                                                                     /*low_4gb*/false,
   1329                                                                     /*reuse*/false,
   1330                                                                     image_filename,
   1331                                                                     error_msg));
   1332   if (image_bitmap_map == nullptr) {
   1333     *error_msg = StringPrintf("Failed to map image bitmap: %s", error_msg->c_str());
   1334     return nullptr;
   1335   }
   1336   // Loaded the map, use the image header from the file now in case we patch it with
   1337   // RelocateInPlace.
   1338   image_header = reinterpret_cast<ImageHeader*>(map->Begin());
   1339   const uint32_t bitmap_index = bitmap_index_.FetchAndAddSequentiallyConsistent(1);
   1340   std::string bitmap_name(StringPrintf("imagespace %s live-bitmap %u",
   1341                                        image_filename,
   1342                                        bitmap_index));
   1343   // Bitmap only needs to cover until the end of the mirror objects section.
   1344   const ImageSection& image_objects = image_header->GetImageSection(ImageHeader::kSectionObjects);
   1345   // We only want the mirror object, not the ArtFields and ArtMethods.
   1346   uint8_t* const image_end = map->Begin() + image_objects.End();
   1347   std::unique_ptr<accounting::ContinuousSpaceBitmap> bitmap;
   1348   {
   1349     TimingLogger::ScopedTiming timing("CreateImageBitmap", &logger);
   1350     bitmap.reset(
   1351       accounting::ContinuousSpaceBitmap::CreateFromMemMap(
   1352           bitmap_name,
   1353           image_bitmap_map.release(),
   1354           reinterpret_cast<uint8_t*>(map->Begin()),
   1355           image_objects.End()));
   1356     if (bitmap == nullptr) {
   1357       *error_msg = StringPrintf("Could not create bitmap '%s'", bitmap_name.c_str());
   1358       return nullptr;
   1359     }
   1360   }
   1361   {
   1362     TimingLogger::ScopedTiming timing("RelocateImage", &logger);
   1363     if (!RelocateInPlace(*image_header,
   1364                          map->Begin(),
   1365                          bitmap.get(),
   1366                          oat_file,
   1367                          error_msg)) {
   1368       return nullptr;
   1369     }
   1370   }
   1371   // We only want the mirror object, not the ArtFields and ArtMethods.
   1372   std::unique_ptr<ImageSpace> space(new ImageSpace(image_filename,
   1373                                                    image_location,
   1374                                                    map.release(),
   1375                                                    bitmap.release(),
   1376                                                    image_end));
   1377 
   1378   // VerifyImageAllocations() will be called later in Runtime::Init()
   1379   // as some class roots like ArtMethod::java_lang_reflect_ArtMethod_
   1380   // and ArtField::java_lang_reflect_ArtField_, which are used from
   1381   // Object::SizeOf() which VerifyImageAllocations() calls, are not
   1382   // set yet at this point.
   1383   if (oat_file == nullptr) {
   1384     TimingLogger::ScopedTiming timing("OpenOatFile", &logger);
   1385     space->oat_file_.reset(space->OpenOatFile(image_filename, error_msg));
   1386     if (space->oat_file_ == nullptr) {
   1387       DCHECK(!error_msg->empty());
   1388       return nullptr;
   1389     }
   1390     space->oat_file_non_owned_ = space->oat_file_.get();
   1391   } else {
   1392     space->oat_file_non_owned_ = oat_file;
   1393   }
   1394 
   1395   if (validate_oat_file) {
   1396     TimingLogger::ScopedTiming timing("ValidateOatFile", &logger);
   1397     if (!space->ValidateOatFile(error_msg)) {
   1398      DCHECK(!error_msg->empty());
   1399       return nullptr;
   1400     }
   1401   }
   1402 
   1403   Runtime* runtime = Runtime::Current();
   1404 
   1405   // If oat_file is null, then it is the boot image space. Use oat_file_non_owned_ from the space
   1406   // to set the runtime methods.
   1407   CHECK_EQ(oat_file != nullptr, image_header->IsAppImage());
   1408   if (image_header->IsAppImage()) {
   1409     CHECK_EQ(runtime->GetResolutionMethod(),
   1410              image_header->GetImageMethod(ImageHeader::kResolutionMethod));
   1411     CHECK_EQ(runtime->GetImtConflictMethod(),
   1412              image_header->GetImageMethod(ImageHeader::kImtConflictMethod));
   1413     CHECK_EQ(runtime->GetImtUnimplementedMethod(),
   1414              image_header->GetImageMethod(ImageHeader::kImtUnimplementedMethod));
   1415     CHECK_EQ(runtime->GetCalleeSaveMethod(Runtime::kSaveAll),
   1416              image_header->GetImageMethod(ImageHeader::kCalleeSaveMethod));
   1417     CHECK_EQ(runtime->GetCalleeSaveMethod(Runtime::kRefsOnly),
   1418              image_header->GetImageMethod(ImageHeader::kRefsOnlySaveMethod));
   1419     CHECK_EQ(runtime->GetCalleeSaveMethod(Runtime::kRefsAndArgs),
   1420              image_header->GetImageMethod(ImageHeader::kRefsAndArgsSaveMethod));
   1421   } else if (!runtime->HasResolutionMethod()) {
   1422     runtime->SetInstructionSet(space->oat_file_non_owned_->GetOatHeader().GetInstructionSet());
   1423     runtime->SetResolutionMethod(image_header->GetImageMethod(ImageHeader::kResolutionMethod));
   1424     runtime->SetImtConflictMethod(image_header->GetImageMethod(ImageHeader::kImtConflictMethod));
   1425     runtime->SetImtUnimplementedMethod(
   1426         image_header->GetImageMethod(ImageHeader::kImtUnimplementedMethod));
   1427     runtime->SetCalleeSaveMethod(
   1428         image_header->GetImageMethod(ImageHeader::kCalleeSaveMethod), Runtime::kSaveAll);
   1429     runtime->SetCalleeSaveMethod(
   1430         image_header->GetImageMethod(ImageHeader::kRefsOnlySaveMethod), Runtime::kRefsOnly);
   1431     runtime->SetCalleeSaveMethod(
   1432         image_header->GetImageMethod(ImageHeader::kRefsAndArgsSaveMethod), Runtime::kRefsAndArgs);
   1433   }
   1434 
   1435   VLOG(image) << "ImageSpace::Init exiting " << *space.get();
   1436   if (VLOG_IS_ON(image)) {
   1437     logger.Dump(LOG(INFO));
   1438   }
   1439   return space.release();
   1440 }
   1441 
   1442 OatFile* ImageSpace::OpenOatFile(const char* image_path, std::string* error_msg) const {
   1443   const ImageHeader& image_header = GetImageHeader();
   1444   std::string oat_filename = ImageHeader::GetOatLocationFromImageLocation(image_path);
   1445 
   1446   CHECK(image_header.GetOatDataBegin() != nullptr);
   1447 
   1448   OatFile* oat_file = OatFile::Open(oat_filename,
   1449                                     oat_filename,
   1450                                     image_header.GetOatDataBegin(),
   1451                                     image_header.GetOatFileBegin(),
   1452                                     !Runtime::Current()->IsAotCompiler(),
   1453                                     /*low_4gb*/false,
   1454                                     nullptr,
   1455                                     error_msg);
   1456   if (oat_file == nullptr) {
   1457     *error_msg = StringPrintf("Failed to open oat file '%s' referenced from image %s: %s",
   1458                               oat_filename.c_str(), GetName(), error_msg->c_str());
   1459     return nullptr;
   1460   }
   1461   uint32_t oat_checksum = oat_file->GetOatHeader().GetChecksum();
   1462   uint32_t image_oat_checksum = image_header.GetOatChecksum();
   1463   if (oat_checksum != image_oat_checksum) {
   1464     *error_msg = StringPrintf("Failed to match oat file checksum 0x%x to expected oat checksum 0x%x"
   1465                               " in image %s", oat_checksum, image_oat_checksum, GetName());
   1466     return nullptr;
   1467   }
   1468   int32_t image_patch_delta = image_header.GetPatchDelta();
   1469   int32_t oat_patch_delta = oat_file->GetOatHeader().GetImagePatchDelta();
   1470   if (oat_patch_delta != image_patch_delta && !image_header.CompilePic()) {
   1471     // We should have already relocated by this point. Bail out.
   1472     *error_msg = StringPrintf("Failed to match oat file patch delta %d to expected patch delta %d "
   1473                               "in image %s", oat_patch_delta, image_patch_delta, GetName());
   1474     return nullptr;
   1475   }
   1476 
   1477   return oat_file;
   1478 }
   1479 
   1480 bool ImageSpace::ValidateOatFile(std::string* error_msg) const {
   1481   CHECK(oat_file_.get() != nullptr);
   1482   for (const OatFile::OatDexFile* oat_dex_file : oat_file_->GetOatDexFiles()) {
   1483     const std::string& dex_file_location = oat_dex_file->GetDexFileLocation();
   1484     uint32_t dex_file_location_checksum;
   1485     if (!DexFile::GetChecksum(dex_file_location.c_str(), &dex_file_location_checksum, error_msg)) {
   1486       *error_msg = StringPrintf("Failed to get checksum of dex file '%s' referenced by image %s: "
   1487                                 "%s", dex_file_location.c_str(), GetName(), error_msg->c_str());
   1488       return false;
   1489     }
   1490     if (dex_file_location_checksum != oat_dex_file->GetDexFileLocationChecksum()) {
   1491       *error_msg = StringPrintf("ValidateOatFile found checksum mismatch between oat file '%s' and "
   1492                                 "dex file '%s' (0x%x != 0x%x)",
   1493                                 oat_file_->GetLocation().c_str(), dex_file_location.c_str(),
   1494                                 oat_dex_file->GetDexFileLocationChecksum(),
   1495                                 dex_file_location_checksum);
   1496       return false;
   1497     }
   1498   }
   1499   return true;
   1500 }
   1501 
   1502 const OatFile* ImageSpace::GetOatFile() const {
   1503   return oat_file_non_owned_;
   1504 }
   1505 
   1506 std::unique_ptr<const OatFile> ImageSpace::ReleaseOatFile() {
   1507   CHECK(oat_file_ != nullptr);
   1508   return std::move(oat_file_);
   1509 }
   1510 
   1511 void ImageSpace::Dump(std::ostream& os) const {
   1512   os << GetType()
   1513       << " begin=" << reinterpret_cast<void*>(Begin())
   1514       << ",end=" << reinterpret_cast<void*>(End())
   1515       << ",size=" << PrettySize(Size())
   1516       << ",name=\"" << GetName() << "\"]";
   1517 }
   1518 
   1519 void ImageSpace::CreateMultiImageLocations(const std::string& input_image_file_name,
   1520                                            const std::string& boot_classpath,
   1521                                            std::vector<std::string>* image_file_names) {
   1522   DCHECK(image_file_names != nullptr);
   1523 
   1524   std::vector<std::string> images;
   1525   Split(boot_classpath, ':', &images);
   1526 
   1527   // Add the rest into the list. We have to adjust locations, possibly:
   1528   //
   1529   // For example, image_file_name is /a/b/c/d/e.art
   1530   //              images[0] is          f/c/d/e.art
   1531   // ----------------------------------------------
   1532   //              images[1] is          g/h/i/j.art  -> /a/b/h/i/j.art
   1533   const std::string& first_image = images[0];
   1534   // Length of common suffix.
   1535   size_t common = 0;
   1536   while (common < input_image_file_name.size() &&
   1537          common < first_image.size() &&
   1538          *(input_image_file_name.end() - common - 1) == *(first_image.end() - common - 1)) {
   1539     ++common;
   1540   }
   1541   // We want to replace the prefix of the input image with the prefix of the boot class path.
   1542   // This handles the case where the image file contains @ separators.
   1543   // Example image_file_name is oats/system@framework (at) boot.art
   1544   // images[0] is .../arm/boot.art
   1545   // means that the image name prefix will be oats/system@framework@
   1546   // so that the other images are openable.
   1547   const size_t old_prefix_length = first_image.size() - common;
   1548   const std::string new_prefix = input_image_file_name.substr(
   1549       0,
   1550       input_image_file_name.size() - common);
   1551 
   1552   // Apply pattern to images[1] .. images[n].
   1553   for (size_t i = 1; i < images.size(); ++i) {
   1554     const std::string& image = images[i];
   1555     CHECK_GT(image.length(), old_prefix_length);
   1556     std::string suffix = image.substr(old_prefix_length);
   1557     image_file_names->push_back(new_prefix + suffix);
   1558   }
   1559 }
   1560 
   1561 ImageSpace* ImageSpace::CreateFromAppImage(const char* image,
   1562                                            const OatFile* oat_file,
   1563                                            std::string* error_msg) {
   1564   return gc::space::ImageSpace::Init(image,
   1565                                      image,
   1566                                      /*validate_oat_file*/false,
   1567                                      oat_file,
   1568                                      /*out*/error_msg);
   1569 }
   1570 
   1571 void ImageSpace::DumpSections(std::ostream& os) const {
   1572   const uint8_t* base = Begin();
   1573   const ImageHeader& header = GetImageHeader();
   1574   for (size_t i = 0; i < ImageHeader::kSectionCount; ++i) {
   1575     auto section_type = static_cast<ImageHeader::ImageSections>(i);
   1576     const ImageSection& section = header.GetImageSection(section_type);
   1577     os << section_type << " " << reinterpret_cast<const void*>(base + section.Offset())
   1578        << "-" << reinterpret_cast<const void*>(base + section.End()) << "\n";
   1579   }
   1580 }
   1581 
   1582 }  // namespace space
   1583 }  // namespace gc
   1584 }  // namespace art
   1585