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 <sys/statvfs.h>
20 #include <sys/types.h>
21 #include <unistd.h>
22 
23 #include <random>
24 
25 #include "android-base/stringprintf.h"
26 #include "android-base/strings.h"
27 #include "android-base/unique_fd.h"
28 
29 #include "arch/instruction_set.h"
30 #include "art_field-inl.h"
31 #include "art_method-inl.h"
32 #include "base/array_ref.h"
33 #include "base/bit_memory_region.h"
34 #include "base/callee_save_type.h"
35 #include "base/enums.h"
36 #include "base/file_utils.h"
37 #include "base/macros.h"
38 #include "base/memfd.h"
39 #include "base/os.h"
40 #include "base/scoped_flock.h"
41 #include "base/stl_util.h"
42 #include "base/string_view_cpp20.h"
43 #include "base/systrace.h"
44 #include "base/time_utils.h"
45 #include "base/utils.h"
46 #include "class_root-inl.h"
47 #include "dex/art_dex_file_loader.h"
48 #include "dex/dex_file_loader.h"
49 #include "exec_utils.h"
50 #include "gc/accounting/space_bitmap-inl.h"
51 #include "gc/task_processor.h"
52 #include "image-inl.h"
53 #include "intern_table-inl.h"
54 #include "mirror/class-inl.h"
55 #include "mirror/executable-inl.h"
56 #include "mirror/object-inl.h"
57 #include "mirror/object-refvisitor-inl.h"
58 #include "oat.h"
59 #include "oat_file.h"
60 #include "profile/profile_compilation_info.h"
61 #include "runtime.h"
62 #include "space-inl.h"
63 
64 namespace art {
65 namespace gc {
66 namespace space {
67 
68 using android::base::Join;
69 using android::base::StringAppendF;
70 using android::base::StringPrintf;
71 
72 // We do not allow the boot image and extensions to take more than 1GiB. They are
73 // supposed to be much smaller and allocating more that this would likely fail anyway.
74 static constexpr size_t kMaxTotalImageReservationSize = 1 * GB;
75 
76 Atomic<uint32_t> ImageSpace::bitmap_index_(0);
77 
ImageSpace(const std::string & image_filename,const char * image_location,const char * profile_file,MemMap && mem_map,accounting::ContinuousSpaceBitmap && live_bitmap,uint8_t * end)78 ImageSpace::ImageSpace(const std::string& image_filename,
79                        const char* image_location,
80                        const char* profile_file,
81                        MemMap&& mem_map,
82                        accounting::ContinuousSpaceBitmap&& live_bitmap,
83                        uint8_t* end)
84     : MemMapSpace(image_filename,
85                   std::move(mem_map),
86                   mem_map.Begin(),
87                   end,
88                   end,
89                   kGcRetentionPolicyNeverCollect),
90       live_bitmap_(std::move(live_bitmap)),
91       oat_file_non_owned_(nullptr),
92       image_location_(image_location),
93       profile_file_(profile_file) {
94   DCHECK(live_bitmap_.IsValid());
95 }
96 
ChooseRelocationOffsetDelta(int32_t min_delta,int32_t max_delta)97 static int32_t ChooseRelocationOffsetDelta(int32_t min_delta, int32_t max_delta) {
98   CHECK_ALIGNED(min_delta, kPageSize);
99   CHECK_ALIGNED(max_delta, kPageSize);
100   CHECK_LT(min_delta, max_delta);
101 
102   int32_t r = GetRandomNumber<int32_t>(min_delta, max_delta);
103   if (r % 2 == 0) {
104     r = RoundUp(r, kPageSize);
105   } else {
106     r = RoundDown(r, kPageSize);
107   }
108   CHECK_LE(min_delta, r);
109   CHECK_GE(max_delta, r);
110   CHECK_ALIGNED(r, kPageSize);
111   return r;
112 }
113 
ChooseRelocationOffsetDelta()114 static int32_t ChooseRelocationOffsetDelta() {
115   return ChooseRelocationOffsetDelta(ART_BASE_ADDRESS_MIN_DELTA, ART_BASE_ADDRESS_MAX_DELTA);
116 }
117 
FindImageFilenameImpl(const char * image_location,const InstructionSet image_isa,bool * has_system,std::string * system_filename)118 static bool FindImageFilenameImpl(const char* image_location,
119                                   const InstructionSet image_isa,
120                                   bool* has_system,
121                                   std::string* system_filename) {
122   *has_system = false;
123 
124   // image_location = /system/framework/boot.art
125   // system_image_location = /system/framework/<image_isa>/boot.art
126   std::string system_image_filename(GetSystemImageFilename(image_location, image_isa));
127   if (OS::FileExists(system_image_filename.c_str())) {
128     *system_filename = system_image_filename;
129     *has_system = true;
130   }
131 
132   return *has_system;
133 }
134 
FindImageFilename(const char * image_location,const InstructionSet image_isa,std::string * system_filename,bool * has_system)135 bool ImageSpace::FindImageFilename(const char* image_location,
136                                    const InstructionSet image_isa,
137                                    std::string* system_filename,
138                                    bool* has_system) {
139   std::string dalvik_cache_unused;
140   return FindImageFilenameImpl(image_location,
141                                image_isa,
142                                has_system,
143                                system_filename);
144 }
145 
ReadSpecificImageHeader(File * image_file,const char * file_description,ImageHeader * image_header,std::string * error_msg)146 static bool ReadSpecificImageHeader(File* image_file,
147                                     const char* file_description,
148                                     /*out*/ImageHeader* image_header,
149                                     /*out*/std::string* error_msg) {
150     if (!image_file->ReadFully(image_header, sizeof(ImageHeader))) {
151       *error_msg = StringPrintf("Unable to read image header from \"%s\"", file_description);
152       return false;
153     }
154     if (!image_header->IsValid()) {
155       *error_msg = StringPrintf("Image header from \"%s\" is invalid", file_description);
156       return false;
157     }
158     return true;
159 }
160 
ReadSpecificImageHeader(const char * filename,ImageHeader * image_header,std::string * error_msg)161 static bool ReadSpecificImageHeader(const char* filename,
162                                     /*out*/ImageHeader* image_header,
163                                     /*out*/std::string* error_msg) {
164   std::unique_ptr<File> image_file(OS::OpenFileForReading(filename));
165   if (image_file.get() == nullptr) {
166     *error_msg = StringPrintf("Unable to open file \"%s\" for reading image header", filename);
167     return false;
168   }
169   return ReadSpecificImageHeader(image_file.get(), filename, image_header, error_msg);
170 }
171 
ReadSpecificImageHeader(const char * filename,std::string * error_msg)172 static std::unique_ptr<ImageHeader> ReadSpecificImageHeader(const char* filename,
173                                                             std::string* error_msg) {
174   std::unique_ptr<ImageHeader> hdr(new ImageHeader);
175   if (!ReadSpecificImageHeader(filename, hdr.get(), error_msg)) {
176     return nullptr;
177   }
178   return hdr;
179 }
180 
VerifyImageAllocations()181 void ImageSpace::VerifyImageAllocations() {
182   uint8_t* current = Begin() + RoundUp(sizeof(ImageHeader), kObjectAlignment);
183   while (current < End()) {
184     CHECK_ALIGNED(current, kObjectAlignment);
185     auto* obj = reinterpret_cast<mirror::Object*>(current);
186     CHECK(obj->GetClass() != nullptr) << "Image object at address " << obj << " has null class";
187     CHECK(live_bitmap_.Test(obj)) << obj->PrettyTypeOf();
188     if (kUseBakerReadBarrier) {
189       obj->AssertReadBarrierState();
190     }
191     current += RoundUp(obj->SizeOf(), kObjectAlignment);
192   }
193 }
194 
195 // Helper class for relocating from one range of memory to another.
196 class RelocationRange {
197  public:
198   RelocationRange() = default;
199   RelocationRange(const RelocationRange&) = default;
RelocationRange(uintptr_t source,uintptr_t dest,uintptr_t length)200   RelocationRange(uintptr_t source, uintptr_t dest, uintptr_t length)
201       : source_(source),
202         dest_(dest),
203         length_(length) {}
204 
InSource(uintptr_t address) const205   bool InSource(uintptr_t address) const {
206     return address - source_ < length_;
207   }
208 
InDest(const void * dest) const209   bool InDest(const void* dest) const {
210     return InDest(reinterpret_cast<uintptr_t>(dest));
211   }
212 
InDest(uintptr_t address) const213   bool InDest(uintptr_t address) const {
214     return address - dest_ < length_;
215   }
216 
217   // Translate a source address to the destination space.
ToDest(uintptr_t address) const218   uintptr_t ToDest(uintptr_t address) const {
219     DCHECK(InSource(address));
220     return address + Delta();
221   }
222 
223   template <typename T>
ToDest(T * src) const224   T* ToDest(T* src) const {
225     return reinterpret_cast<T*>(ToDest(reinterpret_cast<uintptr_t>(src)));
226   }
227 
228   // Returns the delta between the dest from the source.
Delta() const229   uintptr_t Delta() const {
230     return dest_ - source_;
231   }
232 
Source() const233   uintptr_t Source() const {
234     return source_;
235   }
236 
Dest() const237   uintptr_t Dest() const {
238     return dest_;
239   }
240 
Length() const241   uintptr_t Length() const {
242     return length_;
243   }
244 
245  private:
246   const uintptr_t source_;
247   const uintptr_t dest_;
248   const uintptr_t length_;
249 };
250 
operator <<(std::ostream & os,const RelocationRange & reloc)251 std::ostream& operator<<(std::ostream& os, const RelocationRange& reloc) {
252   return os << "(" << reinterpret_cast<const void*>(reloc.Source()) << "-"
253             << reinterpret_cast<const void*>(reloc.Source() + reloc.Length()) << ")->("
254             << reinterpret_cast<const void*>(reloc.Dest()) << "-"
255             << reinterpret_cast<const void*>(reloc.Dest() + reloc.Length()) << ")";
256 }
257 
258 template <PointerSize kPointerSize, typename HeapVisitor, typename NativeVisitor>
259 class ImageSpace::PatchObjectVisitor final {
260  public:
PatchObjectVisitor(HeapVisitor heap_visitor,NativeVisitor native_visitor)261   explicit PatchObjectVisitor(HeapVisitor heap_visitor, NativeVisitor native_visitor)
262       : heap_visitor_(heap_visitor), native_visitor_(native_visitor) {}
263 
VisitClass(ObjPtr<mirror::Class> klass,ObjPtr<mirror::Class> class_class)264   void VisitClass(ObjPtr<mirror::Class> klass, ObjPtr<mirror::Class> class_class)
265       REQUIRES_SHARED(Locks::mutator_lock_) {
266     // A mirror::Class object consists of
267     //  - instance fields inherited from j.l.Object,
268     //  - instance fields inherited from j.l.Class,
269     //  - embedded tables (vtable, interface method table),
270     //  - static fields of the class itself.
271     // The reference fields are at the start of each field section (this is how the
272     // ClassLinker orders fields; except when that would create a gap between superclass
273     // fields and the first reference of the subclass due to alignment, it can be filled
274     // with smaller fields - but that's not the case for j.l.Object and j.l.Class).
275 
276     DCHECK_ALIGNED(klass.Ptr(), kObjectAlignment);
277     static_assert(IsAligned<kHeapReferenceSize>(kObjectAlignment), "Object alignment check.");
278     // First, patch the `klass->klass_`, known to be a reference to the j.l.Class.class.
279     // This should be the only reference field in j.l.Object and we assert that below.
280     DCHECK_EQ(class_class,
281               heap_visitor_(klass->GetClass<kVerifyNone, kWithoutReadBarrier>()));
282     klass->SetFieldObjectWithoutWriteBarrier<
283         /*kTransactionActive=*/ false,
284         /*kCheckTransaction=*/ true,
285         kVerifyNone>(mirror::Object::ClassOffset(), class_class);
286     // Then patch the reference instance fields described by j.l.Class.class.
287     // Use the sizeof(Object) to determine where these reference fields start;
288     // this is the same as `class_class->GetFirstReferenceInstanceFieldOffset()`
289     // after patching but the j.l.Class may not have been patched yet.
290     size_t num_reference_instance_fields = class_class->NumReferenceInstanceFields<kVerifyNone>();
291     DCHECK_NE(num_reference_instance_fields, 0u);
292     static_assert(IsAligned<kHeapReferenceSize>(sizeof(mirror::Object)), "Size alignment check.");
293     MemberOffset instance_field_offset(sizeof(mirror::Object));
294     for (size_t i = 0; i != num_reference_instance_fields; ++i) {
295       PatchReferenceField(klass, instance_field_offset);
296       static_assert(sizeof(mirror::HeapReference<mirror::Object>) == kHeapReferenceSize,
297                     "Heap reference sizes equality check.");
298       instance_field_offset =
299           MemberOffset(instance_field_offset.Uint32Value() + kHeapReferenceSize);
300     }
301     // Now that we have patched the `super_class_`, if this is the j.l.Class.class,
302     // we can get a reference to j.l.Object.class and assert that it has only one
303     // reference instance field (the `klass_` patched above).
304     if (kIsDebugBuild && klass == class_class) {
305       ObjPtr<mirror::Class> object_class =
306           klass->GetSuperClass<kVerifyNone, kWithoutReadBarrier>();
307       CHECK_EQ(object_class->NumReferenceInstanceFields<kVerifyNone>(), 1u);
308     }
309     // Then patch static fields.
310     size_t num_reference_static_fields = klass->NumReferenceStaticFields<kVerifyNone>();
311     if (num_reference_static_fields != 0u) {
312       MemberOffset static_field_offset =
313           klass->GetFirstReferenceStaticFieldOffset<kVerifyNone>(kPointerSize);
314       for (size_t i = 0; i != num_reference_static_fields; ++i) {
315         PatchReferenceField(klass, static_field_offset);
316         static_assert(sizeof(mirror::HeapReference<mirror::Object>) == kHeapReferenceSize,
317                       "Heap reference sizes equality check.");
318         static_field_offset =
319             MemberOffset(static_field_offset.Uint32Value() + kHeapReferenceSize);
320       }
321     }
322     // Then patch native pointers.
323     klass->FixupNativePointers<kVerifyNone>(klass.Ptr(), kPointerSize, *this);
324   }
325 
326   template <typename T>
operator ()(T * ptr,void ** dest_addr ATTRIBUTE_UNUSED) const327   T* operator()(T* ptr, void** dest_addr ATTRIBUTE_UNUSED) const {
328     return (ptr != nullptr) ? native_visitor_(ptr) : nullptr;
329   }
330 
VisitPointerArray(ObjPtr<mirror::PointerArray> pointer_array)331   void VisitPointerArray(ObjPtr<mirror::PointerArray> pointer_array)
332       REQUIRES_SHARED(Locks::mutator_lock_) {
333     // Fully patch the pointer array, including the `klass_` field.
334     PatchReferenceField</*kMayBeNull=*/ false>(pointer_array, mirror::Object::ClassOffset());
335 
336     int32_t length = pointer_array->GetLength<kVerifyNone>();
337     for (int32_t i = 0; i != length; ++i) {
338       ArtMethod** method_entry = reinterpret_cast<ArtMethod**>(
339           pointer_array->ElementAddress<kVerifyNone>(i, kPointerSize));
340       PatchNativePointer</*kMayBeNull=*/ false>(method_entry);
341     }
342   }
343 
VisitObject(mirror::Object * object)344   void VisitObject(mirror::Object* object) REQUIRES_SHARED(Locks::mutator_lock_) {
345     // Visit all reference fields.
346     object->VisitReferences</*kVisitNativeRoots=*/ false,
347                             kVerifyNone,
348                             kWithoutReadBarrier>(*this, *this);
349     // This function should not be called for classes.
350     DCHECK(!object->IsClass<kVerifyNone>());
351   }
352 
353   // Visitor for VisitReferences().
operator ()(ObjPtr<mirror::Object> object,MemberOffset field_offset,bool is_static) const354   ALWAYS_INLINE void operator()(ObjPtr<mirror::Object> object,
355                                 MemberOffset field_offset,
356                                 bool is_static)
357       const REQUIRES_SHARED(Locks::mutator_lock_) {
358     DCHECK(!is_static);
359     PatchReferenceField(object, field_offset);
360   }
361   // Visitor for VisitReferences(), java.lang.ref.Reference case.
operator ()(ObjPtr<mirror::Class> klass,ObjPtr<mirror::Reference> ref) const362   ALWAYS_INLINE void operator()(ObjPtr<mirror::Class> klass, ObjPtr<mirror::Reference> ref) const
363       REQUIRES_SHARED(Locks::mutator_lock_) {
364     DCHECK(klass->IsTypeOfReferenceClass());
365     this->operator()(ref, mirror::Reference::ReferentOffset(), /*is_static=*/ false);
366   }
367   // Ignore class native roots; not called from VisitReferences() for kVisitNativeRoots == false.
VisitRootIfNonNull(mirror::CompressedReference<mirror::Object> * root ATTRIBUTE_UNUSED) const368   void VisitRootIfNonNull(mirror::CompressedReference<mirror::Object>* root ATTRIBUTE_UNUSED)
369       const {}
VisitRoot(mirror::CompressedReference<mirror::Object> * root ATTRIBUTE_UNUSED) const370   void VisitRoot(mirror::CompressedReference<mirror::Object>* root ATTRIBUTE_UNUSED) const {}
371 
372   template <bool kMayBeNull = true, typename T>
PatchGcRoot(GcRoot<T> * root) const373   ALWAYS_INLINE void PatchGcRoot(/*inout*/GcRoot<T>* root) const
374       REQUIRES_SHARED(Locks::mutator_lock_) {
375     static_assert(sizeof(GcRoot<mirror::Class*>) == sizeof(uint32_t), "GcRoot size check");
376     T* old_value = root->template Read<kWithoutReadBarrier>();
377     DCHECK(kMayBeNull || old_value != nullptr);
378     if (!kMayBeNull || old_value != nullptr) {
379       *root = GcRoot<T>(heap_visitor_(old_value));
380     }
381   }
382 
383   template <bool kMayBeNull = true, typename T>
PatchNativePointer(T ** entry) const384   ALWAYS_INLINE void PatchNativePointer(/*inout*/T** entry) const {
385     if (kPointerSize == PointerSize::k64) {
386       uint64_t* raw_entry = reinterpret_cast<uint64_t*>(entry);
387       T* old_value = reinterpret_cast64<T*>(*raw_entry);
388       DCHECK(kMayBeNull || old_value != nullptr);
389       if (!kMayBeNull || old_value != nullptr) {
390         T* new_value = native_visitor_(old_value);
391         *raw_entry = reinterpret_cast64<uint64_t>(new_value);
392       }
393     } else {
394       uint32_t* raw_entry = reinterpret_cast<uint32_t*>(entry);
395       T* old_value = reinterpret_cast32<T*>(*raw_entry);
396       DCHECK(kMayBeNull || old_value != nullptr);
397       if (!kMayBeNull || old_value != nullptr) {
398         T* new_value = native_visitor_(old_value);
399         *raw_entry = reinterpret_cast32<uint32_t>(new_value);
400       }
401     }
402   }
403 
404   template <bool kMayBeNull = true>
PatchReferenceField(ObjPtr<mirror::Object> object,MemberOffset offset) const405   ALWAYS_INLINE void PatchReferenceField(ObjPtr<mirror::Object> object, MemberOffset offset) const
406       REQUIRES_SHARED(Locks::mutator_lock_) {
407     ObjPtr<mirror::Object> old_value =
408         object->GetFieldObject<mirror::Object, kVerifyNone, kWithoutReadBarrier>(offset);
409     DCHECK(kMayBeNull || old_value != nullptr);
410     if (!kMayBeNull || old_value != nullptr) {
411       ObjPtr<mirror::Object> new_value = heap_visitor_(old_value.Ptr());
412       object->SetFieldObjectWithoutWriteBarrier</*kTransactionActive=*/ false,
413                                                 /*kCheckTransaction=*/ true,
414                                                 kVerifyNone>(offset, new_value);
415     }
416   }
417 
418  private:
419   // Heap objects visitor.
420   HeapVisitor heap_visitor_;
421 
422   // Native objects visitor.
423   NativeVisitor native_visitor_;
424 };
425 
426 template <typename ReferenceVisitor>
427 class ImageSpace::ClassTableVisitor final {
428  public:
ClassTableVisitor(const ReferenceVisitor & reference_visitor)429   explicit ClassTableVisitor(const ReferenceVisitor& reference_visitor)
430       : reference_visitor_(reference_visitor) {}
431 
VisitRoot(mirror::CompressedReference<mirror::Object> * root) const432   void VisitRoot(mirror::CompressedReference<mirror::Object>* root) const
433       REQUIRES_SHARED(Locks::mutator_lock_) {
434     DCHECK(root->AsMirrorPtr() != nullptr);
435     root->Assign(reference_visitor_(root->AsMirrorPtr()));
436   }
437 
438  private:
439   ReferenceVisitor reference_visitor_;
440 };
441 
442 class ImageSpace::RemapInternedStringsVisitor {
443  public:
RemapInternedStringsVisitor(const SafeMap<mirror::String *,mirror::String * > & intern_remap)444   explicit RemapInternedStringsVisitor(
445       const SafeMap<mirror::String*, mirror::String*>& intern_remap)
446       REQUIRES_SHARED(Locks::mutator_lock_)
447       : intern_remap_(intern_remap),
448         string_class_(GetStringClass()) {}
449 
450   // Visitor for VisitReferences().
operator ()(ObjPtr<mirror::Object> object,MemberOffset field_offset,bool is_static ATTRIBUTE_UNUSED) const451   ALWAYS_INLINE void operator()(ObjPtr<mirror::Object> object,
452                                 MemberOffset field_offset,
453                                 bool is_static ATTRIBUTE_UNUSED)
454       const REQUIRES_SHARED(Locks::mutator_lock_) {
455     ObjPtr<mirror::Object> old_value =
456         object->GetFieldObject<mirror::Object, kVerifyNone, kWithoutReadBarrier>(field_offset);
457     if (old_value != nullptr &&
458         old_value->GetClass<kVerifyNone, kWithoutReadBarrier>() == string_class_) {
459       auto it = intern_remap_.find(old_value->AsString().Ptr());
460       if (it != intern_remap_.end()) {
461         mirror::String* new_value = it->second;
462         object->SetFieldObjectWithoutWriteBarrier</*kTransactionActive=*/ false,
463                                                   /*kCheckTransaction=*/ true,
464                                                   kVerifyNone>(field_offset, new_value);
465       }
466     }
467   }
468   // Visitor for VisitReferences(), java.lang.ref.Reference case.
operator ()(ObjPtr<mirror::Class> klass,ObjPtr<mirror::Reference> ref) const469   ALWAYS_INLINE void operator()(ObjPtr<mirror::Class> klass, ObjPtr<mirror::Reference> ref) const
470       REQUIRES_SHARED(Locks::mutator_lock_) {
471     DCHECK(klass->IsTypeOfReferenceClass());
472     this->operator()(ref, mirror::Reference::ReferentOffset(), /*is_static=*/ false);
473   }
474   // Ignore class native roots; not called from VisitReferences() for kVisitNativeRoots == false.
VisitRootIfNonNull(mirror::CompressedReference<mirror::Object> * root ATTRIBUTE_UNUSED) const475   void VisitRootIfNonNull(mirror::CompressedReference<mirror::Object>* root ATTRIBUTE_UNUSED)
476       const {}
VisitRoot(mirror::CompressedReference<mirror::Object> * root ATTRIBUTE_UNUSED) const477   void VisitRoot(mirror::CompressedReference<mirror::Object>* root ATTRIBUTE_UNUSED) const {}
478 
479  private:
GetStringClass()480   mirror::Class* GetStringClass() REQUIRES_SHARED(Locks::mutator_lock_) {
481     DCHECK(!intern_remap_.empty());
482     return intern_remap_.begin()->first->GetClass<kVerifyNone, kWithoutReadBarrier>();
483   }
484 
485   const SafeMap<mirror::String*, mirror::String*>& intern_remap_;
486   mirror::Class* const string_class_;
487 };
488 
489 // Helper class encapsulating loading, so we can access private ImageSpace members (this is a
490 // nested class), but not declare functions in the header.
491 class ImageSpace::Loader {
492  public:
InitAppImage(const char * image_filename,const char * image_location,const OatFile * oat_file,ArrayRef<ImageSpace * const> boot_image_spaces,std::string * error_msg)493   static std::unique_ptr<ImageSpace> InitAppImage(const char* image_filename,
494                                                   const char* image_location,
495                                                   const OatFile* oat_file,
496                                                   ArrayRef<ImageSpace* const> boot_image_spaces,
497                                                   /*out*/std::string* error_msg)
498       REQUIRES_SHARED(Locks::mutator_lock_) {
499     TimingLogger logger(__PRETTY_FUNCTION__, /*precise=*/ true, VLOG_IS_ON(image));
500 
501     std::unique_ptr<ImageSpace> space = Init(image_filename,
502                                              image_location,
503                                              &logger,
504                                              /*image_reservation=*/ nullptr,
505                                              error_msg);
506     if (space != nullptr) {
507       space->oat_file_non_owned_ = oat_file;
508       const ImageHeader& image_header = space->GetImageHeader();
509 
510       // Check the oat file checksum.
511       const uint32_t oat_checksum = oat_file->GetOatHeader().GetChecksum();
512       const uint32_t image_oat_checksum = image_header.GetOatChecksum();
513       if (oat_checksum != image_oat_checksum) {
514         *error_msg = StringPrintf("Oat checksum 0x%x does not match the image one 0x%x in image %s",
515                                   oat_checksum,
516                                   image_oat_checksum,
517                                   image_filename);
518         return nullptr;
519       }
520       size_t boot_image_space_dependencies;
521       if (!ValidateBootImageChecksum(image_filename,
522                                      image_header,
523                                      oat_file,
524                                      boot_image_spaces,
525                                      &boot_image_space_dependencies,
526                                      error_msg)) {
527         DCHECK(!error_msg->empty());
528         return nullptr;
529       }
530 
531       uint32_t expected_reservation_size = RoundUp(image_header.GetImageSize(), kPageSize);
532       if (!CheckImageReservationSize(*space, expected_reservation_size, error_msg) ||
533           !CheckImageComponentCount(*space, /*expected_component_count=*/ 1u, error_msg)) {
534         return nullptr;
535       }
536 
537       {
538         TimingLogger::ScopedTiming timing("RelocateImage", &logger);
539         const PointerSize pointer_size = image_header.GetPointerSize();
540         uint32_t boot_image_begin =
541             reinterpret_cast32<uint32_t>(boot_image_spaces.front()->Begin());
542         bool result;
543         if (pointer_size == PointerSize::k64) {
544           result = RelocateInPlace<PointerSize::k64>(boot_image_begin,
545                                                      space->GetMemMap()->Begin(),
546                                                      space->GetLiveBitmap(),
547                                                      oat_file,
548                                                      error_msg);
549         } else {
550           result = RelocateInPlace<PointerSize::k32>(boot_image_begin,
551                                                      space->GetMemMap()->Begin(),
552                                                      space->GetLiveBitmap(),
553                                                      oat_file,
554                                                      error_msg);
555         }
556         if (!result) {
557           return nullptr;
558         }
559       }
560 
561       DCHECK_LE(boot_image_space_dependencies, boot_image_spaces.size());
562       if (boot_image_space_dependencies != boot_image_spaces.size()) {
563         TimingLogger::ScopedTiming timing("DeduplicateInternedStrings", &logger);
564         // There shall be no duplicates with boot image spaces this app image depends on.
565         ArrayRef<ImageSpace* const> old_spaces =
566             boot_image_spaces.SubArray(/*pos=*/ boot_image_space_dependencies);
567         SafeMap<mirror::String*, mirror::String*> intern_remap;
568         RemoveInternTableDuplicates(old_spaces, space.get(), &intern_remap);
569         if (!intern_remap.empty()) {
570           RemapInternedStringDuplicates(intern_remap, space.get());
571         }
572       }
573 
574       const ImageHeader& primary_header = boot_image_spaces.front()->GetImageHeader();
575       static_assert(static_cast<size_t>(ImageHeader::kResolutionMethod) == 0u);
576       for (size_t i = 0u; i != static_cast<size_t>(ImageHeader::kImageMethodsCount); ++i) {
577         ImageHeader::ImageMethod method = static_cast<ImageHeader::ImageMethod>(i);
578         CHECK_EQ(primary_header.GetImageMethod(method), image_header.GetImageMethod(method))
579             << method;
580       }
581 
582       VLOG(image) << "ImageSpace::Loader::InitAppImage exiting " << *space.get();
583     }
584     if (VLOG_IS_ON(image)) {
585       logger.Dump(LOG_STREAM(INFO));
586     }
587     return space;
588   }
589 
Init(const char * image_filename,const char * image_location,TimingLogger * logger,MemMap * image_reservation,std::string * error_msg)590   static std::unique_ptr<ImageSpace> Init(const char* image_filename,
591                                           const char* image_location,
592                                           TimingLogger* logger,
593                                           /*inout*/MemMap* image_reservation,
594                                           /*out*/std::string* error_msg)
595       REQUIRES_SHARED(Locks::mutator_lock_) {
596     CHECK(image_filename != nullptr);
597     CHECK(image_location != nullptr);
598 
599     std::unique_ptr<File> file;
600     {
601       TimingLogger::ScopedTiming timing("OpenImageFile", logger);
602       file.reset(OS::OpenFileForReading(image_filename));
603       if (file == nullptr) {
604         *error_msg = StringPrintf("Failed to open '%s'", image_filename);
605         return nullptr;
606       }
607     }
608     return Init(file.get(),
609                 image_filename,
610                 image_location,
611                 /* profile_file=*/ "",
612                 /*allow_direct_mapping=*/ true,
613                 logger,
614                 image_reservation,
615                 error_msg);
616   }
617 
Init(File * file,const char * image_filename,const char * image_location,const char * profile_file,bool allow_direct_mapping,TimingLogger * logger,MemMap * image_reservation,std::string * error_msg)618   static std::unique_ptr<ImageSpace> Init(File* file,
619                                           const char* image_filename,
620                                           const char* image_location,
621                                           const char* profile_file,
622                                           bool allow_direct_mapping,
623                                           TimingLogger* logger,
624                                           /*inout*/MemMap* image_reservation,
625                                           /*out*/std::string* error_msg)
626       REQUIRES_SHARED(Locks::mutator_lock_) {
627     CHECK(image_filename != nullptr);
628     CHECK(image_location != nullptr);
629 
630     VLOG(image) << "ImageSpace::Init entering image_filename=" << image_filename;
631 
632     ImageHeader image_header;
633     {
634       TimingLogger::ScopedTiming timing("ReadImageHeader", logger);
635       bool success = file->PreadFully(&image_header, sizeof(image_header), /*offset=*/ 0u);
636       if (!success || !image_header.IsValid()) {
637         *error_msg = StringPrintf("Invalid image header in '%s'", image_filename);
638         return nullptr;
639       }
640     }
641     // Check that the file is larger or equal to the header size + data size.
642     const uint64_t image_file_size = static_cast<uint64_t>(file->GetLength());
643     if (image_file_size < sizeof(ImageHeader) + image_header.GetDataSize()) {
644       *error_msg = StringPrintf(
645           "Image file truncated: %" PRIu64 " vs. %" PRIu64 ".",
646            image_file_size,
647            static_cast<uint64_t>(sizeof(ImageHeader) + image_header.GetDataSize()));
648       return nullptr;
649     }
650 
651     if (VLOG_IS_ON(startup)) {
652       LOG(INFO) << "Dumping image sections";
653       for (size_t i = 0; i < ImageHeader::kSectionCount; ++i) {
654         const auto section_idx = static_cast<ImageHeader::ImageSections>(i);
655         auto& section = image_header.GetImageSection(section_idx);
656         LOG(INFO) << section_idx << " start="
657             << reinterpret_cast<void*>(image_header.GetImageBegin() + section.Offset()) << " "
658             << section;
659       }
660     }
661 
662     const auto& bitmap_section = image_header.GetImageBitmapSection();
663     // The location we want to map from is the first aligned page after the end of the stored
664     // (possibly compressed) data.
665     const size_t image_bitmap_offset =
666         RoundUp(sizeof(ImageHeader) + image_header.GetDataSize(), kPageSize);
667     const size_t end_of_bitmap = image_bitmap_offset + bitmap_section.Size();
668     if (end_of_bitmap != image_file_size) {
669       *error_msg = StringPrintf(
670           "Image file size does not equal end of bitmap: size=%" PRIu64 " vs. %zu.",
671           image_file_size,
672           end_of_bitmap);
673       return nullptr;
674     }
675 
676     // GetImageBegin is the preferred address to map the image. If we manage to map the
677     // image at the image begin, the amount of fixup work required is minimized.
678     // If it is pic we will retry with error_msg for the2 failure case. Pass a null error_msg to
679     // avoid reading proc maps for a mapping failure and slowing everything down.
680     // For the boot image, we have already reserved the memory and we load the image
681     // into the `image_reservation`.
682     MemMap map = LoadImageFile(
683         image_filename,
684         image_location,
685         image_header,
686         file->Fd(),
687         allow_direct_mapping,
688         logger,
689         image_reservation,
690         error_msg);
691     if (!map.IsValid()) {
692       DCHECK(!error_msg->empty());
693       return nullptr;
694     }
695     DCHECK_EQ(0, memcmp(&image_header, map.Begin(), sizeof(ImageHeader)));
696 
697     MemMap image_bitmap_map = MemMap::MapFile(bitmap_section.Size(),
698                                               PROT_READ,
699                                               MAP_PRIVATE,
700                                               file->Fd(),
701                                               image_bitmap_offset,
702                                               /*low_4gb=*/ false,
703                                               image_filename,
704                                               error_msg);
705     if (!image_bitmap_map.IsValid()) {
706       *error_msg = StringPrintf("Failed to map image bitmap: %s", error_msg->c_str());
707       return nullptr;
708     }
709     const uint32_t bitmap_index = ImageSpace::bitmap_index_.fetch_add(1);
710     std::string bitmap_name(StringPrintf("imagespace %s live-bitmap %u",
711                                          image_filename,
712                                          bitmap_index));
713     // Bitmap only needs to cover until the end of the mirror objects section.
714     const ImageSection& image_objects = image_header.GetObjectsSection();
715     // We only want the mirror object, not the ArtFields and ArtMethods.
716     uint8_t* const image_end = map.Begin() + image_objects.End();
717     accounting::ContinuousSpaceBitmap bitmap;
718     {
719       TimingLogger::ScopedTiming timing("CreateImageBitmap", logger);
720       bitmap = accounting::ContinuousSpaceBitmap::CreateFromMemMap(
721           bitmap_name,
722           std::move(image_bitmap_map),
723           reinterpret_cast<uint8_t*>(map.Begin()),
724           // Make sure the bitmap is aligned to card size instead of just bitmap word size.
725           RoundUp(image_objects.End(), gc::accounting::CardTable::kCardSize));
726       if (!bitmap.IsValid()) {
727         *error_msg = StringPrintf("Could not create bitmap '%s'", bitmap_name.c_str());
728         return nullptr;
729       }
730     }
731     // We only want the mirror object, not the ArtFields and ArtMethods.
732     std::unique_ptr<ImageSpace> space(new ImageSpace(image_filename,
733                                                      image_location,
734                                                      profile_file,
735                                                      std::move(map),
736                                                      std::move(bitmap),
737                                                      image_end));
738     return space;
739   }
740 
CheckImageComponentCount(const ImageSpace & space,uint32_t expected_component_count,std::string * error_msg)741   static bool CheckImageComponentCount(const ImageSpace& space,
742                                        uint32_t expected_component_count,
743                                        /*out*/std::string* error_msg) {
744     const ImageHeader& header = space.GetImageHeader();
745     if (header.GetComponentCount() != expected_component_count) {
746       *error_msg = StringPrintf("Unexpected component count in %s, received %u, expected %u",
747                                 space.GetImageFilename().c_str(),
748                                 header.GetComponentCount(),
749                                 expected_component_count);
750       return false;
751     }
752     return true;
753   }
754 
CheckImageReservationSize(const ImageSpace & space,uint32_t expected_reservation_size,std::string * error_msg)755   static bool CheckImageReservationSize(const ImageSpace& space,
756                                         uint32_t expected_reservation_size,
757                                         /*out*/std::string* error_msg) {
758     const ImageHeader& header = space.GetImageHeader();
759     if (header.GetImageReservationSize() != expected_reservation_size) {
760       *error_msg = StringPrintf("Unexpected reservation size in %s, received %u, expected %u",
761                                 space.GetImageFilename().c_str(),
762                                 header.GetImageReservationSize(),
763                                 expected_reservation_size);
764       return false;
765     }
766     return true;
767   }
768 
769   template <typename Container>
RemoveInternTableDuplicates(const Container & old_spaces,ImageSpace * new_space,SafeMap<mirror::String *,mirror::String * > * intern_remap)770   static void RemoveInternTableDuplicates(
771       const Container& old_spaces,
772       /*inout*/ImageSpace* new_space,
773       /*inout*/SafeMap<mirror::String*, mirror::String*>* intern_remap)
774       REQUIRES_SHARED(Locks::mutator_lock_) {
775     const ImageSection& new_interns = new_space->GetImageHeader().GetInternedStringsSection();
776     if (new_interns.Size() != 0u) {
777       const uint8_t* new_data = new_space->Begin() + new_interns.Offset();
778       size_t new_read_count;
779       InternTable::UnorderedSet new_set(new_data, /*make_copy_of_data=*/ false, &new_read_count);
780       for (const auto& old_space : old_spaces) {
781         const ImageSection& old_interns = old_space->GetImageHeader().GetInternedStringsSection();
782         if (old_interns.Size() != 0u) {
783           const uint8_t* old_data = old_space->Begin() + old_interns.Offset();
784           size_t old_read_count;
785           InternTable::UnorderedSet old_set(
786               old_data, /*make_copy_of_data=*/ false, &old_read_count);
787           RemoveDuplicates(old_set, &new_set, intern_remap);
788         }
789       }
790     }
791   }
792 
RemapInternedStringDuplicates(const SafeMap<mirror::String *,mirror::String * > & intern_remap,ImageSpace * new_space)793   static void RemapInternedStringDuplicates(
794       const SafeMap<mirror::String*, mirror::String*>& intern_remap,
795       ImageSpace* new_space) REQUIRES_SHARED(Locks::mutator_lock_) {
796     RemapInternedStringsVisitor visitor(intern_remap);
797     static_assert(IsAligned<kObjectAlignment>(sizeof(ImageHeader)), "Header alignment check");
798     uint32_t objects_end = new_space->GetImageHeader().GetObjectsSection().Size();
799     DCHECK_ALIGNED(objects_end, kObjectAlignment);
800     for (uint32_t pos = sizeof(ImageHeader); pos != objects_end; ) {
801       mirror::Object* object = reinterpret_cast<mirror::Object*>(new_space->Begin() + pos);
802       object->VisitReferences</*kVisitNativeRoots=*/ false,
803                               kVerifyNone,
804                               kWithoutReadBarrier>(visitor, visitor);
805       pos += RoundUp(object->SizeOf<kVerifyNone>(), kObjectAlignment);
806     }
807   }
808 
809  private:
810   // Remove duplicates found in the `old_set` from the `new_set`.
811   // Record the removed Strings for remapping. No read barriers are needed as the
812   // tables are either just being loaded and not yet a part of the heap, or boot
813   // image intern tables with non-moveable Strings used when loading an app image.
RemoveDuplicates(const InternTable::UnorderedSet & old_set,InternTable::UnorderedSet * new_set,SafeMap<mirror::String *,mirror::String * > * intern_remap)814   static void RemoveDuplicates(const InternTable::UnorderedSet& old_set,
815                                /*inout*/InternTable::UnorderedSet* new_set,
816                                /*inout*/SafeMap<mirror::String*, mirror::String*>* intern_remap)
817       REQUIRES_SHARED(Locks::mutator_lock_) {
818     if (old_set.size() < new_set->size()) {
819       for (const GcRoot<mirror::String>& old_s : old_set) {
820         auto new_it = new_set->find(old_s);
821         if (UNLIKELY(new_it != new_set->end())) {
822           intern_remap->Put(new_it->Read<kWithoutReadBarrier>(), old_s.Read<kWithoutReadBarrier>());
823           new_set->erase(new_it);
824         }
825       }
826     } else {
827       for (auto new_it = new_set->begin(), end = new_set->end(); new_it != end; ) {
828         auto old_it = old_set.find(*new_it);
829         if (UNLIKELY(old_it != old_set.end())) {
830           intern_remap->Put(new_it->Read<kWithoutReadBarrier>(),
831                             old_it->Read<kWithoutReadBarrier>());
832           new_it = new_set->erase(new_it);
833         } else {
834           ++new_it;
835         }
836       }
837     }
838   }
839 
ValidateBootImageChecksum(const char * image_filename,const ImageHeader & image_header,const OatFile * oat_file,ArrayRef<ImageSpace * const> boot_image_spaces,size_t * boot_image_space_dependencies,std::string * error_msg)840   static bool ValidateBootImageChecksum(const char* image_filename,
841                                         const ImageHeader& image_header,
842                                         const OatFile* oat_file,
843                                         ArrayRef<ImageSpace* const> boot_image_spaces,
844                                         /*out*/size_t* boot_image_space_dependencies,
845                                         /*out*/std::string* error_msg) {
846     // Use the boot image component count to calculate the checksum from
847     // the appropriate number of boot image chunks.
848     uint32_t boot_image_component_count = image_header.GetBootImageComponentCount();
849     size_t expected_image_component_count = ImageSpace::GetNumberOfComponents(boot_image_spaces);
850     if (boot_image_component_count > expected_image_component_count) {
851       *error_msg = StringPrintf("Too many boot image dependencies (%u > %zu) in image %s",
852                                 boot_image_component_count,
853                                 expected_image_component_count,
854                                 image_filename);
855       return false;
856     }
857     uint32_t checksum = 0u;
858     size_t chunk_count = 0u;
859     size_t space_pos = 0u;
860     uint64_t boot_image_size = 0u;
861     for (size_t component_count = 0u; component_count != boot_image_component_count; ) {
862       const ImageHeader& current_header = boot_image_spaces[space_pos]->GetImageHeader();
863       if (current_header.GetComponentCount() > boot_image_component_count - component_count) {
864         *error_msg = StringPrintf("Boot image component count in %s ends in the middle of a chunk, "
865                                       "%u is between %zu and %zu",
866                                   image_filename,
867                                   boot_image_component_count,
868                                   component_count,
869                                   component_count + current_header.GetComponentCount());
870         return false;
871       }
872       component_count += current_header.GetComponentCount();
873       checksum ^= current_header.GetImageChecksum();
874       chunk_count += 1u;
875       space_pos += current_header.GetImageSpaceCount();
876       boot_image_size += current_header.GetImageReservationSize();
877     }
878     if (image_header.GetBootImageChecksum() != checksum) {
879       *error_msg = StringPrintf("Boot image checksum mismatch (0x%08x != 0x%08x) in image %s",
880                                 image_header.GetBootImageChecksum(),
881                                 checksum,
882                                 image_filename);
883       return false;
884     }
885     if (image_header.GetBootImageSize() != boot_image_size) {
886       *error_msg = StringPrintf("Boot image size mismatch (0x%08x != 0x%08" PRIx64 ") in image %s",
887                                 image_header.GetBootImageSize(),
888                                 boot_image_size,
889                                 image_filename);
890       return false;
891     }
892     // Oat checksums, if present, have already been validated, so we know that
893     // they match the loaded image spaces. Therefore, we just verify that they
894     // are consistent in the number of boot image chunks they list by looking
895     // for the kImageChecksumPrefix at the start of each component.
896     const char* oat_boot_class_path_checksums =
897         oat_file->GetOatHeader().GetStoreValueByKey(OatHeader::kBootClassPathChecksumsKey);
898     if (oat_boot_class_path_checksums != nullptr) {
899       size_t oat_bcp_chunk_count = 0u;
900       while (*oat_boot_class_path_checksums == kImageChecksumPrefix) {
901         oat_bcp_chunk_count += 1u;
902         // Find the start of the next component if any.
903         const char* separator = strchr(oat_boot_class_path_checksums, ':');
904         oat_boot_class_path_checksums = (separator != nullptr) ? separator + 1u : "";
905       }
906       if (oat_bcp_chunk_count != chunk_count) {
907         *error_msg = StringPrintf("Boot image chunk count mismatch (%zu != %zu) in image %s",
908                                   oat_bcp_chunk_count,
909                                   chunk_count,
910                                   image_filename);
911         return false;
912       }
913     }
914     *boot_image_space_dependencies = space_pos;
915     return true;
916   }
917 
LoadImageFile(const char * image_filename,const char * image_location,const ImageHeader & image_header,int fd,bool allow_direct_mapping,TimingLogger * logger,MemMap * image_reservation,std::string * error_msg)918   static MemMap LoadImageFile(const char* image_filename,
919                               const char* image_location,
920                               const ImageHeader& image_header,
921                               int fd,
922                               bool allow_direct_mapping,
923                               TimingLogger* logger,
924                               /*inout*/MemMap* image_reservation,
925                               /*out*/std::string* error_msg)
926         REQUIRES_SHARED(Locks::mutator_lock_) {
927     TimingLogger::ScopedTiming timing("MapImageFile", logger);
928     std::string temp_error_msg;
929     const bool is_compressed = image_header.HasCompressedBlock();
930     if (!is_compressed && allow_direct_mapping) {
931       uint8_t* address = (image_reservation != nullptr) ? image_reservation->Begin() : nullptr;
932       return MemMap::MapFileAtAddress(address,
933                                       image_header.GetImageSize(),
934                                       PROT_READ | PROT_WRITE,
935                                       MAP_PRIVATE,
936                                       fd,
937                                       /*start=*/ 0,
938                                       /*low_4gb=*/ true,
939                                       image_filename,
940                                       /*reuse=*/ false,
941                                       image_reservation,
942                                       error_msg);
943     }
944 
945     // Reserve output and copy/decompress into it.
946     MemMap map = MemMap::MapAnonymous(image_location,
947                                       image_header.GetImageSize(),
948                                       PROT_READ | PROT_WRITE,
949                                       /*low_4gb=*/ true,
950                                       image_reservation,
951                                       error_msg);
952     if (map.IsValid()) {
953       const size_t stored_size = image_header.GetDataSize();
954       MemMap temp_map = MemMap::MapFile(sizeof(ImageHeader) + stored_size,
955                                         PROT_READ,
956                                         MAP_PRIVATE,
957                                         fd,
958                                         /*start=*/ 0,
959                                         /*low_4gb=*/ false,
960                                         image_filename,
961                                         error_msg);
962       if (!temp_map.IsValid()) {
963         DCHECK(error_msg == nullptr || !error_msg->empty());
964         return MemMap::Invalid();
965       }
966 
967       Runtime* runtime = Runtime::Current();
968       // The runtime might not be available at this point if we're running
969       // dex2oat or oatdump.
970       if (runtime != nullptr) {
971         size_t madvise_size_limit = runtime->GetMadviseWillNeedSizeArt();
972         Runtime::MadviseFileForRange(madvise_size_limit,
973                                      temp_map.Size(),
974                                      temp_map.Begin(),
975                                      temp_map.End(),
976                                      image_filename);
977       }
978 
979       if (is_compressed) {
980         memcpy(map.Begin(), &image_header, sizeof(ImageHeader));
981 
982         Runtime::ScopedThreadPoolUsage stpu;
983         ThreadPool* const pool = stpu.GetThreadPool();
984         const uint64_t start = NanoTime();
985         Thread* const self = Thread::Current();
986         static constexpr size_t kMinBlocks = 2u;
987         const bool use_parallel = pool != nullptr && image_header.GetBlockCount() >= kMinBlocks;
988         for (const ImageHeader::Block& block : image_header.GetBlocks(temp_map.Begin())) {
989           auto function = [&](Thread*) {
990             const uint64_t start2 = NanoTime();
991             ScopedTrace trace("LZ4 decompress block");
992             bool result = block.Decompress(/*out_ptr=*/map.Begin(),
993                                            /*in_ptr=*/temp_map.Begin(),
994                                            error_msg);
995             if (!result && error_msg != nullptr) {
996               *error_msg = "Failed to decompress image block " + *error_msg;
997             }
998             VLOG(image) << "Decompress block " << block.GetDataSize() << " -> "
999                         << block.GetImageSize() << " in " << PrettyDuration(NanoTime() - start2);
1000           };
1001           if (use_parallel) {
1002             pool->AddTask(self, new FunctionTask(std::move(function)));
1003           } else {
1004             function(self);
1005           }
1006         }
1007         if (use_parallel) {
1008           ScopedTrace trace("Waiting for workers");
1009           // Go to native since we don't want to suspend while holding the mutator lock.
1010           ScopedThreadSuspension sts(Thread::Current(), kNative);
1011           pool->Wait(self, true, false);
1012         }
1013         const uint64_t time = NanoTime() - start;
1014         // Add one 1 ns to prevent possible divide by 0.
1015         VLOG(image) << "Decompressing image took " << PrettyDuration(time) << " ("
1016                     << PrettySize(static_cast<uint64_t>(map.Size()) * MsToNs(1000) / (time + 1))
1017                     << "/s)";
1018       } else {
1019         DCHECK(!allow_direct_mapping);
1020         // We do not allow direct mapping for boot image extensions compiled to a memfd.
1021         // This prevents wasting memory by kernel keeping the contents of the file alive
1022         // despite these contents being unreachable once the file descriptor is closed
1023         // and mmapped memory is copied for all existing mappings.
1024         //
1025         // Most pages would be copied during relocation while there is only one mapping.
1026         // We could use MAP_SHARED for relocation and then msync() and remap MAP_PRIVATE
1027         // as required for forking from zygote, but there would still be some pages
1028         // wasted anyway and we want to avoid that. (For example, static synchronized
1029         // methods use the class object for locking and thus modify its lockword.)
1030 
1031         // No other process should race to overwrite the extension in memfd.
1032         DCHECK_EQ(memcmp(temp_map.Begin(), &image_header, sizeof(ImageHeader)), 0);
1033         memcpy(map.Begin(), temp_map.Begin(), temp_map.Size());
1034       }
1035     }
1036 
1037     return map;
1038   }
1039 
1040   class EmptyRange {
1041    public:
InSource(uintptr_t) const1042     ALWAYS_INLINE bool InSource(uintptr_t) const { return false; }
InDest(uintptr_t) const1043     ALWAYS_INLINE bool InDest(uintptr_t) const { return false; }
ToDest(uintptr_t) const1044     ALWAYS_INLINE uintptr_t ToDest(uintptr_t) const { UNREACHABLE(); }
1045   };
1046 
1047   template <typename Range0, typename Range1 = EmptyRange, typename Range2 = EmptyRange>
1048   class ForwardAddress {
1049    public:
ForwardAddress(const Range0 & range0=Range0 (),const Range1 & range1=Range1 (),const Range2 & range2=Range2 ())1050     explicit ForwardAddress(const Range0& range0 = Range0(),
1051                             const Range1& range1 = Range1(),
1052                             const Range2& range2 = Range2())
1053         : range0_(range0), range1_(range1), range2_(range2) {}
1054 
1055     // Return the relocated address of a heap object.
1056     // Null checks must be performed in the caller (for performance reasons).
1057     template <typename T>
operator ()(T * src) const1058     ALWAYS_INLINE T* operator()(T* src) const {
1059       DCHECK(src != nullptr);
1060       const uintptr_t uint_src = reinterpret_cast<uintptr_t>(src);
1061       if (range2_.InSource(uint_src)) {
1062         return reinterpret_cast<T*>(range2_.ToDest(uint_src));
1063       }
1064       if (range1_.InSource(uint_src)) {
1065         return reinterpret_cast<T*>(range1_.ToDest(uint_src));
1066       }
1067       CHECK(range0_.InSource(uint_src))
1068           << reinterpret_cast<const void*>(src) << " not in "
1069           << reinterpret_cast<const void*>(range0_.Source()) << "-"
1070           << reinterpret_cast<const void*>(range0_.Source() + range0_.Length());
1071       return reinterpret_cast<T*>(range0_.ToDest(uint_src));
1072     }
1073 
1074    private:
1075     const Range0 range0_;
1076     const Range1 range1_;
1077     const Range2 range2_;
1078   };
1079 
1080   template <typename Forward>
1081   class FixupRootVisitor {
1082    public:
1083     template<typename... Args>
FixupRootVisitor(Args...args)1084     explicit FixupRootVisitor(Args... args) : forward_(args...) {}
1085 
VisitRootIfNonNull(mirror::CompressedReference<mirror::Object> * root) const1086     ALWAYS_INLINE void VisitRootIfNonNull(mirror::CompressedReference<mirror::Object>* root) const
1087         REQUIRES_SHARED(Locks::mutator_lock_) {
1088       if (!root->IsNull()) {
1089         VisitRoot(root);
1090       }
1091     }
1092 
VisitRoot(mirror::CompressedReference<mirror::Object> * root) const1093     ALWAYS_INLINE void VisitRoot(mirror::CompressedReference<mirror::Object>* root) const
1094         REQUIRES_SHARED(Locks::mutator_lock_) {
1095       mirror::Object* ref = root->AsMirrorPtr();
1096       mirror::Object* new_ref = forward_(ref);
1097       if (ref != new_ref) {
1098         root->Assign(new_ref);
1099       }
1100     }
1101 
1102    private:
1103     Forward forward_;
1104   };
1105 
1106   template <typename Forward>
1107   class FixupObjectVisitor {
1108    public:
FixupObjectVisitor(gc::accounting::ContinuousSpaceBitmap * visited,const Forward & forward)1109     explicit FixupObjectVisitor(gc::accounting::ContinuousSpaceBitmap* visited,
1110                                 const Forward& forward)
1111         : visited_(visited), forward_(forward) {}
1112 
1113     // Fix up separately since we also need to fix up method entrypoints.
VisitRootIfNonNull(mirror::CompressedReference<mirror::Object> * root ATTRIBUTE_UNUSED) const1114     ALWAYS_INLINE void VisitRootIfNonNull(
1115         mirror::CompressedReference<mirror::Object>* root ATTRIBUTE_UNUSED) const {}
1116 
VisitRoot(mirror::CompressedReference<mirror::Object> * root ATTRIBUTE_UNUSED) const1117     ALWAYS_INLINE void VisitRoot(mirror::CompressedReference<mirror::Object>* root ATTRIBUTE_UNUSED)
1118         const {}
1119 
operator ()(ObjPtr<mirror::Object> obj,MemberOffset offset,bool is_static ATTRIBUTE_UNUSED) const1120     ALWAYS_INLINE void operator()(ObjPtr<mirror::Object> obj,
1121                                   MemberOffset offset,
1122                                   bool is_static ATTRIBUTE_UNUSED) const
1123         NO_THREAD_SAFETY_ANALYSIS {
1124       // Space is not yet added to the heap, don't do a read barrier.
1125       mirror::Object* ref = obj->GetFieldObject<mirror::Object, kVerifyNone, kWithoutReadBarrier>(
1126           offset);
1127       if (ref != nullptr) {
1128         // Use SetFieldObjectWithoutWriteBarrier to avoid card marking since we are writing to the
1129         // image.
1130         obj->SetFieldObjectWithoutWriteBarrier<false, true, kVerifyNone>(offset, forward_(ref));
1131       }
1132     }
1133 
1134     // java.lang.ref.Reference visitor.
operator ()(ObjPtr<mirror::Class> klass,ObjPtr<mirror::Reference> ref) const1135     ALWAYS_INLINE void operator()(ObjPtr<mirror::Class> klass, ObjPtr<mirror::Reference> ref) const
1136         REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(Locks::heap_bitmap_lock_) {
1137       DCHECK(klass->IsTypeOfReferenceClass());
1138       this->operator()(ref, mirror::Reference::ReferentOffset(), /*is_static=*/ false);
1139     }
1140 
operator ()(mirror::Object * obj) const1141     void operator()(mirror::Object* obj) const
1142         NO_THREAD_SAFETY_ANALYSIS {
1143       if (!visited_->Set(obj)) {
1144         // Not already visited.
1145         obj->VisitReferences</*visit native roots*/false, kVerifyNone, kWithoutReadBarrier>(
1146             *this,
1147             *this);
1148         CHECK(!obj->IsClass());
1149       }
1150     }
1151 
1152    private:
1153     gc::accounting::ContinuousSpaceBitmap* const visited_;
1154     Forward forward_;
1155   };
1156 
1157   // Relocate an image space mapped at target_base which possibly used to be at a different base
1158   // address. In place means modifying a single ImageSpace in place rather than relocating from
1159   // one ImageSpace to another.
1160   template <PointerSize kPointerSize>
RelocateInPlace(uint32_t boot_image_begin,uint8_t * target_base,accounting::ContinuousSpaceBitmap * bitmap,const OatFile * app_oat_file,std::string * error_msg)1161   static bool RelocateInPlace(uint32_t boot_image_begin,
1162                               uint8_t* target_base,
1163                               accounting::ContinuousSpaceBitmap* bitmap,
1164                               const OatFile* app_oat_file,
1165                               std::string* error_msg) {
1166     DCHECK(error_msg != nullptr);
1167     // Set up sections.
1168     ImageHeader* image_header = reinterpret_cast<ImageHeader*>(target_base);
1169     const uint32_t boot_image_size = image_header->GetBootImageSize();
1170     const ImageSection& objects_section = image_header->GetObjectsSection();
1171     // Where the app image objects are mapped to.
1172     uint8_t* objects_location = target_base + objects_section.Offset();
1173     TimingLogger logger(__FUNCTION__, true, false);
1174     RelocationRange boot_image(image_header->GetBootImageBegin(),
1175                                boot_image_begin,
1176                                boot_image_size);
1177     // Metadata is everything after the objects section, use exclusion to be safe.
1178     RelocationRange app_image_metadata(
1179         reinterpret_cast<uintptr_t>(image_header->GetImageBegin()) + objects_section.End(),
1180         reinterpret_cast<uintptr_t>(target_base) + objects_section.End(),
1181         image_header->GetImageSize() - objects_section.End());
1182     // App image heap objects, may be mapped in the heap.
1183     RelocationRange app_image_objects(
1184         reinterpret_cast<uintptr_t>(image_header->GetImageBegin()) + objects_section.Offset(),
1185         reinterpret_cast<uintptr_t>(objects_location),
1186         objects_section.Size());
1187     // Use the oat data section since this is where the OatFile::Begin is.
1188     RelocationRange app_oat(reinterpret_cast<uintptr_t>(image_header->GetOatDataBegin()),
1189                             // Not necessarily in low 4GB.
1190                             reinterpret_cast<uintptr_t>(app_oat_file->Begin()),
1191                             image_header->GetOatDataEnd() - image_header->GetOatDataBegin());
1192     VLOG(image) << "App image metadata " << app_image_metadata;
1193     VLOG(image) << "App image objects " << app_image_objects;
1194     VLOG(image) << "App oat " << app_oat;
1195     VLOG(image) << "Boot image " << boot_image;
1196     // True if we need to fixup any heap pointers.
1197     const bool fixup_image = boot_image.Delta() != 0 || app_image_metadata.Delta() != 0 ||
1198         app_image_objects.Delta() != 0;
1199     if (!fixup_image) {
1200       // Nothing to fix up.
1201       return true;
1202     }
1203     ScopedDebugDisallowReadBarriers sddrb(Thread::Current());
1204 
1205     using ForwardObject = ForwardAddress<RelocationRange, RelocationRange>;
1206     ForwardObject forward_object(boot_image, app_image_objects);
1207     ForwardObject forward_metadata(boot_image, app_image_metadata);
1208     using ForwardCode = ForwardAddress<RelocationRange, RelocationRange>;
1209     ForwardCode forward_code(boot_image, app_oat);
1210     PatchObjectVisitor<kPointerSize, ForwardObject, ForwardCode> patch_object_visitor(
1211         forward_object,
1212         forward_metadata);
1213     if (fixup_image) {
1214       // Two pass approach, fix up all classes first, then fix up non class-objects.
1215       // The visited bitmap is used to ensure that pointer arrays are not forwarded twice.
1216       gc::accounting::ContinuousSpaceBitmap visited_bitmap(
1217           gc::accounting::ContinuousSpaceBitmap::Create("Relocate bitmap",
1218                                                         target_base,
1219                                                         image_header->GetImageSize()));
1220       {
1221         TimingLogger::ScopedTiming timing("Fixup classes", &logger);
1222         ObjPtr<mirror::Class> class_class = [&]() NO_THREAD_SAFETY_ANALYSIS {
1223           ObjPtr<mirror::ObjectArray<mirror::Object>> image_roots = app_image_objects.ToDest(
1224               image_header->GetImageRoots<kWithoutReadBarrier>().Ptr());
1225           int32_t class_roots_index = enum_cast<int32_t>(ImageHeader::kClassRoots);
1226           DCHECK_LT(class_roots_index, image_roots->GetLength<kVerifyNone>());
1227           ObjPtr<mirror::ObjectArray<mirror::Class>> class_roots =
1228               ObjPtr<mirror::ObjectArray<mirror::Class>>::DownCast(boot_image.ToDest(
1229                   image_roots->GetWithoutChecks<kVerifyNone>(class_roots_index).Ptr()));
1230           return GetClassRoot<mirror::Class, kWithoutReadBarrier>(class_roots);
1231         }();
1232         const auto& class_table_section = image_header->GetClassTableSection();
1233         if (class_table_section.Size() > 0u) {
1234           ScopedObjectAccess soa(Thread::Current());
1235           ClassTableVisitor class_table_visitor(forward_object);
1236           size_t read_count = 0u;
1237           const uint8_t* data = target_base + class_table_section.Offset();
1238           // We avoid making a copy of the data since we want modifications to be propagated to the
1239           // memory map.
1240           ClassTable::ClassSet temp_set(data, /*make_copy_of_data=*/ false, &read_count);
1241           for (ClassTable::TableSlot& slot : temp_set) {
1242             slot.VisitRoot(class_table_visitor);
1243             ObjPtr<mirror::Class> klass = slot.Read<kWithoutReadBarrier>();
1244             if (!app_image_objects.InDest(klass.Ptr())) {
1245               continue;
1246             }
1247             const bool already_marked = visited_bitmap.Set(klass.Ptr());
1248             CHECK(!already_marked) << "App image class already visited";
1249             patch_object_visitor.VisitClass(klass, class_class);
1250             // Then patch the non-embedded vtable and iftable.
1251             ObjPtr<mirror::PointerArray> vtable =
1252                 klass->GetVTable<kVerifyNone, kWithoutReadBarrier>();
1253             if (vtable != nullptr &&
1254                 app_image_objects.InDest(vtable.Ptr()) &&
1255                 !visited_bitmap.Set(vtable.Ptr())) {
1256               patch_object_visitor.VisitPointerArray(vtable);
1257             }
1258             ObjPtr<mirror::IfTable> iftable = klass->GetIfTable<kVerifyNone, kWithoutReadBarrier>();
1259             if (iftable != nullptr && app_image_objects.InDest(iftable.Ptr())) {
1260               // Avoid processing the fields of iftable since we will process them later anyways
1261               // below.
1262               int32_t ifcount = klass->GetIfTableCount<kVerifyNone>();
1263               for (int32_t i = 0; i != ifcount; ++i) {
1264                 ObjPtr<mirror::PointerArray> unpatched_ifarray =
1265                     iftable->GetMethodArrayOrNull<kVerifyNone, kWithoutReadBarrier>(i);
1266                 if (unpatched_ifarray != nullptr) {
1267                   // The iftable has not been patched, so we need to explicitly adjust the pointer.
1268                   ObjPtr<mirror::PointerArray> ifarray = forward_object(unpatched_ifarray.Ptr());
1269                   if (app_image_objects.InDest(ifarray.Ptr()) &&
1270                       !visited_bitmap.Set(ifarray.Ptr())) {
1271                     patch_object_visitor.VisitPointerArray(ifarray);
1272                   }
1273                 }
1274               }
1275             }
1276           }
1277         }
1278       }
1279 
1280       // Fixup objects may read fields in the boot image so we hold the mutator lock (although it is
1281       // probably not required).
1282       TimingLogger::ScopedTiming timing("Fixup objects", &logger);
1283       ScopedObjectAccess soa(Thread::Current());
1284       // Need to update the image to be at the target base.
1285       uintptr_t objects_begin = reinterpret_cast<uintptr_t>(target_base + objects_section.Offset());
1286       uintptr_t objects_end = reinterpret_cast<uintptr_t>(target_base + objects_section.End());
1287       FixupObjectVisitor<ForwardObject> fixup_object_visitor(&visited_bitmap, forward_object);
1288       bitmap->VisitMarkedRange(objects_begin, objects_end, fixup_object_visitor);
1289       // Fixup image roots.
1290       CHECK(app_image_objects.InSource(reinterpret_cast<uintptr_t>(
1291           image_header->GetImageRoots<kWithoutReadBarrier>().Ptr())));
1292       image_header->RelocateImageReferences(app_image_objects.Delta());
1293       image_header->RelocateBootImageReferences(boot_image.Delta());
1294       CHECK_EQ(image_header->GetImageBegin(), target_base);
1295     }
1296     {
1297       // Only touches objects in the app image, no need for mutator lock.
1298       TimingLogger::ScopedTiming timing("Fixup methods", &logger);
1299       image_header->VisitPackedArtMethods([&](ArtMethod& method) NO_THREAD_SAFETY_ANALYSIS {
1300         // TODO: Consider a separate visitor for runtime vs normal methods.
1301         if (UNLIKELY(method.IsRuntimeMethod())) {
1302           ImtConflictTable* table = method.GetImtConflictTable(kPointerSize);
1303           if (table != nullptr) {
1304             ImtConflictTable* new_table = forward_metadata(table);
1305             if (table != new_table) {
1306               method.SetImtConflictTable(new_table, kPointerSize);
1307             }
1308           }
1309           const void* old_code = method.GetEntryPointFromQuickCompiledCodePtrSize(kPointerSize);
1310           const void* new_code = forward_code(old_code);
1311           if (old_code != new_code) {
1312             method.SetEntryPointFromQuickCompiledCodePtrSize(new_code, kPointerSize);
1313           }
1314         } else {
1315           patch_object_visitor.PatchGcRoot(&method.DeclaringClassRoot());
1316           method.UpdateEntrypoints(forward_code, kPointerSize);
1317         }
1318       }, target_base, kPointerSize);
1319     }
1320     if (fixup_image) {
1321       {
1322         // Only touches objects in the app image, no need for mutator lock.
1323         TimingLogger::ScopedTiming timing("Fixup fields", &logger);
1324         image_header->VisitPackedArtFields([&](ArtField& field) NO_THREAD_SAFETY_ANALYSIS {
1325           patch_object_visitor.template PatchGcRoot</*kMayBeNull=*/ false>(
1326               &field.DeclaringClassRoot());
1327         }, target_base);
1328       }
1329       {
1330         TimingLogger::ScopedTiming timing("Fixup imt", &logger);
1331         image_header->VisitPackedImTables(forward_metadata, target_base, kPointerSize);
1332       }
1333       {
1334         TimingLogger::ScopedTiming timing("Fixup conflict tables", &logger);
1335         image_header->VisitPackedImtConflictTables(forward_metadata, target_base, kPointerSize);
1336       }
1337       // Fix up the intern table.
1338       const auto& intern_table_section = image_header->GetInternedStringsSection();
1339       if (intern_table_section.Size() > 0u) {
1340         TimingLogger::ScopedTiming timing("Fixup intern table", &logger);
1341         ScopedObjectAccess soa(Thread::Current());
1342         // Fixup the pointers in the newly written intern table to contain image addresses.
1343         InternTable temp_intern_table;
1344         // Note that we require that ReadFromMemory does not make an internal copy of the elements
1345         // so that the VisitRoots() will update the memory directly rather than the copies.
1346         temp_intern_table.AddTableFromMemory(target_base + intern_table_section.Offset(),
1347                                              [&](InternTable::UnorderedSet& strings)
1348             REQUIRES_SHARED(Locks::mutator_lock_) {
1349           for (GcRoot<mirror::String>& root : strings) {
1350             root = GcRoot<mirror::String>(forward_object(root.Read<kWithoutReadBarrier>()));
1351           }
1352         }, /*is_boot_image=*/ false);
1353       }
1354     }
1355     if (VLOG_IS_ON(image)) {
1356       logger.Dump(LOG_STREAM(INFO));
1357     }
1358     return true;
1359   }
1360 };
1361 
AppendImageChecksum(uint32_t component_count,uint32_t checksum,std::string * checksums)1362 static void AppendImageChecksum(uint32_t component_count,
1363                                 uint32_t checksum,
1364                                 /*inout*/std::string* checksums) {
1365   static_assert(ImageSpace::kImageChecksumPrefix == 'i', "Format prefix check.");
1366   StringAppendF(checksums, "i;%u/%08x", component_count, checksum);
1367 }
1368 
CheckAndRemoveImageChecksum(uint32_t component_count,uint32_t checksum,std::string_view * oat_checksums,std::string * error_msg)1369 static bool CheckAndRemoveImageChecksum(uint32_t component_count,
1370                                         uint32_t checksum,
1371                                         /*inout*/std::string_view* oat_checksums,
1372                                         /*out*/std::string* error_msg) {
1373   std::string image_checksum;
1374   AppendImageChecksum(component_count, checksum, &image_checksum);
1375   if (!StartsWith(*oat_checksums, image_checksum)) {
1376     *error_msg = StringPrintf("Image checksum mismatch, expected %s to start with %s",
1377                               std::string(*oat_checksums).c_str(),
1378                               image_checksum.c_str());
1379     return false;
1380   }
1381   oat_checksums->remove_prefix(image_checksum.size());
1382   return true;
1383 }
1384 
1385 // Helper class to find the primary boot image and boot image extensions
1386 // and determine the boot image layout.
1387 class ImageSpace::BootImageLayout {
1388  public:
1389   // Description of a "chunk" of the boot image, i.e. either primary boot image
1390   // or a boot image extension, used in conjunction with the boot class path to
1391   // load boot image components.
1392   struct ImageChunk {
1393     std::string base_location;
1394     std::string base_filename;
1395     std::string profile_file;
1396     size_t start_index;
1397     uint32_t component_count;
1398     uint32_t image_space_count;
1399     uint32_t reservation_size;
1400     uint32_t checksum;
1401     uint32_t boot_image_component_count;
1402     uint32_t boot_image_checksum;
1403     uint32_t boot_image_size;
1404 
1405     // The following file descriptors hold the memfd files for extensions compiled
1406     // in memory and described by the above fields. We want to use them to mmap()
1407     // the contents and then close them while treating the ImageChunk description
1408     // as immutable (const), so make these fields explicitly mutable.
1409     mutable android::base::unique_fd art_fd;
1410     mutable android::base::unique_fd vdex_fd;
1411     mutable android::base::unique_fd oat_fd;
1412   };
1413 
BootImageLayout(const std::string & image_location,ArrayRef<const std::string> boot_class_path,ArrayRef<const std::string> boot_class_path_locations)1414   BootImageLayout(const std::string& image_location,
1415                   ArrayRef<const std::string> boot_class_path,
1416                   ArrayRef<const std::string> boot_class_path_locations)
1417      : image_location_(image_location),
1418        boot_class_path_(boot_class_path),
1419        boot_class_path_locations_(boot_class_path_locations) {}
1420 
1421   std::string GetPrimaryImageLocation();
1422 
LoadFromSystem(InstructionSet image_isa,std::string * error_msg)1423   bool LoadFromSystem(InstructionSet image_isa, /*out*/std::string* error_msg) {
1424     return LoadOrValidateFromSystem(image_isa, /*oat_checksums=*/ nullptr, error_msg);
1425   }
1426 
ValidateFromSystem(InstructionSet image_isa,std::string_view * oat_checksums,std::string * error_msg)1427   bool ValidateFromSystem(InstructionSet image_isa,
1428                           /*inout*/std::string_view* oat_checksums,
1429                           /*out*/std::string* error_msg) {
1430     DCHECK(oat_checksums != nullptr);
1431     return LoadOrValidateFromSystem(image_isa, oat_checksums, error_msg);
1432   }
1433 
GetChunks() const1434   ArrayRef<const ImageChunk> GetChunks() const {
1435     return ArrayRef<const ImageChunk>(chunks_);
1436   }
1437 
GetBaseAddress() const1438   uint32_t GetBaseAddress() const {
1439     return base_address_;
1440   }
1441 
GetNextBcpIndex() const1442   size_t GetNextBcpIndex() const {
1443     return next_bcp_index_;
1444   }
1445 
GetTotalComponentCount() const1446   size_t GetTotalComponentCount() const {
1447     return total_component_count_;
1448   }
1449 
GetTotalReservationSize() const1450   size_t GetTotalReservationSize() const {
1451     return total_reservation_size_;
1452   }
1453 
1454  private:
1455   struct NamedComponentLocation {
1456     std::string base_location;
1457     size_t bcp_index;
1458     std::string profile_filename;
1459   };
1460 
ExpandLocationImpl(const std::string & location,size_t bcp_index,bool boot_image_extension)1461   std::string ExpandLocationImpl(const std::string& location,
1462                                  size_t bcp_index,
1463                                  bool boot_image_extension) {
1464     std::vector<std::string> expanded = ExpandMultiImageLocations(
1465         ArrayRef<const std::string>(boot_class_path_).SubArray(bcp_index, 1u),
1466         location,
1467         boot_image_extension);
1468     DCHECK_EQ(expanded.size(), 1u);
1469     return expanded[0];
1470   }
1471 
ExpandLocation(const std::string & location,size_t bcp_index)1472   std::string ExpandLocation(const std::string& location, size_t bcp_index) {
1473     if (bcp_index == 0u) {
1474       DCHECK_EQ(location, ExpandLocationImpl(location, bcp_index, /*boot_image_extension=*/ false));
1475       return location;
1476     } else {
1477       return ExpandLocationImpl(location, bcp_index, /*boot_image_extension=*/ true);
1478     }
1479   }
1480 
GetBcpComponentPath(size_t bcp_index)1481   std::string GetBcpComponentPath(size_t bcp_index) {
1482     DCHECK_LE(bcp_index, boot_class_path_.size());
1483     size_t bcp_slash_pos = boot_class_path_[bcp_index].rfind('/');
1484     DCHECK_NE(bcp_slash_pos, std::string::npos);
1485     return boot_class_path_[bcp_index].substr(0u, bcp_slash_pos + 1u);
1486   }
1487 
1488   bool VerifyImageLocation(const std::vector<std::string>& components,
1489                            /*out*/size_t* named_components_count,
1490                            /*out*/std::string* error_msg);
1491 
1492   bool MatchNamedComponents(
1493       ArrayRef<const std::string> named_components,
1494       /*out*/std::vector<NamedComponentLocation>* named_component_locations,
1495       /*out*/std::string* error_msg);
1496 
1497   bool ValidateBootImageChecksum(const char* file_description,
1498                                  const ImageHeader& header,
1499                                  /*out*/std::string* error_msg);
1500 
1501   bool ValidateHeader(const ImageHeader& header,
1502                       size_t bcp_index,
1503                       const char* file_description,
1504                       /*out*/std::string* error_msg);
1505 
1506   bool ReadHeader(const std::string& base_location,
1507                   const std::string& base_filename,
1508                   size_t bcp_index,
1509                   /*out*/std::string* error_msg);
1510 
1511   bool CompileExtension(const std::string& base_location,
1512                         const std::string& base_filename,
1513                         size_t bcp_index,
1514                         const std::string& profile_filename,
1515                         ArrayRef<std::string> dependencies,
1516                         /*out*/std::string* error_msg);
1517 
1518   bool CheckAndRemoveLastChunkChecksum(/*inout*/std::string_view* oat_checksums,
1519                                        /*out*/std::string* error_msg);
1520 
1521   template <typename FilenameFn>
1522   bool LoadOrValidate(FilenameFn&& filename_fn,
1523                       /*inout*/std::string_view* oat_checksums,
1524                       /*out*/std::string* error_msg);
1525 
1526   bool LoadOrValidateFromSystem(InstructionSet image_isa,
1527                                 /*inout*/std::string_view* oat_checksums,
1528                                 /*out*/std::string* error_msg);
1529 
1530   const std::string& image_location_;
1531   ArrayRef<const std::string> boot_class_path_;
1532   ArrayRef<const std::string> boot_class_path_locations_;
1533 
1534   std::vector<ImageChunk> chunks_;
1535   uint32_t base_address_ = 0u;
1536   size_t next_bcp_index_ = 0u;
1537   size_t total_component_count_ = 0u;
1538   size_t total_reservation_size_ = 0u;
1539 };
1540 
GetPrimaryImageLocation()1541 std::string ImageSpace::BootImageLayout::GetPrimaryImageLocation() {
1542   size_t location_start = 0u;
1543   size_t location_end = image_location_.find(kComponentSeparator);
1544   while (location_end == location_start) {
1545     ++location_start;
1546     location_end = image_location_.find(location_start, kComponentSeparator);
1547   }
1548   std::string location = (location_end == std::string::npos)
1549       ? image_location_.substr(location_start)
1550       : image_location_.substr(location_start, location_end - location_start);
1551   if (location.find('/') == std::string::npos) {
1552     // No path, so use the path from the first boot class path component.
1553     size_t slash_pos = boot_class_path_.empty()
1554         ? std::string::npos
1555         : boot_class_path_[0].rfind('/');
1556     if (slash_pos == std::string::npos) {
1557       return std::string();
1558     }
1559     location.insert(0u, boot_class_path_[0].substr(0u, slash_pos + 1u));
1560   }
1561   return location;
1562 }
1563 
VerifyImageLocation(const std::vector<std::string> & components,size_t * named_components_count,std::string * error_msg)1564 bool ImageSpace::BootImageLayout::VerifyImageLocation(
1565     const std::vector<std::string>& components,
1566     /*out*/size_t* named_components_count,
1567     /*out*/std::string* error_msg) {
1568   DCHECK(named_components_count != nullptr);
1569 
1570   // Validate boot class path. Require a path and non-empty name in each component.
1571   for (const std::string& bcp_component : boot_class_path_) {
1572     size_t bcp_slash_pos = bcp_component.rfind('/');
1573     if (bcp_slash_pos == std::string::npos || bcp_slash_pos == bcp_component.size() - 1u) {
1574       *error_msg = StringPrintf("Invalid boot class path component: %s", bcp_component.c_str());
1575       return false;
1576     }
1577   }
1578 
1579   // Validate the format of image location components.
1580   size_t components_size = components.size();
1581   if (components_size == 0u) {
1582     *error_msg = "Empty image location.";
1583     return false;
1584   }
1585   size_t wildcards_start = components_size;  // No wildcards.
1586   for (size_t i = 0; i != components_size; ++i) {
1587     const std::string& component = components[i];
1588     DCHECK(!component.empty());  // Guaranteed by Split().
1589     const size_t profile_separator_pos = component.find(kProfileSeparator);
1590     size_t wildcard_pos = component.find('*');
1591     if (wildcard_pos == std::string::npos) {
1592       if (wildcards_start != components.size()) {
1593         *error_msg =
1594             StringPrintf("Image component without wildcard after component with wildcard: %s",
1595                          component.c_str());
1596         return false;
1597       }
1598       if (profile_separator_pos != std::string::npos) {
1599         if (component.find(kProfileSeparator, profile_separator_pos + 1u) != std::string::npos) {
1600           *error_msg = StringPrintf("Multiple profile delimiters in %s", component.c_str());
1601           return false;
1602         }
1603         if (profile_separator_pos == 0u || profile_separator_pos + 1u == component.size()) {
1604           *error_msg = StringPrintf("Missing component and/or profile name in %s",
1605                                     component.c_str());
1606           return false;
1607         }
1608         if (component.back() == '/') {
1609           *error_msg = StringPrintf("Profile name ends with path separator: %s",
1610                                     component.c_str());
1611           return false;
1612         }
1613       }
1614       size_t component_name_length =
1615           profile_separator_pos != std::string::npos ? profile_separator_pos : component.size();
1616       if (component[component_name_length - 1u] == '/') {
1617         *error_msg = StringPrintf("Image component ends with path separator: %s",
1618                                   component.c_str());
1619         return false;
1620       }
1621     } else {
1622       if (profile_separator_pos != std::string::npos) {
1623         *error_msg = StringPrintf("Unsupproted wildcard (*) and profile delimiter (!) in %s",
1624                                   component.c_str());
1625         return false;
1626       }
1627       if (wildcards_start == components_size) {
1628         wildcards_start = i;
1629       }
1630       // Wildcard must be the last character.
1631       if (wildcard_pos != component.size() - 1u) {
1632         *error_msg = StringPrintf("Unsupported wildcard (*) position in %s", component.c_str());
1633         return false;
1634       }
1635       // And it must be either plain wildcard or preceded by a path separator.
1636       if (component.size() != 1u && component[wildcard_pos - 1u] != '/') {
1637         *error_msg = StringPrintf("Non-plain wildcard (*) not preceded by path separator '/': %s",
1638                                   component.c_str());
1639         return false;
1640       }
1641       if (i == 0) {
1642         *error_msg = StringPrintf("Primary component contains wildcard (*): %s", component.c_str());
1643         return false;
1644       }
1645     }
1646   }
1647 
1648   *named_components_count = wildcards_start;
1649   return true;
1650 }
1651 
MatchNamedComponents(ArrayRef<const std::string> named_components,std::vector<NamedComponentLocation> * named_component_locations,std::string * error_msg)1652 bool ImageSpace::BootImageLayout::MatchNamedComponents(
1653     ArrayRef<const std::string> named_components,
1654     /*out*/std::vector<NamedComponentLocation>* named_component_locations,
1655     /*out*/std::string* error_msg) {
1656   DCHECK(!named_components.empty());
1657   DCHECK(named_component_locations->empty());
1658   named_component_locations->reserve(named_components.size());
1659   size_t bcp_component_count = boot_class_path_.size();
1660   size_t bcp_pos = 0;
1661   std::string base_name;
1662   for (size_t i = 0, size = named_components.size(); i != size; ++i) {
1663     std::string component = named_components[i];
1664     std::string profile_filename;  // Empty.
1665     const size_t profile_separator_pos = component.find(kProfileSeparator);
1666     if (profile_separator_pos != std::string::npos) {
1667       profile_filename = component.substr(profile_separator_pos + 1u);
1668       DCHECK(!profile_filename.empty());  // Checked by VerifyImageLocation()
1669       component.resize(profile_separator_pos);
1670       DCHECK(!component.empty());  // Checked by VerifyImageLocation()
1671     }
1672     size_t slash_pos = component.rfind('/');
1673     std::string base_location;
1674     if (i == 0u) {
1675       // The primary boot image name is taken as provided. It forms the base
1676       // for expanding the extension filenames.
1677       if (slash_pos != std::string::npos) {
1678         base_name = component.substr(slash_pos + 1u);
1679         base_location = component;
1680       } else {
1681         base_name = component;
1682         base_location = GetBcpComponentPath(0u) + component;
1683       }
1684     } else {
1685       std::string to_match;
1686       if (slash_pos != std::string::npos) {
1687         // If we have the full path, we just need to match the filename to the BCP component.
1688         base_location = component.substr(0u, slash_pos + 1u) + base_name;
1689         to_match = component;
1690       }
1691       while (true) {
1692         if (slash_pos == std::string::npos) {
1693           // If we do not have a full path, we need to update the path based on the BCP location.
1694           std::string path = GetBcpComponentPath(bcp_pos);
1695           to_match = path + component;
1696           base_location = path + base_name;
1697         }
1698         if (ExpandLocation(base_location, bcp_pos) == to_match) {
1699           break;
1700         }
1701         ++bcp_pos;
1702         if (bcp_pos == bcp_component_count) {
1703           *error_msg = StringPrintf("Image component %s does not match a boot class path component",
1704                                     component.c_str());
1705           return false;
1706         }
1707       }
1708     }
1709     if (!profile_filename.empty() && profile_filename.find('/') == std::string::npos) {
1710       profile_filename.insert(/*pos*/ 0u, GetBcpComponentPath(bcp_pos));
1711     }
1712     NamedComponentLocation location;
1713     location.base_location = base_location;
1714     location.bcp_index = bcp_pos;
1715     location.profile_filename = profile_filename;
1716     named_component_locations->push_back(location);
1717     ++bcp_pos;
1718   }
1719   return true;
1720 }
1721 
ValidateBootImageChecksum(const char * file_description,const ImageHeader & header,std::string * error_msg)1722 bool ImageSpace::BootImageLayout::ValidateBootImageChecksum(const char* file_description,
1723                                                             const ImageHeader& header,
1724                                                             /*out*/std::string* error_msg) {
1725   uint32_t boot_image_component_count = header.GetBootImageComponentCount();
1726   if (chunks_.empty() != (boot_image_component_count == 0u)) {
1727     *error_msg = StringPrintf("Unexpected boot image component count in %s: %u, %s",
1728                               file_description,
1729                               boot_image_component_count,
1730                               chunks_.empty() ? "should be 0" : "should not be 0");
1731     return false;
1732   }
1733   uint32_t component_count = 0u;
1734   uint32_t composite_checksum = 0u;
1735   uint64_t boot_image_size = 0u;
1736   for (const ImageChunk& chunk : chunks_) {
1737     if (component_count == boot_image_component_count) {
1738       break;  // Hit the component count.
1739     }
1740     if (chunk.start_index != component_count) {
1741       break;  // End of contiguous chunks, fail below; same as reaching end of `chunks_`.
1742     }
1743     if (chunk.component_count > boot_image_component_count - component_count) {
1744       *error_msg = StringPrintf("Boot image component count in %s ends in the middle of a chunk, "
1745                                     "%u is between %u and %u",
1746                                 file_description,
1747                                 boot_image_component_count,
1748                                 component_count,
1749                                 component_count + chunk.component_count);
1750       return false;
1751     }
1752     component_count += chunk.component_count;
1753     composite_checksum ^= chunk.checksum;
1754     boot_image_size += chunk.reservation_size;
1755   }
1756   DCHECK_LE(component_count, boot_image_component_count);
1757   if (component_count != boot_image_component_count) {
1758     *error_msg = StringPrintf("Missing boot image components for checksum in %s: %u > %u",
1759                               file_description,
1760                               boot_image_component_count,
1761                               component_count);
1762     return false;
1763   }
1764   if (composite_checksum != header.GetBootImageChecksum()) {
1765     *error_msg = StringPrintf("Boot image checksum mismatch in %s: 0x%08x != 0x%08x",
1766                               file_description,
1767                               header.GetBootImageChecksum(),
1768                               composite_checksum);
1769     return false;
1770   }
1771   if (boot_image_size != header.GetBootImageSize()) {
1772     *error_msg = StringPrintf("Boot image size mismatch in %s: 0x%08x != 0x%08" PRIx64,
1773                               file_description,
1774                               header.GetBootImageSize(),
1775                               boot_image_size);
1776     return false;
1777   }
1778   return true;
1779 }
1780 
ValidateHeader(const ImageHeader & header,size_t bcp_index,const char * file_description,std::string * error_msg)1781 bool ImageSpace::BootImageLayout::ValidateHeader(const ImageHeader& header,
1782                                                  size_t bcp_index,
1783                                                  const char* file_description,
1784                                                  /*out*/std::string* error_msg) {
1785   size_t bcp_component_count = boot_class_path_.size();
1786   DCHECK_LT(bcp_index, bcp_component_count);
1787   size_t allowed_component_count = bcp_component_count - bcp_index;
1788   DCHECK_LE(total_reservation_size_, kMaxTotalImageReservationSize);
1789   size_t allowed_reservation_size = kMaxTotalImageReservationSize - total_reservation_size_;
1790 
1791   if (header.GetComponentCount() == 0u ||
1792       header.GetComponentCount() > allowed_component_count) {
1793     *error_msg = StringPrintf("Unexpected component count in %s, received %u, "
1794                                   "expected non-zero and <= %zu",
1795                               file_description,
1796                               header.GetComponentCount(),
1797                               allowed_component_count);
1798     return false;
1799   }
1800   if (header.GetImageReservationSize() > allowed_reservation_size) {
1801     *error_msg = StringPrintf("Reservation size too big in %s: %u > %zu",
1802                               file_description,
1803                               header.GetImageReservationSize(),
1804                               allowed_reservation_size);
1805     return false;
1806   }
1807   if (!ValidateBootImageChecksum(file_description, header, error_msg)) {
1808     return false;
1809   }
1810 
1811   return true;
1812 }
1813 
ReadHeader(const std::string & base_location,const std::string & base_filename,size_t bcp_index,std::string * error_msg)1814 bool ImageSpace::BootImageLayout::ReadHeader(const std::string& base_location,
1815                                              const std::string& base_filename,
1816                                              size_t bcp_index,
1817                                              /*out*/std::string* error_msg) {
1818   DCHECK_LE(next_bcp_index_, bcp_index);
1819   DCHECK_LT(bcp_index, boot_class_path_.size());
1820 
1821   std::string actual_filename = ExpandLocation(base_filename, bcp_index);
1822   ImageHeader header;
1823   if (!ReadSpecificImageHeader(actual_filename.c_str(), &header, error_msg)) {
1824     return false;
1825   }
1826   const char* file_description = actual_filename.c_str();
1827   if (!ValidateHeader(header, bcp_index, file_description, error_msg)) {
1828     return false;
1829   }
1830 
1831   if (chunks_.empty()) {
1832     base_address_ = reinterpret_cast32<uint32_t>(header.GetImageBegin());
1833   }
1834   ImageChunk chunk;
1835   chunk.base_location = base_location;
1836   chunk.base_filename = base_filename;
1837   chunk.start_index = bcp_index;
1838   chunk.component_count = header.GetComponentCount();
1839   chunk.image_space_count = header.GetImageSpaceCount();
1840   chunk.reservation_size = header.GetImageReservationSize();
1841   chunk.checksum = header.GetImageChecksum();
1842   chunk.boot_image_component_count = header.GetBootImageComponentCount();
1843   chunk.boot_image_checksum = header.GetBootImageChecksum();
1844   chunk.boot_image_size = header.GetBootImageSize();
1845   chunks_.push_back(std::move(chunk));
1846   next_bcp_index_ = bcp_index + header.GetComponentCount();
1847   total_component_count_ += header.GetComponentCount();
1848   total_reservation_size_ += header.GetImageReservationSize();
1849   return true;
1850 }
1851 
CompileExtension(const std::string & base_location,const std::string & base_filename,size_t bcp_index,const std::string & profile_filename,ArrayRef<std::string> dependencies,std::string * error_msg)1852 bool ImageSpace::BootImageLayout::CompileExtension(const std::string& base_location,
1853                                                    const std::string& base_filename,
1854                                                    size_t bcp_index,
1855                                                    const std::string& profile_filename,
1856                                                    ArrayRef<std::string> dependencies,
1857                                                    /*out*/std::string* error_msg) {
1858   DCHECK_LE(total_component_count_, next_bcp_index_);
1859   DCHECK_LE(next_bcp_index_, bcp_index);
1860   size_t bcp_component_count = boot_class_path_.size();
1861   DCHECK_LT(bcp_index, bcp_component_count);
1862   DCHECK(!profile_filename.empty());
1863   if (total_component_count_ != bcp_index) {
1864     // We require all previous BCP components to have a boot image space (primary or extension).
1865     *error_msg = "Cannot compile extension because of missing dependencies.";
1866     return false;
1867   }
1868   Runtime* runtime = Runtime::Current();
1869   if (!runtime->IsImageDex2OatEnabled()) {
1870     *error_msg = "Cannot compile extension because dex2oat for image compilation is disabled.";
1871     return false;
1872   }
1873 
1874   // Check dependencies.
1875   DCHECK(!dependencies.empty());
1876   size_t dependency_component_count = 0;
1877   for (size_t i = 0, size = dependencies.size(); i != size; ++i) {
1878     if (chunks_.size() == i || chunks_[i].start_index != dependency_component_count) {
1879       *error_msg = StringPrintf("Missing extension dependency \"%s\"", dependencies[i].c_str());
1880       return false;
1881     }
1882     dependency_component_count += chunks_[i].component_count;
1883   }
1884 
1885   // Collect locations from the profile.
1886   std::set<std::string> dex_locations;
1887   {
1888     std::unique_ptr<File> profile_file(OS::OpenFileForReading(profile_filename.c_str()));
1889     if (profile_file == nullptr) {
1890       *error_msg = StringPrintf("Failed to open profile file \"%s\" for reading, error: %s",
1891                                 profile_filename.c_str(),
1892                                 strerror(errno));
1893       return false;
1894     }
1895 
1896     // TODO: Rewrite ProfileCompilationInfo to provide a better interface and
1897     // to store the dex locations in uncompressed section of the file.
1898     auto collect_fn = [&dex_locations](const std::string& dex_location,
1899                                        uint32_t checksum ATTRIBUTE_UNUSED) {
1900       dex_locations.insert(dex_location);  // Just collect locations.
1901       return false;                        // Do not read the profile data.
1902     };
1903     ProfileCompilationInfo info(/*for_boot_image=*/ true);
1904     if (!info.Load(profile_file->Fd(), /*merge_classes=*/ true, collect_fn)) {
1905       *error_msg = StringPrintf("Failed to scan profile from %s", profile_filename.c_str());
1906       return false;
1907     }
1908   }
1909 
1910   // Match boot class path components to locations from profile.
1911   // Note that the profile records only filenames without paths.
1912   size_t bcp_end = bcp_index;
1913   for (; bcp_end != bcp_component_count; ++bcp_end) {
1914     const std::string& bcp_component = boot_class_path_locations_[bcp_end];
1915     size_t slash_pos = bcp_component.rfind('/');
1916     DCHECK_NE(slash_pos, std::string::npos);
1917     std::string bcp_component_name = bcp_component.substr(slash_pos + 1u);
1918     if (dex_locations.count(bcp_component_name) == 0u) {
1919       break;  // Did not find the current location in dex file.
1920     }
1921   }
1922 
1923   if (bcp_end == bcp_index) {
1924     // No data for the first (requested) component.
1925     *error_msg = StringPrintf("The profile does not contain data for %s",
1926                               boot_class_path_locations_[bcp_index].c_str());
1927     return false;
1928   }
1929 
1930   // Create in-memory files.
1931   std::string art_filename = ExpandLocation(base_filename, bcp_index);
1932   std::string vdex_filename = ImageHeader::GetVdexLocationFromImageLocation(art_filename);
1933   std::string oat_filename = ImageHeader::GetOatLocationFromImageLocation(art_filename);
1934   android::base::unique_fd art_fd(memfd_create_compat(art_filename.c_str(), /*flags=*/ 0));
1935   android::base::unique_fd vdex_fd(memfd_create_compat(vdex_filename.c_str(), /*flags=*/ 0));
1936   android::base::unique_fd oat_fd(memfd_create_compat(oat_filename.c_str(), /*flags=*/ 0));
1937   if (art_fd.get() == -1 || vdex_fd.get() == -1 || oat_fd.get() == -1) {
1938     *error_msg = StringPrintf("Failed to create memfd handles for compiling extension for %s",
1939                               boot_class_path_locations_[bcp_index].c_str());
1940     return false;
1941   }
1942 
1943   // Construct the dex2oat command line.
1944   std::string dex2oat = runtime->GetCompilerExecutable();
1945   ArrayRef<const std::string> head_bcp =
1946       boot_class_path_.SubArray(/*pos=*/ 0u, /*length=*/ dependency_component_count);
1947   ArrayRef<const std::string> head_bcp_locations =
1948       boot_class_path_locations_.SubArray(/*pos=*/ 0u, /*length=*/ dependency_component_count);
1949   ArrayRef<const std::string> extension_bcp =
1950       boot_class_path_.SubArray(/*pos=*/ bcp_index, /*length=*/ bcp_end - bcp_index);
1951   ArrayRef<const std::string> extension_bcp_locations =
1952       boot_class_path_locations_.SubArray(/*pos=*/ bcp_index, /*length=*/ bcp_end - bcp_index);
1953   std::string boot_class_path = Join(head_bcp, ':') + ':' + Join(extension_bcp, ':');
1954   std::string boot_class_path_locations =
1955       Join(head_bcp_locations, ':') + ':' + Join(extension_bcp_locations, ':');
1956 
1957   std::vector<std::string> args;
1958   args.push_back(dex2oat);
1959   args.push_back("--runtime-arg");
1960   args.push_back("-Xbootclasspath:" + boot_class_path);
1961   args.push_back("--runtime-arg");
1962   args.push_back("-Xbootclasspath-locations:" + boot_class_path_locations);
1963   args.push_back("--boot-image=" + Join(dependencies, kComponentSeparator));
1964   for (size_t i = bcp_index; i != bcp_end; ++i) {
1965     args.push_back("--dex-file=" + boot_class_path_[i]);
1966     args.push_back("--dex-location=" + boot_class_path_locations_[i]);
1967   }
1968   args.push_back("--image-fd=" + std::to_string(art_fd.get()));
1969   args.push_back("--output-vdex-fd=" + std::to_string(vdex_fd.get()));
1970   args.push_back("--oat-fd=" + std::to_string(oat_fd.get()));
1971   args.push_back("--oat-location=" + ImageHeader::GetOatLocationFromImageLocation(base_filename));
1972   args.push_back("--single-image");
1973   args.push_back("--image-format=uncompressed");
1974 
1975   // We currently cannot guarantee that the boot class path has no verification failures.
1976   // And we do not want to compile anything, compilation should be done by JIT in zygote.
1977   args.push_back("--compiler-filter=verify");
1978 
1979   // Pass the profile.
1980   args.push_back("--profile-file=" + profile_filename);
1981 
1982   // Do not let the file descriptor numbers change the compilation output.
1983   args.push_back("--avoid-storing-invocation");
1984 
1985   runtime->AddCurrentRuntimeFeaturesAsDex2OatArguments(&args);
1986 
1987   if (!kIsTargetBuild) {
1988     args.push_back("--host");
1989   }
1990 
1991   // Image compiler options go last to allow overriding above args, such as --compiler-filter.
1992   for (const std::string& compiler_option : runtime->GetImageCompilerOptions()) {
1993     args.push_back(compiler_option);
1994   }
1995 
1996   // Compile the extension.
1997   VLOG(image) << "Compiling boot image extension for " << (bcp_end - bcp_index)
1998               << " components, starting from " << boot_class_path_locations_[bcp_index];
1999   if (!Exec(args, error_msg)) {
2000     return false;
2001   }
2002 
2003   // Read and validate the image header.
2004   ImageHeader header;
2005   {
2006     File image_file(art_fd.release(), /*check_usage=*/ false);
2007     if (!ReadSpecificImageHeader(&image_file, "compiled image file", &header, error_msg)) {
2008       return false;
2009     }
2010     art_fd.reset(image_file.Release());
2011   }
2012   const char* file_description = "compiled image file";
2013   if (!ValidateHeader(header, bcp_index, file_description, error_msg)) {
2014     return false;
2015   }
2016 
2017   DCHECK(!chunks_.empty());
2018   ImageChunk chunk;
2019   chunk.base_location = base_location;
2020   chunk.base_filename = base_filename;
2021   chunk.profile_file = profile_filename;
2022   chunk.start_index = bcp_index;
2023   chunk.component_count = header.GetComponentCount();
2024   chunk.image_space_count = header.GetImageSpaceCount();
2025   chunk.reservation_size = header.GetImageReservationSize();
2026   chunk.checksum = header.GetImageChecksum();
2027   chunk.boot_image_component_count = header.GetBootImageComponentCount();
2028   chunk.boot_image_checksum = header.GetBootImageChecksum();
2029   chunk.boot_image_size = header.GetBootImageSize();
2030   chunk.art_fd.reset(art_fd.release());
2031   chunk.vdex_fd.reset(vdex_fd.release());
2032   chunk.oat_fd.reset(oat_fd.release());
2033   chunks_.push_back(std::move(chunk));
2034   next_bcp_index_ = bcp_index + header.GetComponentCount();
2035   total_component_count_ += header.GetComponentCount();
2036   total_reservation_size_ += header.GetImageReservationSize();
2037   return true;
2038 }
2039 
CheckAndRemoveLastChunkChecksum(std::string_view * oat_checksums,std::string * error_msg)2040 bool ImageSpace::BootImageLayout::CheckAndRemoveLastChunkChecksum(
2041     /*inout*/std::string_view* oat_checksums,
2042     /*out*/std::string* error_msg) {
2043   DCHECK(oat_checksums != nullptr);
2044   DCHECK(!chunks_.empty());
2045   const ImageChunk& chunk = chunks_.back();
2046   size_t component_count = chunk.component_count;
2047   size_t checksum = chunk.checksum;
2048   if (!CheckAndRemoveImageChecksum(component_count, checksum, oat_checksums, error_msg)) {
2049     DCHECK(!error_msg->empty());
2050     return false;
2051   }
2052   if (oat_checksums->empty()) {
2053     if (next_bcp_index_ != boot_class_path_.size()) {
2054       *error_msg = StringPrintf("Checksum too short, missing %zu components.",
2055                                 boot_class_path_.size() - next_bcp_index_);
2056       return false;
2057     }
2058     return true;
2059   }
2060   if (!StartsWith(*oat_checksums, ":")) {
2061     *error_msg = StringPrintf("Missing ':' separator at start of %s",
2062                               std::string(*oat_checksums).c_str());
2063     return false;
2064   }
2065   oat_checksums->remove_prefix(1u);
2066   if (oat_checksums->empty()) {
2067     *error_msg = "Missing checksums after the ':' separator.";
2068     return false;
2069   }
2070   return true;
2071 }
2072 
2073 template <typename FilenameFn>
LoadOrValidate(FilenameFn && filename_fn,std::string_view * oat_checksums,std::string * error_msg)2074 bool ImageSpace::BootImageLayout::LoadOrValidate(FilenameFn&& filename_fn,
2075                                                  /*inout*/std::string_view* oat_checksums,
2076                                                  /*out*/std::string* error_msg) {
2077   DCHECK(GetChunks().empty());
2078   DCHECK_EQ(GetBaseAddress(), 0u);
2079   bool validate = (oat_checksums != nullptr);
2080   static_assert(ImageSpace::kImageChecksumPrefix == 'i', "Format prefix check.");
2081   DCHECK(!validate || StartsWith(*oat_checksums, "i"));
2082 
2083   std::vector<std::string> components;
2084   Split(image_location_, kComponentSeparator, &components);
2085   size_t named_components_count = 0u;
2086   if (!VerifyImageLocation(components, &named_components_count, error_msg)) {
2087     return false;
2088   }
2089 
2090   ArrayRef<const std::string> named_components =
2091       ArrayRef<const std::string>(components).SubArray(/*pos=*/ 0u, named_components_count);
2092 
2093   std::vector<NamedComponentLocation> named_component_locations;
2094   if (!MatchNamedComponents(named_components, &named_component_locations, error_msg)) {
2095     return false;
2096   }
2097 
2098   // Load the image headers of named components.
2099   DCHECK_EQ(named_component_locations.size(), named_components.size());
2100   const size_t bcp_component_count = boot_class_path_.size();
2101   size_t bcp_pos = 0u;
2102   ArrayRef<std::string> extension_dependencies;
2103   for (size_t i = 0, size = named_components.size(); i != size; ++i) {
2104     const std::string& base_location = named_component_locations[i].base_location;
2105     size_t bcp_index = named_component_locations[i].bcp_index;
2106     const std::string& profile_filename = named_component_locations[i].profile_filename;
2107     if (extension_dependencies.empty() && !profile_filename.empty()) {
2108       // Each extension is compiled against the same dependencies, namely the leading
2109       // named components that were specified without providing the profile filename.
2110       extension_dependencies =
2111           ArrayRef<std::string>(components).SubArray(/*pos=*/ 0, /*length=*/ i);
2112     }
2113     if (bcp_index < bcp_pos) {
2114       DCHECK_NE(i, 0u);
2115       LOG(ERROR) << "Named image component already covered by previous image: " << base_location;
2116       continue;
2117     }
2118     if (validate && bcp_index > bcp_pos) {
2119       *error_msg = StringPrintf("End of contiguous boot class path images, remaining checksum: %s",
2120                                 std::string(*oat_checksums).c_str());
2121       return false;
2122     }
2123     std::string local_error_msg;
2124     std::string* err_msg = (i == 0 || validate) ? error_msg : &local_error_msg;
2125     std::string base_filename;
2126     if (!filename_fn(base_location, &base_filename, err_msg) ||
2127         !ReadHeader(base_location, base_filename, bcp_index, err_msg)) {
2128       if (i == 0u || validate) {
2129         return false;
2130       }
2131       VLOG(image) << "Error reading named image component header for " << base_location
2132                   << ", error: " << local_error_msg;
2133       if (profile_filename.empty() ||
2134           !CompileExtension(base_location,
2135                             base_filename,
2136                             bcp_index,
2137                             profile_filename,
2138                             extension_dependencies,
2139                             &local_error_msg)) {
2140         if (!profile_filename.empty()) {
2141           VLOG(image) << "Error compiling extension for " << boot_class_path_[bcp_index]
2142                       << " error: " << local_error_msg;
2143         }
2144         bcp_pos = bcp_index + 1u;  // Skip at least this component.
2145         DCHECK_GT(bcp_pos, GetNextBcpIndex());
2146         continue;
2147       }
2148     }
2149     if (validate) {
2150       if (!CheckAndRemoveLastChunkChecksum(oat_checksums, error_msg)) {
2151         return false;
2152       }
2153       if (oat_checksums->empty() || !StartsWith(*oat_checksums, "i")) {
2154         return true;  // Let the caller deal with the dex file checksums if any.
2155       }
2156     }
2157     bcp_pos = GetNextBcpIndex();
2158   }
2159 
2160   // Look for remaining components if there are any wildcard specifications.
2161   ArrayRef<const std::string> search_paths =
2162       ArrayRef<const std::string>(components).SubArray(/*pos=*/ named_components_count);
2163   if (!search_paths.empty()) {
2164     const std::string& primary_base_location = named_component_locations[0].base_location;
2165     size_t base_slash_pos = primary_base_location.rfind('/');
2166     DCHECK_NE(base_slash_pos, std::string::npos);
2167     std::string base_name = primary_base_location.substr(base_slash_pos + 1u);
2168     DCHECK(!base_name.empty());
2169     while (bcp_pos != bcp_component_count) {
2170       const std::string& bcp_component =  boot_class_path_[bcp_pos];
2171       bool found = false;
2172       for (const std::string& path : search_paths) {
2173         std::string base_location;
2174         if (path.size() == 1u) {
2175           DCHECK_EQ(path, "*");
2176           size_t slash_pos = bcp_component.rfind('/');
2177           DCHECK_NE(slash_pos, std::string::npos);
2178           base_location = bcp_component.substr(0u, slash_pos + 1u) + base_name;
2179         } else {
2180           DCHECK(EndsWith(path, "/*"));
2181           base_location = path.substr(0u, path.size() - 1u) + base_name;
2182         }
2183         std::string err_msg;  // Ignored.
2184         std::string base_filename;
2185         if (filename_fn(base_location, &base_filename, &err_msg) &&
2186             ReadHeader(base_location, base_filename, bcp_pos, &err_msg)) {
2187           VLOG(image) << "Found image extension for " << ExpandLocation(base_location, bcp_pos);
2188           bcp_pos = GetNextBcpIndex();
2189           found = true;
2190           if (validate) {
2191             if (!CheckAndRemoveLastChunkChecksum(oat_checksums, error_msg)) {
2192               return false;
2193             }
2194             if (oat_checksums->empty() || !StartsWith(*oat_checksums, "i")) {
2195               return true;  // Let the caller deal with the dex file checksums if any.
2196             }
2197           }
2198           break;
2199         }
2200       }
2201       if (!found) {
2202         if (validate) {
2203           *error_msg = StringPrintf("Missing extension for %s, remaining checksum: %s",
2204                                     bcp_component.c_str(),
2205                                     std::string(*oat_checksums).c_str());
2206           return false;
2207         }
2208         ++bcp_pos;
2209       }
2210     }
2211   }
2212 
2213   return true;
2214 }
2215 
LoadOrValidateFromSystem(InstructionSet image_isa,std::string_view * oat_checksums,std::string * error_msg)2216 bool ImageSpace::BootImageLayout::LoadOrValidateFromSystem(InstructionSet image_isa,
2217                                                            /*inout*/std::string_view* oat_checksums,
2218                                                            /*out*/std::string* error_msg) {
2219   auto filename_fn = [image_isa](const std::string& location,
2220                                  /*out*/std::string* filename,
2221                                  /*out*/std::string* err_msg ATTRIBUTE_UNUSED) {
2222     *filename = GetSystemImageFilename(location.c_str(), image_isa);
2223     return true;
2224   };
2225   return LoadOrValidate(filename_fn, oat_checksums, error_msg);
2226 }
2227 
2228 class ImageSpace::BootImageLoader {
2229  public:
BootImageLoader(const std::vector<std::string> & boot_class_path,const std::vector<std::string> & boot_class_path_locations,const std::string & image_location,InstructionSet image_isa,bool relocate,bool executable)2230   BootImageLoader(const std::vector<std::string>& boot_class_path,
2231                   const std::vector<std::string>& boot_class_path_locations,
2232                   const std::string& image_location,
2233                   InstructionSet image_isa,
2234                   bool relocate,
2235                   bool executable)
2236       : boot_class_path_(boot_class_path),
2237         boot_class_path_locations_(boot_class_path_locations),
2238         image_location_(image_location),
2239         image_isa_(image_isa),
2240         relocate_(relocate),
2241         executable_(executable),
2242         has_system_(false) {
2243   }
2244 
FindImageFiles()2245   void FindImageFiles() {
2246     BootImageLayout layout(image_location_, boot_class_path_, boot_class_path_locations_);
2247     std::string image_location = layout.GetPrimaryImageLocation();
2248     std::string system_filename;
2249     bool found_image = FindImageFilenameImpl(image_location.c_str(),
2250                                              image_isa_,
2251                                              &has_system_,
2252                                              &system_filename);
2253     DCHECK_EQ(found_image, has_system_);
2254   }
2255 
HasSystem() const2256   bool HasSystem() const { return has_system_; }
2257 
2258   bool LoadFromSystem(size_t extra_reservation_size,
2259                       /*out*/std::vector<std::unique_ptr<ImageSpace>>* boot_image_spaces,
2260                       /*out*/MemMap* extra_reservation,
2261                       /*out*/std::string* error_msg) REQUIRES_SHARED(Locks::mutator_lock_);
2262 
2263  private:
LoadImage(const BootImageLayout & layout,bool validate_oat_file,size_t extra_reservation_size,TimingLogger * logger,std::vector<std::unique_ptr<ImageSpace>> * boot_image_spaces,MemMap * extra_reservation,std::string * error_msg)2264   bool LoadImage(
2265       const BootImageLayout& layout,
2266       bool validate_oat_file,
2267       size_t extra_reservation_size,
2268       TimingLogger* logger,
2269       /*out*/std::vector<std::unique_ptr<ImageSpace>>* boot_image_spaces,
2270       /*out*/MemMap* extra_reservation,
2271       /*out*/std::string* error_msg) REQUIRES_SHARED(Locks::mutator_lock_) {
2272     ArrayRef<const BootImageLayout::ImageChunk> chunks = layout.GetChunks();
2273     DCHECK(!chunks.empty());
2274     const uint32_t base_address = layout.GetBaseAddress();
2275     const size_t image_component_count = layout.GetTotalComponentCount();
2276     const size_t image_reservation_size = layout.GetTotalReservationSize();
2277 
2278     DCHECK_LE(image_reservation_size, kMaxTotalImageReservationSize);
2279     static_assert(kMaxTotalImageReservationSize < std::numeric_limits<uint32_t>::max());
2280     if (extra_reservation_size > std::numeric_limits<uint32_t>::max() - image_reservation_size) {
2281       // Since the `image_reservation_size` is limited to kMaxTotalImageReservationSize,
2282       // the `extra_reservation_size` would have to be really excessive to fail this check.
2283       *error_msg = StringPrintf("Excessive extra reservation size: %zu", extra_reservation_size);
2284       return false;
2285     }
2286 
2287     // Reserve address space. If relocating, choose a random address for ALSR.
2288     uint8_t* addr = reinterpret_cast<uint8_t*>(
2289         relocate_ ? ART_BASE_ADDRESS + ChooseRelocationOffsetDelta() : base_address);
2290     MemMap image_reservation =
2291         ReserveBootImageMemory(addr, image_reservation_size + extra_reservation_size, error_msg);
2292     if (!image_reservation.IsValid()) {
2293       return false;
2294     }
2295 
2296     // Load components.
2297     std::vector<std::unique_ptr<ImageSpace>> spaces;
2298     spaces.reserve(image_component_count);
2299     size_t max_image_space_dependencies = 0u;
2300     for (size_t i = 0, num_chunks = chunks.size(); i != num_chunks; ++i) {
2301       const BootImageLayout::ImageChunk& chunk = chunks[i];
2302       std::string extension_error_msg;
2303       uint8_t* old_reservation_begin = image_reservation.Begin();
2304       size_t old_reservation_size = image_reservation.Size();
2305       DCHECK_LE(chunk.reservation_size, old_reservation_size);
2306       if (!LoadComponents(chunk,
2307                           validate_oat_file,
2308                           max_image_space_dependencies,
2309                           logger,
2310                           &spaces,
2311                           &image_reservation,
2312                           (i == 0) ? error_msg : &extension_error_msg)) {
2313         // Failed to load the chunk. If this is the primary boot image, report the error.
2314         if (i == 0) {
2315           return false;
2316         }
2317         // For extension, shrink the reservation (and remap if needed, see below).
2318         size_t new_reservation_size = old_reservation_size - chunk.reservation_size;
2319         if (new_reservation_size == 0u) {
2320           DCHECK_EQ(extra_reservation_size, 0u);
2321           DCHECK_EQ(i + 1u, num_chunks);
2322           image_reservation.Reset();
2323         } else if (old_reservation_begin != image_reservation.Begin()) {
2324           // Part of the image reservation has been used and then unmapped when
2325           // rollling back the partial boot image extension load. Try to remap
2326           // the image reservation. As this should be running single-threaded,
2327           // the address range should still be available to mmap().
2328           image_reservation.Reset();
2329           std::string remap_error_msg;
2330           image_reservation = ReserveBootImageMemory(old_reservation_begin,
2331                                                      new_reservation_size,
2332                                                      &remap_error_msg);
2333           if (!image_reservation.IsValid()) {
2334             *error_msg = StringPrintf("Failed to remap boot image reservation after failing "
2335                                           "to load boot image extension (%s: %s): %s",
2336                                       boot_class_path_locations_[chunk.start_index].c_str(),
2337                                       extension_error_msg.c_str(),
2338                                       remap_error_msg.c_str());
2339             return false;
2340           }
2341         } else {
2342           DCHECK_EQ(old_reservation_size, image_reservation.Size());
2343           image_reservation.SetSize(new_reservation_size);
2344         }
2345         LOG(ERROR) << "Failed to load boot image extension "
2346             << boot_class_path_locations_[chunk.start_index] << ": " << extension_error_msg;
2347       }
2348       // Update `max_image_space_dependencies` if all previous BCP components
2349       // were covered and loading the current chunk succeeded.
2350       if (max_image_space_dependencies == chunk.start_index &&
2351           spaces.size() == chunk.start_index + chunk.component_count) {
2352         max_image_space_dependencies = chunk.start_index + chunk.component_count;
2353       }
2354     }
2355 
2356     MemMap local_extra_reservation;
2357     if (!RemapExtraReservation(extra_reservation_size,
2358                                &image_reservation,
2359                                &local_extra_reservation,
2360                                error_msg)) {
2361       return false;
2362     }
2363 
2364     MaybeRelocateSpaces(spaces, logger);
2365     DeduplicateInternedStrings(ArrayRef<const std::unique_ptr<ImageSpace>>(spaces), logger);
2366     boot_image_spaces->swap(spaces);
2367     *extra_reservation = std::move(local_extra_reservation);
2368     return true;
2369   }
2370 
2371  private:
2372   class SimpleRelocateVisitor {
2373    public:
SimpleRelocateVisitor(uint32_t diff,uint32_t begin,uint32_t size)2374     SimpleRelocateVisitor(uint32_t diff, uint32_t begin, uint32_t size)
2375         : diff_(diff), begin_(begin), size_(size) {}
2376 
2377     // Adapter taking the same arguments as SplitRangeRelocateVisitor
2378     // to simplify constructing the various visitors in DoRelocateSpaces().
SimpleRelocateVisitor(uint32_t base_diff,uint32_t current_diff,uint32_t bound,uint32_t begin,uint32_t size)2379     SimpleRelocateVisitor(uint32_t base_diff,
2380                           uint32_t current_diff,
2381                           uint32_t bound,
2382                           uint32_t begin,
2383                           uint32_t size)
2384         : SimpleRelocateVisitor(base_diff, begin, size) {
2385       // Check arguments unused by this class.
2386       DCHECK_EQ(base_diff, current_diff);
2387       DCHECK_EQ(bound, begin);
2388     }
2389 
2390     template <typename T>
operator ()(T * src) const2391     ALWAYS_INLINE T* operator()(T* src) const {
2392       DCHECK(InSource(src));
2393       uint32_t raw_src = reinterpret_cast32<uint32_t>(src);
2394       return reinterpret_cast32<T*>(raw_src + diff_);
2395     }
2396 
2397     template <typename T>
InSource(T * ptr) const2398     ALWAYS_INLINE bool InSource(T* ptr) const {
2399       uint32_t raw_ptr = reinterpret_cast32<uint32_t>(ptr);
2400       return raw_ptr - begin_ < size_;
2401     }
2402 
2403     template <typename T>
InDest(T * ptr) const2404     ALWAYS_INLINE bool InDest(T* ptr) const {
2405       uint32_t raw_ptr = reinterpret_cast32<uint32_t>(ptr);
2406       uint32_t src_ptr = raw_ptr - diff_;
2407       return src_ptr - begin_ < size_;
2408     }
2409 
2410    private:
2411     const uint32_t diff_;
2412     const uint32_t begin_;
2413     const uint32_t size_;
2414   };
2415 
2416   class SplitRangeRelocateVisitor {
2417    public:
SplitRangeRelocateVisitor(uint32_t base_diff,uint32_t current_diff,uint32_t bound,uint32_t begin,uint32_t size)2418     SplitRangeRelocateVisitor(uint32_t base_diff,
2419                               uint32_t current_diff,
2420                               uint32_t bound,
2421                               uint32_t begin,
2422                               uint32_t size)
2423         : base_diff_(base_diff),
2424           current_diff_(current_diff),
2425           bound_(bound),
2426           begin_(begin),
2427           size_(size) {
2428       DCHECK_NE(begin_, bound_);
2429       // The bound separates the boot image range and the extension range.
2430       DCHECK_LT(bound_ - begin_, size_);
2431     }
2432 
2433     template <typename T>
operator ()(T * src) const2434     ALWAYS_INLINE T* operator()(T* src) const {
2435       DCHECK(InSource(src));
2436       uint32_t raw_src = reinterpret_cast32<uint32_t>(src);
2437       uint32_t diff = (raw_src < bound_) ? base_diff_ : current_diff_;
2438       return reinterpret_cast32<T*>(raw_src + diff);
2439     }
2440 
2441     template <typename T>
InSource(T * ptr) const2442     ALWAYS_INLINE bool InSource(T* ptr) const {
2443       uint32_t raw_ptr = reinterpret_cast32<uint32_t>(ptr);
2444       return raw_ptr - begin_ < size_;
2445     }
2446 
2447    private:
2448     const uint32_t base_diff_;
2449     const uint32_t current_diff_;
2450     const uint32_t bound_;
2451     const uint32_t begin_;
2452     const uint32_t size_;
2453   };
2454 
PointerAddress(ArtMethod * method,MemberOffset offset)2455   static void** PointerAddress(ArtMethod* method, MemberOffset offset) {
2456     return reinterpret_cast<void**>(reinterpret_cast<uint8_t*>(method) + offset.Uint32Value());
2457   }
2458 
2459   template <PointerSize kPointerSize>
DoRelocateSpaces(ArrayRef<const std::unique_ptr<ImageSpace>> & spaces,int64_t base_diff64)2460   static void DoRelocateSpaces(ArrayRef<const std::unique_ptr<ImageSpace>>& spaces,
2461                                int64_t base_diff64) REQUIRES_SHARED(Locks::mutator_lock_) {
2462     DCHECK(!spaces.empty());
2463     gc::accounting::ContinuousSpaceBitmap patched_objects(
2464         gc::accounting::ContinuousSpaceBitmap::Create(
2465             "Marked objects",
2466             spaces.front()->Begin(),
2467             spaces.back()->End() - spaces.front()->Begin()));
2468     const ImageHeader& base_header = spaces[0]->GetImageHeader();
2469     size_t base_image_space_count = base_header.GetImageSpaceCount();
2470     DCHECK_LE(base_image_space_count, spaces.size());
2471     DoRelocateSpaces<kPointerSize, /*kExtension=*/ false>(
2472         spaces.SubArray(/*pos=*/ 0u, base_image_space_count),
2473         base_diff64,
2474         &patched_objects);
2475 
2476     for (size_t i = base_image_space_count, size = spaces.size(); i != size; ) {
2477       const ImageHeader& ext_header = spaces[i]->GetImageHeader();
2478       size_t ext_image_space_count = ext_header.GetImageSpaceCount();
2479       DCHECK_LE(ext_image_space_count, size - i);
2480       DoRelocateSpaces<kPointerSize, /*kExtension=*/ true>(
2481           spaces.SubArray(/*pos=*/ i, ext_image_space_count),
2482           base_diff64,
2483           &patched_objects);
2484       i += ext_image_space_count;
2485     }
2486   }
2487 
2488   template <PointerSize kPointerSize, bool kExtension>
DoRelocateSpaces(ArrayRef<const std::unique_ptr<ImageSpace>> spaces,int64_t base_diff64,gc::accounting::ContinuousSpaceBitmap * patched_objects)2489   static void DoRelocateSpaces(ArrayRef<const std::unique_ptr<ImageSpace>> spaces,
2490                                int64_t base_diff64,
2491                                gc::accounting::ContinuousSpaceBitmap* patched_objects)
2492       REQUIRES_SHARED(Locks::mutator_lock_) {
2493     DCHECK(!spaces.empty());
2494     const ImageHeader& first_header = spaces.front()->GetImageHeader();
2495     uint32_t image_begin = reinterpret_cast32<uint32_t>(first_header.GetImageBegin());
2496     uint32_t image_size = first_header.GetImageReservationSize();
2497     DCHECK_NE(image_size, 0u);
2498     uint32_t source_begin = kExtension ? first_header.GetBootImageBegin() : image_begin;
2499     uint32_t source_size = kExtension ? first_header.GetBootImageSize() + image_size : image_size;
2500     if (kExtension) {
2501       DCHECK_EQ(first_header.GetBootImageBegin() + first_header.GetBootImageSize(), image_begin);
2502     }
2503     int64_t current_diff64 = kExtension
2504         ? static_cast<int64_t>(reinterpret_cast32<uint32_t>(spaces.front()->Begin())) -
2505               static_cast<int64_t>(image_begin)
2506         : base_diff64;
2507     if (base_diff64 == 0 && current_diff64 == 0) {
2508       return;
2509     }
2510     uint32_t base_diff = static_cast<uint32_t>(base_diff64);
2511     uint32_t current_diff = static_cast<uint32_t>(current_diff64);
2512 
2513     // For boot image the main visitor is a SimpleRelocateVisitor. For the boot image extension we
2514     // mostly use a SplitRelocationVisitor but some work can still use the SimpleRelocationVisitor.
2515     using MainRelocateVisitor = typename std::conditional<
2516         kExtension, SplitRangeRelocateVisitor, SimpleRelocateVisitor>::type;
2517     SimpleRelocateVisitor simple_relocate_visitor(current_diff, image_begin, image_size);
2518     MainRelocateVisitor main_relocate_visitor(
2519         base_diff, current_diff, /*bound=*/ image_begin, source_begin, source_size);
2520 
2521     using MainPatchRelocateVisitor =
2522         PatchObjectVisitor<kPointerSize, MainRelocateVisitor, MainRelocateVisitor>;
2523     using SimplePatchRelocateVisitor =
2524         PatchObjectVisitor<kPointerSize, SimpleRelocateVisitor, SimpleRelocateVisitor>;
2525     MainPatchRelocateVisitor main_patch_object_visitor(main_relocate_visitor,
2526                                                        main_relocate_visitor);
2527     SimplePatchRelocateVisitor simple_patch_object_visitor(simple_relocate_visitor,
2528                                                            simple_relocate_visitor);
2529 
2530     // Retrieve the Class.class, Method.class and Constructor.class needed in the loops below.
2531     ObjPtr<mirror::ObjectArray<mirror::Class>> class_roots;
2532     ObjPtr<mirror::Class> class_class;
2533     ObjPtr<mirror::Class> method_class;
2534     ObjPtr<mirror::Class> constructor_class;
2535     {
2536       ObjPtr<mirror::ObjectArray<mirror::Object>> image_roots =
2537           simple_relocate_visitor(first_header.GetImageRoots<kWithoutReadBarrier>().Ptr());
2538       DCHECK(!patched_objects->Test(image_roots.Ptr()));
2539 
2540       SimpleRelocateVisitor base_relocate_visitor(
2541           base_diff,
2542           source_begin,
2543           kExtension ? source_size - image_size : image_size);
2544       int32_t class_roots_index = enum_cast<int32_t>(ImageHeader::kClassRoots);
2545       DCHECK_LT(class_roots_index, image_roots->GetLength<kVerifyNone>());
2546       class_roots = ObjPtr<mirror::ObjectArray<mirror::Class>>::DownCast(base_relocate_visitor(
2547           image_roots->GetWithoutChecks<kVerifyNone>(class_roots_index).Ptr()));
2548       if (kExtension) {
2549         // Class roots must have been visited if we relocated the primary boot image.
2550         DCHECK(base_diff == 0 || patched_objects->Test(class_roots.Ptr()));
2551         class_class = GetClassRoot<mirror::Class, kWithoutReadBarrier>(class_roots);
2552         method_class = GetClassRoot<mirror::Method, kWithoutReadBarrier>(class_roots);
2553         constructor_class = GetClassRoot<mirror::Constructor, kWithoutReadBarrier>(class_roots);
2554       } else {
2555         DCHECK(!patched_objects->Test(class_roots.Ptr()));
2556         class_class = simple_relocate_visitor(
2557             GetClassRoot<mirror::Class, kWithoutReadBarrier>(class_roots).Ptr());
2558         method_class = simple_relocate_visitor(
2559             GetClassRoot<mirror::Method, kWithoutReadBarrier>(class_roots).Ptr());
2560         constructor_class = simple_relocate_visitor(
2561             GetClassRoot<mirror::Constructor, kWithoutReadBarrier>(class_roots).Ptr());
2562       }
2563     }
2564 
2565     for (const std::unique_ptr<ImageSpace>& space : spaces) {
2566       // First patch the image header.
2567       reinterpret_cast<ImageHeader*>(space->Begin())->RelocateImageReferences(current_diff64);
2568       reinterpret_cast<ImageHeader*>(space->Begin())->RelocateBootImageReferences(base_diff64);
2569 
2570       // Patch fields and methods.
2571       const ImageHeader& image_header = space->GetImageHeader();
2572       image_header.VisitPackedArtFields([&](ArtField& field) REQUIRES_SHARED(Locks::mutator_lock_) {
2573         // Fields always reference class in the current image.
2574         simple_patch_object_visitor.template PatchGcRoot</*kMayBeNull=*/ false>(
2575             &field.DeclaringClassRoot());
2576       }, space->Begin());
2577       image_header.VisitPackedArtMethods([&](ArtMethod& method)
2578           REQUIRES_SHARED(Locks::mutator_lock_) {
2579         main_patch_object_visitor.PatchGcRoot(&method.DeclaringClassRoot());
2580         if (!method.HasCodeItem()) {
2581           void** data_address = PointerAddress(&method, ArtMethod::DataOffset(kPointerSize));
2582           main_patch_object_visitor.PatchNativePointer(data_address);
2583         }
2584         void** entrypoint_address =
2585             PointerAddress(&method, ArtMethod::EntryPointFromQuickCompiledCodeOffset(kPointerSize));
2586         main_patch_object_visitor.PatchNativePointer(entrypoint_address);
2587       }, space->Begin(), kPointerSize);
2588       auto method_table_visitor = [&](ArtMethod* method) {
2589         DCHECK(method != nullptr);
2590         return main_relocate_visitor(method);
2591       };
2592       image_header.VisitPackedImTables(method_table_visitor, space->Begin(), kPointerSize);
2593       image_header.VisitPackedImtConflictTables(method_table_visitor, space->Begin(), kPointerSize);
2594 
2595       // Patch the intern table.
2596       if (image_header.GetInternedStringsSection().Size() != 0u) {
2597         const uint8_t* data = space->Begin() + image_header.GetInternedStringsSection().Offset();
2598         size_t read_count;
2599         InternTable::UnorderedSet temp_set(data, /*make_copy_of_data=*/ false, &read_count);
2600         for (GcRoot<mirror::String>& slot : temp_set) {
2601           // The intern table contains only strings in the current image.
2602           simple_patch_object_visitor.template PatchGcRoot</*kMayBeNull=*/ false>(&slot);
2603         }
2604       }
2605 
2606       // Patch the class table and classes, so that we can traverse class hierarchy to
2607       // determine the types of other objects when we visit them later.
2608       if (image_header.GetClassTableSection().Size() != 0u) {
2609         uint8_t* data = space->Begin() + image_header.GetClassTableSection().Offset();
2610         size_t read_count;
2611         ClassTable::ClassSet temp_set(data, /*make_copy_of_data=*/ false, &read_count);
2612         DCHECK(!temp_set.empty());
2613         // The class table contains only classes in the current image.
2614         ClassTableVisitor class_table_visitor(simple_relocate_visitor);
2615         for (ClassTable::TableSlot& slot : temp_set) {
2616           slot.VisitRoot(class_table_visitor);
2617           ObjPtr<mirror::Class> klass = slot.Read<kWithoutReadBarrier>();
2618           DCHECK(klass != nullptr);
2619           DCHECK(!patched_objects->Test(klass.Ptr()));
2620           patched_objects->Set(klass.Ptr());
2621           main_patch_object_visitor.VisitClass(klass, class_class);
2622           // Then patch the non-embedded vtable and iftable.
2623           ObjPtr<mirror::PointerArray> vtable =
2624               klass->GetVTable<kVerifyNone, kWithoutReadBarrier>();
2625           if ((kExtension ? simple_relocate_visitor.InDest(vtable.Ptr()) : vtable != nullptr) &&
2626               !patched_objects->Set(vtable.Ptr())) {
2627             main_patch_object_visitor.VisitPointerArray(vtable);
2628           }
2629           ObjPtr<mirror::IfTable> iftable = klass->GetIfTable<kVerifyNone, kWithoutReadBarrier>();
2630           if (iftable != nullptr) {
2631             int32_t ifcount = klass->GetIfTableCount<kVerifyNone>();
2632             for (int32_t i = 0; i != ifcount; ++i) {
2633               ObjPtr<mirror::PointerArray> unpatched_ifarray =
2634                   iftable->GetMethodArrayOrNull<kVerifyNone, kWithoutReadBarrier>(i);
2635               if (kExtension ? simple_relocate_visitor.InSource(unpatched_ifarray.Ptr())
2636                              : unpatched_ifarray != nullptr) {
2637                 // The iftable has not been patched, so we need to explicitly adjust the pointer.
2638                 ObjPtr<mirror::PointerArray> ifarray =
2639                     simple_relocate_visitor(unpatched_ifarray.Ptr());
2640                 if (!patched_objects->Set(ifarray.Ptr())) {
2641                   main_patch_object_visitor.VisitPointerArray(ifarray);
2642                 }
2643               }
2644             }
2645           }
2646         }
2647       }
2648     }
2649 
2650     for (const std::unique_ptr<ImageSpace>& space : spaces) {
2651       const ImageHeader& image_header = space->GetImageHeader();
2652 
2653       static_assert(IsAligned<kObjectAlignment>(sizeof(ImageHeader)), "Header alignment check");
2654       uint32_t objects_end = image_header.GetObjectsSection().Size();
2655       DCHECK_ALIGNED(objects_end, kObjectAlignment);
2656       for (uint32_t pos = sizeof(ImageHeader); pos != objects_end; ) {
2657         mirror::Object* object = reinterpret_cast<mirror::Object*>(space->Begin() + pos);
2658         // Note: use Test() rather than Set() as this is the last time we're checking this object.
2659         if (!patched_objects->Test(object)) {
2660           // This is the last pass over objects, so we do not need to Set().
2661           main_patch_object_visitor.VisitObject(object);
2662           ObjPtr<mirror::Class> klass = object->GetClass<kVerifyNone, kWithoutReadBarrier>();
2663           if (klass == method_class || klass == constructor_class) {
2664             // Patch the ArtMethod* in the mirror::Executable subobject.
2665             ObjPtr<mirror::Executable> as_executable =
2666                 ObjPtr<mirror::Executable>::DownCast(object);
2667             ArtMethod* unpatched_method = as_executable->GetArtMethod<kVerifyNone>();
2668             ArtMethod* patched_method = main_relocate_visitor(unpatched_method);
2669             as_executable->SetArtMethod</*kTransactionActive=*/ false,
2670                                         /*kCheckTransaction=*/ true,
2671                                         kVerifyNone>(patched_method);
2672           }
2673         }
2674         pos += RoundUp(object->SizeOf<kVerifyNone>(), kObjectAlignment);
2675       }
2676     }
2677     if (kIsDebugBuild && !kExtension) {
2678       // We used just Test() instead of Set() above but we need to use Set()
2679       // for class roots to satisfy a DCHECK() for extensions.
2680       DCHECK(!patched_objects->Test(class_roots.Ptr()));
2681       patched_objects->Set(class_roots.Ptr());
2682     }
2683   }
2684 
MaybeRelocateSpaces(const std::vector<std::unique_ptr<ImageSpace>> & spaces,TimingLogger * logger)2685   void MaybeRelocateSpaces(const std::vector<std::unique_ptr<ImageSpace>>& spaces,
2686                            TimingLogger* logger)
2687       REQUIRES_SHARED(Locks::mutator_lock_) {
2688     TimingLogger::ScopedTiming timing("MaybeRelocateSpaces", logger);
2689     ImageSpace* first_space = spaces.front().get();
2690     const ImageHeader& first_space_header = first_space->GetImageHeader();
2691     int64_t base_diff64 =
2692         static_cast<int64_t>(reinterpret_cast32<uint32_t>(first_space->Begin())) -
2693         static_cast<int64_t>(reinterpret_cast32<uint32_t>(first_space_header.GetImageBegin()));
2694     if (!relocate_) {
2695       DCHECK_EQ(base_diff64, 0);
2696     }
2697 
2698     ArrayRef<const std::unique_ptr<ImageSpace>> spaces_ref(spaces);
2699     PointerSize pointer_size = first_space_header.GetPointerSize();
2700     if (pointer_size == PointerSize::k64) {
2701       DoRelocateSpaces<PointerSize::k64>(spaces_ref, base_diff64);
2702     } else {
2703       DoRelocateSpaces<PointerSize::k32>(spaces_ref, base_diff64);
2704     }
2705   }
2706 
DeduplicateInternedStrings(ArrayRef<const std::unique_ptr<ImageSpace>> spaces,TimingLogger * logger)2707   void DeduplicateInternedStrings(ArrayRef<const std::unique_ptr<ImageSpace>> spaces,
2708                                   TimingLogger* logger) REQUIRES_SHARED(Locks::mutator_lock_) {
2709     TimingLogger::ScopedTiming timing("DeduplicateInternedStrings", logger);
2710     DCHECK(!spaces.empty());
2711     size_t num_spaces = spaces.size();
2712     const ImageHeader& primary_header = spaces.front()->GetImageHeader();
2713     size_t primary_image_count = primary_header.GetImageSpaceCount();
2714     DCHECK_LE(primary_image_count, num_spaces);
2715     DCHECK_EQ(primary_image_count, primary_header.GetComponentCount());
2716     size_t component_count = primary_image_count;
2717     size_t space_pos = primary_image_count;
2718     while (space_pos != num_spaces) {
2719       const ImageHeader& current_header = spaces[space_pos]->GetImageHeader();
2720       size_t image_space_count = current_header.GetImageSpaceCount();
2721       DCHECK_LE(image_space_count, num_spaces - space_pos);
2722       size_t dependency_component_count = current_header.GetBootImageComponentCount();
2723       DCHECK_LE(dependency_component_count, component_count);
2724       if (dependency_component_count < component_count) {
2725         // There shall be no duplicate strings with the components that this space depends on.
2726         // Find the end of the dependencies, i.e. start of non-dependency images.
2727         size_t start_component_count = primary_image_count;
2728         size_t start_pos = primary_image_count;
2729         while (start_component_count != dependency_component_count) {
2730           const ImageHeader& dependency_header = spaces[start_pos]->GetImageHeader();
2731           DCHECK_LE(dependency_header.GetComponentCount(),
2732                     dependency_component_count - start_component_count);
2733           start_component_count += dependency_header.GetComponentCount();
2734           start_pos += dependency_header.GetImageSpaceCount();
2735         }
2736         // Remove duplicates from all intern tables belonging to the chunk.
2737         ArrayRef<const std::unique_ptr<ImageSpace>> old_spaces =
2738             spaces.SubArray(/*pos=*/ start_pos, space_pos - start_pos);
2739         SafeMap<mirror::String*, mirror::String*> intern_remap;
2740         for (size_t i = 0; i != image_space_count; ++i) {
2741           ImageSpace* new_space = spaces[space_pos + i].get();
2742           Loader::RemoveInternTableDuplicates(old_spaces, new_space, &intern_remap);
2743         }
2744         // Remap string for all spaces belonging to the chunk.
2745         if (!intern_remap.empty()) {
2746           for (size_t i = 0; i != image_space_count; ++i) {
2747             ImageSpace* new_space = spaces[space_pos + i].get();
2748             Loader::RemapInternedStringDuplicates(intern_remap, new_space);
2749           }
2750         }
2751       }
2752       component_count += current_header.GetComponentCount();
2753       space_pos += image_space_count;
2754     }
2755   }
2756 
Load(const std::string & image_location,const std::string & image_filename,const std::string & profile_file,android::base::unique_fd art_fd,TimingLogger * logger,MemMap * image_reservation,std::string * error_msg)2757   std::unique_ptr<ImageSpace> Load(const std::string& image_location,
2758                                    const std::string& image_filename,
2759                                    const std::string& profile_file,
2760                                    android::base::unique_fd art_fd,
2761                                    TimingLogger* logger,
2762                                    /*inout*/MemMap* image_reservation,
2763                                    /*out*/std::string* error_msg)
2764       REQUIRES_SHARED(Locks::mutator_lock_) {
2765     if (art_fd.get() != -1) {
2766       // No need to lock memfd for which we hold the only file descriptor
2767       // (see locking with ScopedFlock for normal files below).
2768       VLOG(startup) << "Using image file " << image_filename.c_str() << " for image location "
2769                     << image_location << " for compiled extension";
2770 
2771       File image_file(art_fd.release(), image_filename, /*check_usage=*/ false);
2772       std::unique_ptr<ImageSpace> result = Loader::Init(&image_file,
2773                                                         image_filename.c_str(),
2774                                                         image_location.c_str(),
2775                                                         profile_file.c_str(),
2776                                                         /*allow_direct_mapping=*/ false,
2777                                                         logger,
2778                                                         image_reservation,
2779                                                         error_msg);
2780       // Note: We're closing the image file descriptor here when we destroy
2781       // the `image_file` as we no longer need it.
2782       return result;
2783     }
2784 
2785     // Note that we must not use the file descriptor associated with
2786     // ScopedFlock::GetFile to Init the image file. We want the file
2787     // descriptor (and the associated exclusive lock) to be released when
2788     // we leave Create.
2789     ScopedFlock image = LockedFile::Open(image_filename.c_str(),
2790                                          /*flags=*/ O_RDONLY,
2791                                          /*block=*/ true,
2792                                          error_msg);
2793 
2794     VLOG(startup) << "Using image file " << image_filename.c_str() << " for image location "
2795                   << image_location;
2796 
2797     // If we are in /system we can assume the image is good. We can also
2798     // assume this if we are using a relocated image (i.e. image checksum
2799     // matches) since this is only different by the offset. We need this to
2800     // make sure that host tests continue to work.
2801     // Since we are the boot image, pass null since we load the oat file from the boot image oat
2802     // file name.
2803     return Loader::Init(image_filename.c_str(),
2804                         image_location.c_str(),
2805                         logger,
2806                         image_reservation,
2807                         error_msg);
2808   }
2809 
OpenOatFile(ImageSpace * space,android::base::unique_fd vdex_fd,android::base::unique_fd oat_fd,ArrayRef<const std::string> dex_filenames,bool validate_oat_file,ArrayRef<const std::unique_ptr<ImageSpace>> dependencies,TimingLogger * logger,MemMap * image_reservation,std::string * error_msg)2810   bool OpenOatFile(ImageSpace* space,
2811                    android::base::unique_fd vdex_fd,
2812                    android::base::unique_fd oat_fd,
2813                    ArrayRef<const std::string> dex_filenames,
2814                    bool validate_oat_file,
2815                    ArrayRef<const std::unique_ptr<ImageSpace>> dependencies,
2816                    TimingLogger* logger,
2817                    /*inout*/MemMap* image_reservation,
2818                    /*out*/std::string* error_msg) {
2819     // VerifyImageAllocations() will be called later in Runtime::Init()
2820     // as some class roots like ArtMethod::java_lang_reflect_ArtMethod_
2821     // and ArtField::java_lang_reflect_ArtField_, which are used from
2822     // Object::SizeOf() which VerifyImageAllocations() calls, are not
2823     // set yet at this point.
2824     DCHECK(image_reservation != nullptr);
2825     std::unique_ptr<OatFile> oat_file;
2826     {
2827       TimingLogger::ScopedTiming timing("OpenOatFile", logger);
2828       std::string oat_filename =
2829           ImageHeader::GetOatLocationFromImageLocation(space->GetImageFilename());
2830       std::string oat_location =
2831           ImageHeader::GetOatLocationFromImageLocation(space->GetImageLocation());
2832 
2833       DCHECK_EQ(vdex_fd.get() != -1, oat_fd.get() != -1);
2834       if (vdex_fd.get() == -1) {
2835         oat_file.reset(OatFile::Open(/*zip_fd=*/ -1,
2836                                      oat_filename,
2837                                      oat_location,
2838                                      executable_,
2839                                      /*low_4gb=*/ false,
2840                                      dex_filenames,
2841                                      image_reservation,
2842                                      error_msg));
2843       } else {
2844         oat_file.reset(OatFile::Open(/*zip_fd=*/ -1,
2845                                      vdex_fd.get(),
2846                                      oat_fd.get(),
2847                                      oat_location,
2848                                      executable_,
2849                                      /*low_4gb=*/ false,
2850                                      dex_filenames,
2851                                      image_reservation,
2852                                      error_msg));
2853         // We no longer need the file descriptors and they will be closed by
2854         // the unique_fd destructor when we leave this function.
2855       }
2856 
2857       if (oat_file == nullptr) {
2858         *error_msg = StringPrintf("Failed to open oat file '%s' referenced from image %s: %s",
2859                                   oat_filename.c_str(),
2860                                   space->GetName(),
2861                                   error_msg->c_str());
2862         return false;
2863       }
2864       const ImageHeader& image_header = space->GetImageHeader();
2865       uint32_t oat_checksum = oat_file->GetOatHeader().GetChecksum();
2866       uint32_t image_oat_checksum = image_header.GetOatChecksum();
2867       if (oat_checksum != image_oat_checksum) {
2868         *error_msg = StringPrintf("Failed to match oat file checksum 0x%x to expected oat checksum"
2869                                   " 0x%x in image %s",
2870                                   oat_checksum,
2871                                   image_oat_checksum,
2872                                   space->GetName());
2873         return false;
2874       }
2875       const char* oat_boot_class_path =
2876           oat_file->GetOatHeader().GetStoreValueByKey(OatHeader::kBootClassPathKey);
2877       oat_boot_class_path = (oat_boot_class_path != nullptr) ? oat_boot_class_path : "";
2878       const char* oat_boot_class_path_checksums =
2879           oat_file->GetOatHeader().GetStoreValueByKey(OatHeader::kBootClassPathChecksumsKey);
2880       oat_boot_class_path_checksums =
2881           (oat_boot_class_path_checksums != nullptr) ? oat_boot_class_path_checksums : "";
2882       size_t component_count = image_header.GetComponentCount();
2883       if (component_count == 0u) {
2884         if (oat_boot_class_path[0] != 0 || oat_boot_class_path_checksums[0] != 0) {
2885           *error_msg = StringPrintf("Unexpected non-empty boot class path %s and/or checksums %s"
2886                                     " in image %s",
2887                                     oat_boot_class_path,
2888                                     oat_boot_class_path_checksums,
2889                                     space->GetName());
2890           return false;
2891         }
2892       } else if (dependencies.empty()) {
2893         std::string expected_boot_class_path = Join(ArrayRef<const std::string>(
2894               boot_class_path_locations_).SubArray(0u, component_count), ':');
2895         if (expected_boot_class_path != oat_boot_class_path) {
2896           *error_msg = StringPrintf("Failed to match oat boot class path %s to expected "
2897                                     "boot class path %s in image %s",
2898                                     oat_boot_class_path,
2899                                     expected_boot_class_path.c_str(),
2900                                     space->GetName());
2901           return false;
2902         }
2903       } else {
2904         std::string local_error_msg;
2905         if (!VerifyBootClassPathChecksums(
2906                  oat_boot_class_path_checksums,
2907                  oat_boot_class_path,
2908                  dependencies,
2909                  ArrayRef<const std::string>(boot_class_path_locations_),
2910                  ArrayRef<const std::string>(boot_class_path_),
2911                  &local_error_msg)) {
2912           *error_msg = StringPrintf("Failed to verify BCP %s with checksums %s in image %s: %s",
2913                                     oat_boot_class_path,
2914                                     oat_boot_class_path_checksums,
2915                                     space->GetName(),
2916                                     local_error_msg.c_str());
2917           return false;
2918         }
2919       }
2920       ptrdiff_t relocation_diff = space->Begin() - image_header.GetImageBegin();
2921       CHECK(image_header.GetOatDataBegin() != nullptr);
2922       uint8_t* oat_data_begin = image_header.GetOatDataBegin() + relocation_diff;
2923       if (oat_file->Begin() != oat_data_begin) {
2924         *error_msg = StringPrintf("Oat file '%s' referenced from image %s has unexpected begin"
2925                                       " %p v. %p",
2926                                   oat_filename.c_str(),
2927                                   space->GetName(),
2928                                   oat_file->Begin(),
2929                                   oat_data_begin);
2930         return false;
2931       }
2932     }
2933     if (validate_oat_file) {
2934       TimingLogger::ScopedTiming timing("ValidateOatFile", logger);
2935       if (!ImageSpace::ValidateOatFile(*oat_file, error_msg)) {
2936         DCHECK(!error_msg->empty());
2937         return false;
2938       }
2939     }
2940     space->oat_file_ = std::move(oat_file);
2941     space->oat_file_non_owned_ = space->oat_file_.get();
2942     return true;
2943   }
2944 
LoadComponents(const BootImageLayout::ImageChunk & chunk,bool validate_oat_file,size_t max_image_space_dependencies,TimingLogger * logger,std::vector<std::unique_ptr<ImageSpace>> * spaces,MemMap * image_reservation,std::string * error_msg)2945   bool LoadComponents(const BootImageLayout::ImageChunk& chunk,
2946                       bool validate_oat_file,
2947                       size_t max_image_space_dependencies,
2948                       TimingLogger* logger,
2949                       /*inout*/std::vector<std::unique_ptr<ImageSpace>>* spaces,
2950                       /*inout*/MemMap* image_reservation,
2951                       /*out*/std::string* error_msg)
2952       REQUIRES_SHARED(Locks::mutator_lock_) {
2953     // Make sure we destroy the spaces we created if we're returning an error.
2954     // Note that this can unmap part of the original `image_reservation`.
2955     class Guard {
2956      public:
2957       explicit Guard(std::vector<std::unique_ptr<ImageSpace>>* spaces_in)
2958           : spaces_(spaces_in), committed_(spaces_->size()) {}
2959       void Commit() {
2960         DCHECK_LT(committed_, spaces_->size());
2961         committed_ = spaces_->size();
2962       }
2963       ~Guard() {
2964         DCHECK_LE(committed_, spaces_->size());
2965         spaces_->resize(committed_);
2966       }
2967      private:
2968       std::vector<std::unique_ptr<ImageSpace>>* const spaces_;
2969       size_t committed_;
2970     };
2971     Guard guard(spaces);
2972 
2973     bool is_extension = (chunk.start_index != 0u);
2974     DCHECK_NE(spaces->empty(), is_extension);
2975     if (max_image_space_dependencies < chunk.boot_image_component_count) {
2976       DCHECK(is_extension);
2977       *error_msg = StringPrintf("Missing dependencies for extension component %s, %zu < %u",
2978                                 boot_class_path_locations_[chunk.start_index].c_str(),
2979                                 max_image_space_dependencies,
2980                                 chunk.boot_image_component_count);
2981       return false;
2982     }
2983     ArrayRef<const std::string> requested_bcp_locations =
2984         ArrayRef<const std::string>(boot_class_path_locations_).SubArray(
2985             chunk.start_index, chunk.image_space_count);
2986     std::vector<std::string> locations =
2987         ExpandMultiImageLocations(requested_bcp_locations, chunk.base_location, is_extension);
2988     std::vector<std::string> filenames =
2989         ExpandMultiImageLocations(requested_bcp_locations, chunk.base_filename, is_extension);
2990     DCHECK_EQ(locations.size(), filenames.size());
2991     for (size_t i = 0u, size = locations.size(); i != size; ++i) {
2992       spaces->push_back(Load(locations[i],
2993                              filenames[i],
2994                              chunk.profile_file,
2995                              std::move(chunk.art_fd),
2996                              logger,
2997                              image_reservation,
2998                              error_msg));
2999       const ImageSpace* space = spaces->back().get();
3000       if (space == nullptr) {
3001         return false;
3002       }
3003       uint32_t expected_component_count = (i == 0u) ? chunk.component_count : 0u;
3004       uint32_t expected_reservation_size = (i == 0u) ? chunk.reservation_size : 0u;
3005       if (!Loader::CheckImageReservationSize(*space, expected_reservation_size, error_msg) ||
3006           !Loader::CheckImageComponentCount(*space, expected_component_count, error_msg)) {
3007         return false;
3008       }
3009       const ImageHeader& header = space->GetImageHeader();
3010       if (i == 0 && (chunk.checksum != header.GetImageChecksum() ||
3011                      chunk.image_space_count != header.GetImageSpaceCount() ||
3012                      chunk.boot_image_component_count != header.GetBootImageComponentCount() ||
3013                      chunk.boot_image_checksum != header.GetBootImageChecksum() ||
3014                      chunk.boot_image_size != header.GetBootImageSize())) {
3015         *error_msg = StringPrintf("Image header modified since previously read from %s; "
3016                                       "checksum: 0x%08x -> 0x%08x,"
3017                                       "image_space_count: %u -> %u"
3018                                       "boot_image_component_count: %u -> %u, "
3019                                       "boot_image_checksum: 0x%08x -> 0x%08x"
3020                                       "boot_image_size: 0x%08x -> 0x%08x",
3021                                   space->GetImageFilename().c_str(),
3022                                   chunk.checksum,
3023                                   chunk.image_space_count,
3024                                   header.GetImageSpaceCount(),
3025                                   header.GetImageChecksum(),
3026                                   chunk.boot_image_component_count,
3027                                   header.GetBootImageComponentCount(),
3028                                   chunk.boot_image_checksum,
3029                                   header.GetBootImageChecksum(),
3030                                   chunk.boot_image_size,
3031                                   header.GetBootImageSize());
3032         return false;
3033       }
3034     }
3035     DCHECK_GE(max_image_space_dependencies, chunk.boot_image_component_count);
3036     ArrayRef<const std::unique_ptr<ImageSpace>> dependencies =
3037         ArrayRef<const std::unique_ptr<ImageSpace>>(*spaces).SubArray(
3038             /*pos=*/ 0u, chunk.boot_image_component_count);
3039     for (size_t i = 0u, size = locations.size(); i != size; ++i) {
3040       ImageSpace* space = (*spaces)[spaces->size() - chunk.image_space_count + i].get();
3041       size_t bcp_chunk_size = (chunk.image_space_count == 1u) ? chunk.component_count : 1u;
3042       if (!OpenOatFile(space,
3043                        std::move(chunk.vdex_fd),
3044                        std::move(chunk.oat_fd),
3045                        boot_class_path_.SubArray(/*pos=*/ chunk.start_index + i, bcp_chunk_size),
3046                        validate_oat_file,
3047                        dependencies,
3048                        logger,
3049                        image_reservation,
3050                        error_msg)) {
3051         return false;
3052       }
3053     }
3054 
3055     guard.Commit();
3056     return true;
3057   }
3058 
ReserveBootImageMemory(uint8_t * addr,uint32_t reservation_size,std::string * error_msg)3059   MemMap ReserveBootImageMemory(uint8_t* addr,
3060                                 uint32_t reservation_size,
3061                                 /*out*/std::string* error_msg) {
3062     DCHECK_ALIGNED(reservation_size, kPageSize);
3063     DCHECK_ALIGNED(addr, kPageSize);
3064     return MemMap::MapAnonymous("Boot image reservation",
3065                                 addr,
3066                                 reservation_size,
3067                                 PROT_NONE,
3068                                 /*low_4gb=*/ true,
3069                                 /*reuse=*/ false,
3070                                 /*reservation=*/ nullptr,
3071                                 error_msg);
3072   }
3073 
RemapExtraReservation(size_t extra_reservation_size,MemMap * image_reservation,MemMap * extra_reservation,std::string * error_msg)3074   bool RemapExtraReservation(size_t extra_reservation_size,
3075                              /*inout*/MemMap* image_reservation,
3076                              /*out*/MemMap* extra_reservation,
3077                              /*out*/std::string* error_msg) {
3078     DCHECK_ALIGNED(extra_reservation_size, kPageSize);
3079     DCHECK(!extra_reservation->IsValid());
3080     size_t expected_size = image_reservation->IsValid() ? image_reservation->Size() : 0u;
3081     if (extra_reservation_size != expected_size) {
3082       *error_msg = StringPrintf("Image reservation mismatch after loading boot image: %zu != %zu",
3083                                 extra_reservation_size,
3084                                 expected_size);
3085       return false;
3086     }
3087     if (extra_reservation_size != 0u) {
3088       DCHECK(image_reservation->IsValid());
3089       DCHECK_EQ(extra_reservation_size, image_reservation->Size());
3090       *extra_reservation = image_reservation->RemapAtEnd(image_reservation->Begin(),
3091                                                          "Boot image extra reservation",
3092                                                          PROT_NONE,
3093                                                          error_msg);
3094       if (!extra_reservation->IsValid()) {
3095         return false;
3096       }
3097     }
3098     DCHECK(!image_reservation->IsValid());
3099     return true;
3100   }
3101 
3102   const ArrayRef<const std::string> boot_class_path_;
3103   const ArrayRef<const std::string> boot_class_path_locations_;
3104   const std::string image_location_;
3105   const InstructionSet image_isa_;
3106   const bool relocate_;
3107   const bool executable_;
3108   bool has_system_;
3109 };
3110 
LoadFromSystem(size_t extra_reservation_size,std::vector<std::unique_ptr<ImageSpace>> * boot_image_spaces,MemMap * extra_reservation,std::string * error_msg)3111 bool ImageSpace::BootImageLoader::LoadFromSystem(
3112     size_t extra_reservation_size,
3113     /*out*/std::vector<std::unique_ptr<ImageSpace>>* boot_image_spaces,
3114     /*out*/MemMap* extra_reservation,
3115     /*out*/std::string* error_msg) {
3116   TimingLogger logger(__PRETTY_FUNCTION__, /*precise=*/ true, VLOG_IS_ON(image));
3117 
3118   BootImageLayout layout(image_location_, boot_class_path_, boot_class_path_locations_);
3119   if (!layout.LoadFromSystem(image_isa_, error_msg)) {
3120     return false;
3121   }
3122 
3123   if (!LoadImage(layout,
3124                  /*validate_oat_file=*/ false,
3125                  extra_reservation_size,
3126                  &logger,
3127                  boot_image_spaces,
3128                  extra_reservation,
3129                  error_msg)) {
3130     return false;
3131   }
3132 
3133   if (VLOG_IS_ON(image)) {
3134     LOG(INFO) << "ImageSpace::BootImageLoader::LoadFromSystem exiting "
3135         << *boot_image_spaces->front();
3136     logger.Dump(LOG_STREAM(INFO));
3137   }
3138   return true;
3139 }
3140 
IsBootClassPathOnDisk(InstructionSet image_isa)3141 bool ImageSpace::IsBootClassPathOnDisk(InstructionSet image_isa) {
3142   Runtime* runtime = Runtime::Current();
3143   BootImageLayout layout(runtime->GetImageLocation(),
3144                          ArrayRef<const std::string>(runtime->GetBootClassPath()),
3145                          ArrayRef<const std::string>(runtime->GetBootClassPathLocations()));
3146   const std::string image_location = layout.GetPrimaryImageLocation();
3147   std::unique_ptr<ImageHeader> image_header;
3148   std::string error_msg;
3149 
3150   std::string system_filename;
3151   bool has_system = false;
3152 
3153   if (FindImageFilename(image_location.c_str(),
3154                         image_isa,
3155                         &system_filename,
3156                         &has_system)) {
3157     DCHECK(has_system);
3158     image_header = ReadSpecificImageHeader(system_filename.c_str(), &error_msg);
3159   }
3160 
3161   return image_header != nullptr;
3162 }
3163 
LoadBootImage(const std::vector<std::string> & boot_class_path,const std::vector<std::string> & boot_class_path_locations,const std::string & image_location,const InstructionSet image_isa,bool relocate,bool executable,size_t extra_reservation_size,std::vector<std::unique_ptr<ImageSpace>> * boot_image_spaces,MemMap * extra_reservation)3164 bool ImageSpace::LoadBootImage(
3165     const std::vector<std::string>& boot_class_path,
3166     const std::vector<std::string>& boot_class_path_locations,
3167     const std::string& image_location,
3168     const InstructionSet image_isa,
3169     bool relocate,
3170     bool executable,
3171     size_t extra_reservation_size,
3172     /*out*/std::vector<std::unique_ptr<ImageSpace>>* boot_image_spaces,
3173     /*out*/MemMap* extra_reservation) {
3174   ScopedTrace trace(__FUNCTION__);
3175 
3176   DCHECK(boot_image_spaces != nullptr);
3177   DCHECK(boot_image_spaces->empty());
3178   DCHECK_ALIGNED(extra_reservation_size, kPageSize);
3179   DCHECK(extra_reservation != nullptr);
3180   DCHECK_NE(image_isa, InstructionSet::kNone);
3181 
3182   if (image_location.empty()) {
3183     return false;
3184   }
3185 
3186   BootImageLoader loader(boot_class_path,
3187                          boot_class_path_locations,
3188                          image_location,
3189                          image_isa,
3190                          relocate,
3191                          executable);
3192   loader.FindImageFiles();
3193 
3194   // Collect all the errors.
3195   std::vector<std::string> error_msgs;
3196 
3197   std::string error_msg;
3198   if (loader.HasSystem()) {
3199     if (loader.LoadFromSystem(extra_reservation_size,
3200                               boot_image_spaces,
3201                               extra_reservation,
3202                               &error_msg)) {
3203       return true;
3204     }
3205     error_msgs.push_back(error_msg);
3206   }
3207 
3208   std::ostringstream oss;
3209   bool first = true;
3210   for (const auto& msg : error_msgs) {
3211     if (first) {
3212       first = false;
3213     } else {
3214       oss << "\n    ";
3215     }
3216     oss << msg;
3217   }
3218 
3219   LOG(ERROR) << "Could not create image space with image file '" << image_location << "'. "
3220       << "Attempting to fall back to imageless running. Error was: " << oss.str();
3221 
3222   return false;
3223 }
3224 
~ImageSpace()3225 ImageSpace::~ImageSpace() {
3226   // Everything done by member destructors. Classes forward-declared in header are now defined.
3227 }
3228 
CreateFromAppImage(const char * image,const OatFile * oat_file,std::string * error_msg)3229 std::unique_ptr<ImageSpace> ImageSpace::CreateFromAppImage(const char* image,
3230                                                            const OatFile* oat_file,
3231                                                            std::string* error_msg) {
3232   // Note: The oat file has already been validated.
3233   const std::vector<ImageSpace*>& boot_image_spaces =
3234       Runtime::Current()->GetHeap()->GetBootImageSpaces();
3235   return CreateFromAppImage(image,
3236                             oat_file,
3237                             ArrayRef<ImageSpace* const>(boot_image_spaces),
3238                             error_msg);
3239 }
3240 
CreateFromAppImage(const char * image,const OatFile * oat_file,ArrayRef<ImageSpace * const> boot_image_spaces,std::string * error_msg)3241 std::unique_ptr<ImageSpace> ImageSpace::CreateFromAppImage(
3242     const char* image,
3243     const OatFile* oat_file,
3244     ArrayRef<ImageSpace* const> boot_image_spaces,
3245     std::string* error_msg) {
3246   return Loader::InitAppImage(image,
3247                               image,
3248                               oat_file,
3249                               boot_image_spaces,
3250                               error_msg);
3251 }
3252 
GetOatFile() const3253 const OatFile* ImageSpace::GetOatFile() const {
3254   return oat_file_non_owned_;
3255 }
3256 
ReleaseOatFile()3257 std::unique_ptr<const OatFile> ImageSpace::ReleaseOatFile() {
3258   CHECK(oat_file_ != nullptr);
3259   return std::move(oat_file_);
3260 }
3261 
Dump(std::ostream & os) const3262 void ImageSpace::Dump(std::ostream& os) const {
3263   os << GetType()
3264       << " begin=" << reinterpret_cast<void*>(Begin())
3265       << ",end=" << reinterpret_cast<void*>(End())
3266       << ",size=" << PrettySize(Size())
3267       << ",name=\"" << GetName() << "\"]";
3268 }
3269 
ValidateOatFile(const OatFile & oat_file,std::string * error_msg)3270 bool ImageSpace::ValidateOatFile(const OatFile& oat_file, std::string* error_msg) {
3271   const ArtDexFileLoader dex_file_loader;
3272   for (const OatDexFile* oat_dex_file : oat_file.GetOatDexFiles()) {
3273     const std::string& dex_file_location = oat_dex_file->GetDexFileLocation();
3274 
3275     // Skip multidex locations - These will be checked when we visit their
3276     // corresponding primary non-multidex location.
3277     if (DexFileLoader::IsMultiDexLocation(dex_file_location.c_str())) {
3278       continue;
3279     }
3280 
3281     std::vector<uint32_t> checksums;
3282     std::vector<std::string> dex_locations_ignored;
3283     if (!dex_file_loader.GetMultiDexChecksums(
3284         dex_file_location.c_str(), &checksums, &dex_locations_ignored, error_msg)) {
3285       *error_msg = StringPrintf("ValidateOatFile failed to get checksums of dex file '%s' "
3286                                 "referenced by oat file %s: %s",
3287                                 dex_file_location.c_str(),
3288                                 oat_file.GetLocation().c_str(),
3289                                 error_msg->c_str());
3290       return false;
3291     }
3292     CHECK(!checksums.empty());
3293     if (checksums[0] != oat_dex_file->GetDexFileLocationChecksum()) {
3294       *error_msg = StringPrintf("ValidateOatFile found checksum mismatch between oat file "
3295                                 "'%s' and dex file '%s' (0x%x != 0x%x)",
3296                                 oat_file.GetLocation().c_str(),
3297                                 dex_file_location.c_str(),
3298                                 oat_dex_file->GetDexFileLocationChecksum(),
3299                                 checksums[0]);
3300       return false;
3301     }
3302 
3303     // Verify checksums for any related multidex entries.
3304     for (size_t i = 1; i < checksums.size(); i++) {
3305       std::string multi_dex_location = DexFileLoader::GetMultiDexLocation(
3306           i,
3307           dex_file_location.c_str());
3308       const OatDexFile* multi_dex = oat_file.GetOatDexFile(multi_dex_location.c_str(),
3309                                                            nullptr,
3310                                                            error_msg);
3311       if (multi_dex == nullptr) {
3312         *error_msg = StringPrintf("ValidateOatFile oat file '%s' is missing entry '%s'",
3313                                   oat_file.GetLocation().c_str(),
3314                                   multi_dex_location.c_str());
3315         return false;
3316       }
3317 
3318       if (checksums[i] != multi_dex->GetDexFileLocationChecksum()) {
3319         *error_msg = StringPrintf("ValidateOatFile found checksum mismatch between oat file "
3320                                   "'%s' and dex file '%s' (0x%x != 0x%x)",
3321                                   oat_file.GetLocation().c_str(),
3322                                   multi_dex_location.c_str(),
3323                                   multi_dex->GetDexFileLocationChecksum(),
3324                                   checksums[i]);
3325         return false;
3326       }
3327     }
3328   }
3329   return true;
3330 }
3331 
GetBootClassPathChecksums(ArrayRef<ImageSpace * const> image_spaces,ArrayRef<const DexFile * const> boot_class_path)3332 std::string ImageSpace::GetBootClassPathChecksums(
3333     ArrayRef<ImageSpace* const> image_spaces,
3334     ArrayRef<const DexFile* const> boot_class_path) {
3335   DCHECK(!boot_class_path.empty());
3336   size_t bcp_pos = 0u;
3337   std::string boot_image_checksum;
3338 
3339   for (size_t image_pos = 0u, size = image_spaces.size(); image_pos != size; ) {
3340     const ImageSpace* main_space = image_spaces[image_pos];
3341     // Caller must make sure that the image spaces correspond to the head of the BCP.
3342     DCHECK_NE(main_space->oat_file_non_owned_->GetOatDexFiles().size(), 0u);
3343     DCHECK_EQ(main_space->oat_file_non_owned_->GetOatDexFiles()[0]->GetDexFileLocation(),
3344               boot_class_path[bcp_pos]->GetLocation());
3345     const ImageHeader& current_header = main_space->GetImageHeader();
3346     uint32_t image_space_count = current_header.GetImageSpaceCount();
3347     DCHECK_NE(image_space_count, 0u);
3348     DCHECK_LE(image_space_count, image_spaces.size() - image_pos);
3349     if (image_pos != 0u) {
3350       boot_image_checksum += ':';
3351     }
3352     uint32_t component_count = current_header.GetComponentCount();
3353     AppendImageChecksum(component_count, current_header.GetImageChecksum(), &boot_image_checksum);
3354     for (size_t space_index = 0; space_index != image_space_count; ++space_index) {
3355       const ImageSpace* space = image_spaces[image_pos + space_index];
3356       const OatFile* oat_file = space->oat_file_non_owned_;
3357       size_t num_dex_files = oat_file->GetOatDexFiles().size();
3358       if (kIsDebugBuild) {
3359         CHECK_NE(num_dex_files, 0u);
3360         CHECK_LE(oat_file->GetOatDexFiles().size(), boot_class_path.size() - bcp_pos);
3361         for (size_t i = 0; i != num_dex_files; ++i) {
3362           CHECK_EQ(oat_file->GetOatDexFiles()[i]->GetDexFileLocation(),
3363                    boot_class_path[bcp_pos + i]->GetLocation());
3364         }
3365       }
3366       bcp_pos += num_dex_files;
3367     }
3368     image_pos += image_space_count;
3369   }
3370 
3371   ArrayRef<const DexFile* const> boot_class_path_tail =
3372       ArrayRef<const DexFile* const>(boot_class_path).SubArray(bcp_pos);
3373   DCHECK(boot_class_path_tail.empty() ||
3374          !DexFileLoader::IsMultiDexLocation(boot_class_path_tail.front()->GetLocation().c_str()));
3375   for (const DexFile* dex_file : boot_class_path_tail) {
3376     if (!DexFileLoader::IsMultiDexLocation(dex_file->GetLocation().c_str())) {
3377       if (!boot_image_checksum.empty()) {
3378         boot_image_checksum += ':';
3379       }
3380       boot_image_checksum += kDexFileChecksumPrefix;
3381     }
3382     StringAppendF(&boot_image_checksum, "/%08x", dex_file->GetLocationChecksum());
3383   }
3384   return boot_image_checksum;
3385 }
3386 
GetNumberOfComponents(ArrayRef<ImageSpace * const> image_spaces)3387 size_t ImageSpace::GetNumberOfComponents(ArrayRef<ImageSpace* const> image_spaces) {
3388   size_t n = 0;
3389   for (auto&& is : image_spaces) {
3390     n += is->GetComponentCount();
3391   }
3392   return n;
3393 }
3394 
CheckAndCountBCPComponents(std::string_view oat_boot_class_path,ArrayRef<const std::string> boot_class_path,std::string * error_msg)3395 static size_t CheckAndCountBCPComponents(std::string_view oat_boot_class_path,
3396                                          ArrayRef<const std::string> boot_class_path,
3397                                          /*out*/std::string* error_msg) {
3398   // Check that the oat BCP is a prefix of current BCP locations and count components.
3399   size_t component_count = 0u;
3400   std::string_view remaining_bcp(oat_boot_class_path);
3401   bool bcp_ok = false;
3402   for (const std::string& location : boot_class_path) {
3403     if (!StartsWith(remaining_bcp, location)) {
3404       break;
3405     }
3406     remaining_bcp.remove_prefix(location.size());
3407     ++component_count;
3408     if (remaining_bcp.empty()) {
3409       bcp_ok = true;
3410       break;
3411     }
3412     if (!StartsWith(remaining_bcp, ":")) {
3413       break;
3414     }
3415     remaining_bcp.remove_prefix(1u);
3416   }
3417   if (!bcp_ok) {
3418     *error_msg = StringPrintf("Oat boot class path (%s) is not a prefix of"
3419                               " runtime boot class path (%s)",
3420                               std::string(oat_boot_class_path).c_str(),
3421                               Join(boot_class_path, ':').c_str());
3422     return static_cast<size_t>(-1);
3423   }
3424   return component_count;
3425 }
3426 
VerifyBootClassPathChecksums(std::string_view oat_checksums,std::string_view oat_boot_class_path,const std::string & image_location,ArrayRef<const std::string> boot_class_path_locations,ArrayRef<const std::string> boot_class_path,InstructionSet image_isa,std::string * error_msg)3427 bool ImageSpace::VerifyBootClassPathChecksums(std::string_view oat_checksums,
3428                                               std::string_view oat_boot_class_path,
3429                                               const std::string& image_location,
3430                                               ArrayRef<const std::string> boot_class_path_locations,
3431                                               ArrayRef<const std::string> boot_class_path,
3432                                               InstructionSet image_isa,
3433                                               /*out*/std::string* error_msg) {
3434   if (oat_checksums.empty() || oat_boot_class_path.empty()) {
3435     *error_msg = oat_checksums.empty() ? "Empty checksums." : "Empty boot class path.";
3436     return false;
3437   }
3438 
3439   DCHECK_EQ(boot_class_path_locations.size(), boot_class_path.size());
3440   size_t bcp_size =
3441       CheckAndCountBCPComponents(oat_boot_class_path, boot_class_path_locations, error_msg);
3442   if (bcp_size == static_cast<size_t>(-1)) {
3443     DCHECK(!error_msg->empty());
3444     return false;
3445   }
3446 
3447   size_t bcp_pos = 0u;
3448   if (StartsWith(oat_checksums, "i")) {
3449     // Use only the matching part of the BCP for validation.
3450     BootImageLayout layout(image_location,
3451                            boot_class_path.SubArray(/*pos=*/ 0u, bcp_size),
3452                            boot_class_path_locations.SubArray(/*pos=*/ 0u, bcp_size));
3453     std::string primary_image_location = layout.GetPrimaryImageLocation();
3454     std::string system_filename;
3455     bool has_system = false;
3456     if (!FindImageFilename(primary_image_location.c_str(),
3457                            image_isa,
3458                            &system_filename,
3459                            &has_system)) {
3460       *error_msg = StringPrintf("Unable to find image file for %s and %s",
3461                                 image_location.c_str(),
3462                                 GetInstructionSetString(image_isa));
3463       return false;
3464     }
3465 
3466     DCHECK(has_system);
3467     if (!layout.ValidateFromSystem(image_isa, &oat_checksums, error_msg)) {
3468       return false;
3469     }
3470     bcp_pos = layout.GetNextBcpIndex();
3471   }
3472 
3473   for ( ; bcp_pos != bcp_size; ++bcp_pos) {
3474     static_assert(ImageSpace::kDexFileChecksumPrefix == 'd', "Format prefix check.");
3475     if (!StartsWith(oat_checksums, "d")) {
3476       *error_msg = StringPrintf("Missing dex checksums, expected %s to start with 'd'",
3477                                 std::string(oat_checksums).c_str());
3478       return false;
3479     }
3480     oat_checksums.remove_prefix(1u);
3481 
3482     const std::string& bcp_filename = boot_class_path[bcp_pos];
3483     std::vector<uint32_t> checksums;
3484     std::vector<std::string> dex_locations;
3485     const ArtDexFileLoader dex_file_loader;
3486     if (!dex_file_loader.GetMultiDexChecksums(bcp_filename.c_str(),
3487                                               &checksums,
3488                                               &dex_locations,
3489                                               error_msg)) {
3490       return false;
3491     }
3492     DCHECK(!checksums.empty());
3493     for (uint32_t checksum : checksums) {
3494       std::string dex_file_checksum = StringPrintf("/%08x", checksum);
3495       if (!StartsWith(oat_checksums, dex_file_checksum)) {
3496         *error_msg = StringPrintf("Dex checksum mismatch, expected %s to start with %s",
3497                                   std::string(oat_checksums).c_str(),
3498                                   dex_file_checksum.c_str());
3499         return false;
3500       }
3501       oat_checksums.remove_prefix(dex_file_checksum.size());
3502     }
3503     if (bcp_pos + 1u != bcp_size) {
3504       if (!StartsWith(oat_checksums, ":")) {
3505         *error_msg = StringPrintf("Missing ':' separator at start of %s",
3506                                   std::string(oat_checksums).c_str());
3507         return false;
3508       }
3509       oat_checksums.remove_prefix(1u);
3510     }
3511   }
3512   if (!oat_checksums.empty()) {
3513     *error_msg = StringPrintf("Checksum too long, unexpected tail %s",
3514                               std::string(oat_checksums).c_str());
3515     return false;
3516   }
3517   return true;
3518 }
3519 
VerifyBootClassPathChecksums(std::string_view oat_checksums,std::string_view oat_boot_class_path,ArrayRef<const std::unique_ptr<ImageSpace>> image_spaces,ArrayRef<const std::string> boot_class_path_locations,ArrayRef<const std::string> boot_class_path,std::string * error_msg)3520 bool ImageSpace::VerifyBootClassPathChecksums(
3521     std::string_view oat_checksums,
3522     std::string_view oat_boot_class_path,
3523     ArrayRef<const std::unique_ptr<ImageSpace>> image_spaces,
3524     ArrayRef<const std::string> boot_class_path_locations,
3525     ArrayRef<const std::string> boot_class_path,
3526     /*out*/std::string* error_msg) {
3527   DCHECK_EQ(boot_class_path.size(), boot_class_path_locations.size());
3528   DCHECK_GE(boot_class_path_locations.size(), image_spaces.size());
3529   if (oat_checksums.empty() || oat_boot_class_path.empty()) {
3530     *error_msg = oat_checksums.empty() ? "Empty checksums." : "Empty boot class path.";
3531     return false;
3532   }
3533 
3534   size_t oat_bcp_size =
3535       CheckAndCountBCPComponents(oat_boot_class_path, boot_class_path_locations, error_msg);
3536   if (oat_bcp_size == static_cast<size_t>(-1)) {
3537     DCHECK(!error_msg->empty());
3538     return false;
3539   }
3540   const size_t num_image_spaces = image_spaces.size();
3541   if (num_image_spaces != oat_bcp_size) {
3542     *error_msg = StringPrintf("Image header records more dependencies (%zu) than BCP (%zu)",
3543                               num_image_spaces,
3544                               oat_bcp_size);
3545     return false;
3546   }
3547 
3548   // Verify image checksums.
3549   size_t bcp_pos = 0u;
3550   size_t image_pos = 0u;
3551   while (image_pos != num_image_spaces && StartsWith(oat_checksums, "i")) {
3552     // Verify the current image checksum.
3553     const ImageHeader& current_header = image_spaces[image_pos]->GetImageHeader();
3554     uint32_t image_space_count = current_header.GetImageSpaceCount();
3555     DCHECK_NE(image_space_count, 0u);
3556     DCHECK_LE(image_space_count, image_spaces.size() - image_pos);
3557     uint32_t component_count = current_header.GetComponentCount();
3558     uint32_t checksum = current_header.GetImageChecksum();
3559     if (!CheckAndRemoveImageChecksum(component_count, checksum, &oat_checksums, error_msg)) {
3560       DCHECK(!error_msg->empty());
3561       return false;
3562     }
3563 
3564     if (kIsDebugBuild) {
3565       for (size_t space_index = 0; space_index != image_space_count; ++space_index) {
3566         const OatFile* oat_file = image_spaces[image_pos + space_index]->oat_file_non_owned_;
3567         size_t num_dex_files = oat_file->GetOatDexFiles().size();
3568         CHECK_NE(num_dex_files, 0u);
3569         const std::string main_location = oat_file->GetOatDexFiles()[0]->GetDexFileLocation();
3570         CHECK_EQ(main_location, boot_class_path_locations[bcp_pos + space_index]);
3571         CHECK(!DexFileLoader::IsMultiDexLocation(main_location.c_str()));
3572         size_t num_base_locations = 1u;
3573         for (size_t i = 1u; i != num_dex_files; ++i) {
3574           if (DexFileLoader::IsMultiDexLocation(
3575                   oat_file->GetOatDexFiles()[i]->GetDexFileLocation().c_str())) {
3576             CHECK_EQ(image_space_count, 1u);  // We can find base locations only for --single-image.
3577             ++num_base_locations;
3578           }
3579         }
3580         if (image_space_count == 1u) {
3581           CHECK_EQ(num_base_locations, component_count);
3582         }
3583       }
3584     }
3585 
3586     image_pos += image_space_count;
3587     bcp_pos += component_count;
3588 
3589     if (!StartsWith(oat_checksums, ":")) {
3590       // Check that we've reached the end of checksums and BCP.
3591       if (!oat_checksums.empty()) {
3592          *error_msg = StringPrintf("Expected ':' separator or end of checksums, remaining %s.",
3593                                    std::string(oat_checksums).c_str());
3594          return false;
3595       }
3596       if (image_pos != oat_bcp_size) {
3597         *error_msg = StringPrintf("Component count mismatch between checksums (%zu) and BCP (%zu)",
3598                                   image_pos,
3599                                   oat_bcp_size);
3600         return false;
3601       }
3602       return true;
3603     }
3604     oat_checksums.remove_prefix(1u);
3605   }
3606 
3607   // We do not allow dependencies of extensions on dex files. That would require
3608   // interleaving the loading of the images with opening the other BCP dex files.
3609   return false;
3610 }
3611 
ExpandMultiImageLocations(ArrayRef<const std::string> dex_locations,const std::string & image_location,bool boot_image_extension)3612 std::vector<std::string> ImageSpace::ExpandMultiImageLocations(
3613     ArrayRef<const std::string> dex_locations,
3614     const std::string& image_location,
3615     bool boot_image_extension) {
3616   DCHECK(!dex_locations.empty());
3617 
3618   // Find the path.
3619   size_t last_slash = image_location.rfind('/');
3620   CHECK_NE(last_slash, std::string::npos);
3621 
3622   // We also need to honor path components that were encoded through '@'. Otherwise the loading
3623   // code won't be able to find the images.
3624   if (image_location.find('@', last_slash) != std::string::npos) {
3625     last_slash = image_location.rfind('@');
3626   }
3627 
3628   // Find the dot separating the primary image name from the extension.
3629   size_t last_dot = image_location.rfind('.');
3630   // Extract the extension and base (the path and primary image name).
3631   std::string extension;
3632   std::string base = image_location;
3633   if (last_dot != std::string::npos && last_dot > last_slash) {
3634     extension = image_location.substr(last_dot);  // Including the dot.
3635     base.resize(last_dot);
3636   }
3637   // For non-empty primary image name, add '-' to the `base`.
3638   if (last_slash + 1u != base.size()) {
3639     base += '-';
3640   }
3641 
3642   std::vector<std::string> locations;
3643   locations.reserve(dex_locations.size());
3644   size_t start_index = 0u;
3645   if (!boot_image_extension) {
3646     start_index = 1u;
3647     locations.push_back(image_location);
3648   }
3649 
3650   // Now create the other names. Use a counted loop to skip the first one if needed.
3651   for (size_t i = start_index; i < dex_locations.size(); ++i) {
3652     // Replace path with `base` (i.e. image path and prefix) and replace the original
3653     // extension (if any) with `extension`.
3654     std::string name = dex_locations[i];
3655     size_t last_dex_slash = name.rfind('/');
3656     if (last_dex_slash != std::string::npos) {
3657       name = name.substr(last_dex_slash + 1);
3658     }
3659     size_t last_dex_dot = name.rfind('.');
3660     if (last_dex_dot != std::string::npos) {
3661       name.resize(last_dex_dot);
3662     }
3663     locations.push_back(base + name + extension);
3664   }
3665   return locations;
3666 }
3667 
DumpSections(std::ostream & os) const3668 void ImageSpace::DumpSections(std::ostream& os) const {
3669   const uint8_t* base = Begin();
3670   const ImageHeader& header = GetImageHeader();
3671   for (size_t i = 0; i < ImageHeader::kSectionCount; ++i) {
3672     auto section_type = static_cast<ImageHeader::ImageSections>(i);
3673     const ImageSection& section = header.GetImageSection(section_type);
3674     os << section_type << " " << reinterpret_cast<const void*>(base + section.Offset())
3675        << "-" << reinterpret_cast<const void*>(base + section.End()) << "\n";
3676   }
3677 }
3678 
ReleaseMetadata()3679 void ImageSpace::ReleaseMetadata() {
3680   const ImageSection& metadata = GetImageHeader().GetMetadataSection();
3681   VLOG(image) << "Releasing " << metadata.Size() << " image metadata bytes";
3682   // Avoid using ZeroAndReleasePages since the zero fill might not be word atomic.
3683   uint8_t* const page_begin = AlignUp(Begin() + metadata.Offset(), kPageSize);
3684   uint8_t* const page_end = AlignDown(Begin() + metadata.End(), kPageSize);
3685   if (page_begin < page_end) {
3686     CHECK_NE(madvise(page_begin, page_end - page_begin, MADV_DONTNEED), -1) << "madvise failed";
3687   }
3688 }
3689 
3690 }  // namespace space
3691 }  // namespace gc
3692 }  // namespace art
3693