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