• 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 #ifndef ART_RUNTIME_GC_SPACE_IMAGE_SPACE_H_
18 #define ART_RUNTIME_GC_SPACE_IMAGE_SPACE_H_
19 
20 #include "android-base/unique_fd.h"
21 #include "base/array_ref.h"
22 #include "gc/accounting/space_bitmap.h"
23 #include "image.h"
24 #include "runtime.h"
25 #include "space.h"
26 
27 namespace art {
28 
29 class DexFile;
30 enum class InstructionSet;
31 class OatFile;
32 class OatHeader;
33 
34 namespace gc {
35 namespace space {
36 
37 // An image space is a space backed with a memory mapped image.
38 class ImageSpace : public MemMapSpace {
39  public:
GetType()40   SpaceType GetType() const override {
41     return kSpaceTypeImageSpace;
42   }
43 
44   // The separator for boot image location components.
45   static constexpr char kComponentSeparator = ':';
46   // The separator for profile filename.
47   static constexpr char kProfileSeparator = '!';
48 
49   // Load boot image spaces for specified boot class path, image location, instruction set, etc.
50   //
51   // On successful return, the loaded spaces are added to boot_image_spaces (which must be
52   // empty on entry) and `extra_reservation` is set to the requested reservation located
53   // after the end of the last loaded oat file.
54   //
55   // IMAGE LOCATION
56   //
57   // The "image location" is a colon-separated list that specifies one or more
58   // components by name and may also specify search paths for extensions
59   // corresponding to the remaining boot class path (BCP) extensions.
60   //
61   // The primary boot image can be specified as one of
62   //     <path>/<base-name>
63   //     <base-name>
64   // and the path of the first BCP component is used for the second form.
65   // The specification may be followed by one or more profile specifications, where each profile
66   // specification is one of
67   //     !<profile-path>/<profile-name>
68   //     !<profile-name>
69   // and the profiles will be used to compile the primary boot image when loading the boot image if
70   // the on-disk version is not acceptable (either not present or fails validation, presumably
71   // because it's out of date). The primary boot image is compiled with no dependency.
72   //
73   // Named extension specifications must correspond to an expansion of the
74   // <base-name> with a BCP component (for example boot.art with the BCP
75   // component name <jar-path>/framework.jar expands to boot-framework.art).
76   // They can be similarly specified as one of
77   //     <ext-path>/<ext-name>
78   //     <ext-name>
79   // and must be listed in the order of their corresponding BCP components.
80   // Similarly, the specification may be followed by one or more profile specifications, where each
81   // profile specification is one of
82   //     !<profile-path>/<profile-name>
83   //     !<profile-name>
84   // and the profiles will be used to compile the extension when loading the boot image if the
85   // on-disk version is not acceptable (either not present or fails validation, presumably because
86   // it's out of date). The primary boot image (i.e., the first element in "image location") is the
87   // dependency that each extension is compiled against.
88   //
89   // Search paths for remaining extensions can be specified after named
90   // components as one of
91   //     <search-path>/*
92   //     *
93   // where the second form means that the path of a particular BCP component
94   // should be used to search for that component's boot image extension.
95   //
96   // The actual filename shall be derived from the specified locations using
97   // `GetSystemImageFilename()`.
98   //
99   // Example image locations:
100   //     /system/framework/boot.art
101   //         - only primary boot image with full path.
102   //     /data/misc/apexdata/com.android.art/dalvik-cache/boot.art!/apex/com.android.art/etc/boot-image.prof!/system/etc/boot-image.prof
103   //         - only primary boot image with full path; if the primary boot image is not found or
104   //           broken, compile it in memory using two specified profile files at the exact paths.
105   //     boot.art:boot-framework.art
106   //         - primary and one extension, use BCP component paths.
107   //     /apex/com.android.art/boot.art:*
108   //         - primary with exact location, search for the rest based on BCP
109   //           component paths.
110   //     boot.art:/system/framework/*
111   //         - primary based on BCP component path, search for extensions in
112   //           /system/framework.
113   //     /apex/com.android.art/boot.art:/system/framework/*:*
114   //         - primary with exact location, search for extensions first in
115   //           /system/framework, then in the corresponding BCP component path.
116   //     /apex/com.android.art/boot.art:*:/system/framework/*
117   //         - primary with exact location, search for extensions first in the
118   //           corresponding BCP component path and then in /system/framework.
119   //     /apex/com.android.art/boot.art:*:boot-framework.jar
120   //         - invalid, named components may not follow search paths.
121   //     boot.art:boot-framework.jar!/system/framework/framework.prof
122   //         - primary and one extension, use BCP component paths; if extension
123   //           is not found or broken compile it in memory using the specified
124   //           profile file from the exact path.
125   //     boot.art:boot-framework.jar:conscrypt.jar!conscrypt.prof
126   //         - primary and two extensions, use BCP component paths; only the
127   //           second extension has a profile file and can be compiled in memory
128   //           when it is not found or broken, using the specified profile file
129   //           in the BCP component path and it is compiled against the primary
130   //           and first extension and only if the first extension is OK.
131   //     boot.art:boot-framework.jar!framework.prof:conscrypt.jar!conscrypt.prof
132   //         - primary and two extensions, use BCP component paths; if any
133   //           extension is not found or broken compile it in memory using
134   //           the specified profile file in the BCP component path, each
135   //           extension is compiled only against the primary boot image.
136   static bool LoadBootImage(
137       const std::vector<std::string>& boot_class_path,
138       const std::vector<std::string>& boot_class_path_locations,
139       const std::vector<int>& boot_class_path_fds,
140       const std::vector<int>& boot_class_path_image_fds,
141       const std::vector<int>& boot_class_path_vdex_fds,
142       const std::vector<int>& boot_class_path_oat_fds,
143       const std::vector<std::string>& image_locations,
144       const InstructionSet image_isa,
145       bool relocate,
146       bool executable,
147       size_t extra_reservation_size,
148       bool allow_in_memory_compilation,
149       /*out*/std::vector<std::unique_ptr<ImageSpace>>* boot_image_spaces,
150       /*out*/MemMap* extra_reservation) REQUIRES_SHARED(Locks::mutator_lock_);
151 
152   // Try to open an existing app image space for an oat file,
153   // using the boot image spaces from the current Runtime.
154   static std::unique_ptr<ImageSpace> CreateFromAppImage(const char* image,
155                                                         const OatFile* oat_file,
156                                                         std::string* error_msg)
157       REQUIRES_SHARED(Locks::mutator_lock_);
158   // Try to open an existing app image space for an the oat file and given boot image spaces.
159   static std::unique_ptr<ImageSpace> CreateFromAppImage(
160       const char* image,
161       const OatFile* oat_file,
162       ArrayRef<ImageSpace* const> boot_image_spaces,
163       std::string* error_msg) REQUIRES_SHARED(Locks::mutator_lock_);
164 
165   // Checks whether we have a primary boot image on the disk.
166   static bool IsBootClassPathOnDisk(InstructionSet image_isa);
167 
168   // Give access to the OatFile.
169   const OatFile* GetOatFile() const;
170 
171   // Releases the OatFile from the ImageSpace so it can be transfer to
172   // the caller, presumably the OatFileManager.
173   std::unique_ptr<const OatFile> ReleaseOatFile();
174 
175   void VerifyImageAllocations()
176       REQUIRES_SHARED(Locks::mutator_lock_);
177 
GetImageHeader()178   const ImageHeader& GetImageHeader() const {
179     return *reinterpret_cast<ImageHeader*>(Begin());
180   }
181 
182   // Actual filename where image was loaded from.
183   // For example: /system/framework/arm64/boot.art
GetImageFilename()184   const std::string GetImageFilename() const {
185     return GetName();
186   }
187 
188   // Symbolic location for image.
189   // For example: /system/framework/boot.art
GetImageLocation()190   const std::string GetImageLocation() const {
191     return image_location_;
192   }
193 
GetProfileFiles()194   const std::vector<std::string>& GetProfileFiles() const { return profile_files_; }
195 
GetLiveBitmap()196   accounting::ContinuousSpaceBitmap* GetLiveBitmap() override {
197     return &live_bitmap_;
198   }
199 
GetMarkBitmap()200   accounting::ContinuousSpaceBitmap* GetMarkBitmap() override {
201     // ImageSpaces have the same bitmap for both live and marked. This helps reduce the number of
202     // special cases to test against.
203     return &live_bitmap_;
204   }
205 
206   // Compute the number of components in the image (contributing jar files).
GetComponentCount()207   size_t GetComponentCount() const {
208     return GetImageHeader().GetComponentCount();
209   }
210 
211   void Dump(std::ostream& os) const override;
212 
213   // Sweeping image spaces is a NOP.
Sweep(bool,size_t *,size_t *)214   void Sweep(bool /* swap_bitmaps */, size_t* /* freed_objects */, size_t* /* freed_bytes */) {
215   }
216 
CanMoveObjects()217   bool CanMoveObjects() const override {
218     return false;
219   }
220 
221   // Returns the filename of the image corresponding to
222   // requested image_location, or the filename where a new image
223   // should be written if one doesn't exist. Looks for a generated
224   // image in the specified location.
225   //
226   // Returns true if an image was found, false otherwise.
227   static bool FindImageFilename(const char* image_location,
228                                 InstructionSet image_isa,
229                                 std::string* system_location,
230                                 bool* has_system);
231 
232   // The leading character in an image checksum part of boot class path checksums.
233   static constexpr char kImageChecksumPrefix = 'i';
234   // The leading character in a dex file checksum part of boot class path checksums.
235   static constexpr char kDexFileChecksumPrefix = 'd';
236 
237   // Returns the checksums for the boot image, extensions and extra boot class path dex files,
238   // based on the image spaces and boot class path dex files loaded in memory.
239   // The `image_spaces` must correspond to the head of the `boot_class_path`.
240   static std::string GetBootClassPathChecksums(ArrayRef<ImageSpace* const> image_spaces,
241                                                ArrayRef<const DexFile* const> boot_class_path);
242 
243   // Returns the total number of components (jar files) associated with the image spaces.
244   static size_t GetNumberOfComponents(ArrayRef<gc::space::ImageSpace* const> image_spaces);
245 
246   // Returns whether the oat checksums and boot class path description are valid
247   // for the given boot image spaces and boot class path. Used for boot image extensions.
248   static bool VerifyBootClassPathChecksums(
249       std::string_view oat_checksums,
250       std::string_view oat_boot_class_path,
251       ArrayRef<const std::unique_ptr<ImageSpace>> image_spaces,
252       ArrayRef<const std::string> boot_class_path_locations,
253       ArrayRef<const std::string> boot_class_path,
254       /*out*/std::string* error_msg);
255 
256   // Expand a single image location to multi-image locations based on the dex locations.
257   static std::vector<std::string> ExpandMultiImageLocations(
258       ArrayRef<const std::string> dex_locations,
259       const std::string& image_location,
260       bool boot_image_extension = false);
261 
262   // Returns true if the APEX versions in the OAT header match the given APEX versions.
263   static bool ValidateApexVersions(const OatHeader& oat_header,
264                                    const std::string& apex_versions,
265                                    const std::string& file_location,
266                                    std::string* error_msg);
267 
268   // Returns true if the dex checksums in the given oat file match the
269   // checksums of the original dex files on disk. This is intended to be used
270   // to validate the boot image oat file, which may contain dex entries from
271   // multiple different (possibly multidex) dex files on disk. Prefer the
272   // OatFileAssistant for validating regular app oat files because the
273   // OatFileAssistant caches dex checksums that are reused to check both the
274   // oat and odex file.
275   //
276   // This function is exposed for testing purposes.
277   //
278   // Calling this function requires an active runtime.
279   static bool ValidateOatFile(const OatFile& oat_file, std::string* error_msg);
280 
281   // Same as above, but allows to use `dex_filenames` and `dex_fds` to find the dex files instead of
282   // using the dex filenames in the header of the oat file, and also takes `apex_versions` from the
283   // input. This overload is useful when the actual dex filenames are different from what's in the
284   // header (e.g., when we run dex2oat on host), when the runtime can only access files through FDs
285   // (e.g., when we run dex2oat on target in a restricted SELinux domain), or when there is no
286   // active runtime.
287   //
288   // Calling this function does not require an active runtime.
289   static bool ValidateOatFile(const OatFile& oat_file,
290                               std::string* error_msg,
291                               ArrayRef<const std::string> dex_filenames,
292                               ArrayRef<const int> dex_fds,
293                               const std::string& apex_versions);
294 
295   // Return the end of the image which includes non-heap objects such as ArtMethods and ArtFields.
GetImageEnd()296   uint8_t* GetImageEnd() const {
297     return Begin() + GetImageHeader().GetImageSize();
298   }
299 
300   void DumpSections(std::ostream& os) const;
301 
302   // De-initialize the image-space by undoing the effects in Init().
303   virtual ~ImageSpace();
304 
305   void ReleaseMetadata() REQUIRES_SHARED(Locks::mutator_lock_);
306 
307   static void AppendImageChecksum(uint32_t component_count,
308                                   uint32_t checksum,
309                                   /*inout*/ std::string* checksums);
310 
311   static size_t CheckAndCountBCPComponents(std::string_view oat_boot_class_path,
312                                            ArrayRef<const std::string> boot_class_path,
313                                            /*out*/ std::string* error_msg);
314 
315   // Helper class to find the primary boot image and boot image extensions
316   // and determine the boot image layout.
317   class BootImageLayout {
318    public:
319     // Description of a "chunk" of the boot image, i.e. either primary boot image
320     // or a boot image extension, used in conjunction with the boot class path to
321     // load boot image components.
322     struct ImageChunk {
323       std::string base_location;
324       std::string base_filename;
325       std::vector<std::string> profile_files;
326       size_t start_index;
327       uint32_t component_count;
328       uint32_t image_space_count;
329       uint32_t reservation_size;
330       uint32_t checksum;
331       uint32_t boot_image_component_count;
332       uint32_t boot_image_checksum;
333       uint32_t boot_image_size;
334 
335       // The following file descriptors hold the memfd files for extensions compiled
336       // in memory and described by the above fields. We want to use them to mmap()
337       // the contents and then close them while treating the ImageChunk description
338       // as immutable (const), so make these fields explicitly mutable.
339       mutable android::base::unique_fd art_fd;
340       mutable android::base::unique_fd vdex_fd;
341       mutable android::base::unique_fd oat_fd;
342     };
343 
344     BootImageLayout(ArrayRef<const std::string> image_locations,
345                     ArrayRef<const std::string> boot_class_path,
346                     ArrayRef<const std::string> boot_class_path_locations,
347                     ArrayRef<const int> boot_class_path_fds,
348                     ArrayRef<const int> boot_class_path_image_fds,
349                     ArrayRef<const int> boot_class_path_vdex_fds,
350                     ArrayRef<const int> boot_class_path_oat_fds,
351                     const std::string* apex_versions = nullptr)
image_locations_(image_locations)352         : image_locations_(image_locations),
353           boot_class_path_(boot_class_path),
354           boot_class_path_locations_(boot_class_path_locations),
355           boot_class_path_fds_(boot_class_path_fds),
356           boot_class_path_image_fds_(boot_class_path_image_fds),
357           boot_class_path_vdex_fds_(boot_class_path_vdex_fds),
358           boot_class_path_oat_fds_(boot_class_path_oat_fds),
359           apex_versions_(GetApexVersions(apex_versions)) {}
360 
361     std::string GetPrimaryImageLocation();
362 
363     bool LoadFromSystem(InstructionSet image_isa,
364                         bool allow_in_memory_compilation,
365                         /*out*/ std::string* error_msg);
366 
GetChunks()367     ArrayRef<const ImageChunk> GetChunks() const { return ArrayRef<const ImageChunk>(chunks_); }
368 
GetBaseAddress()369     uint32_t GetBaseAddress() const { return base_address_; }
370 
GetNextBcpIndex()371     size_t GetNextBcpIndex() const { return next_bcp_index_; }
372 
GetTotalComponentCount()373     size_t GetTotalComponentCount() const { return total_component_count_; }
374 
GetTotalReservationSize()375     size_t GetTotalReservationSize() const { return total_reservation_size_; }
376 
377    private:
378     struct NamedComponentLocation {
379       std::string base_location;
380       size_t bcp_index;
381       std::vector<std::string> profile_filenames;
382     };
383 
ExpandLocationImpl(const std::string & location,size_t bcp_index,bool boot_image_extension)384     std::string ExpandLocationImpl(const std::string& location,
385                                    size_t bcp_index,
386                                    bool boot_image_extension) {
387       std::vector<std::string> expanded = ExpandMultiImageLocations(
388           ArrayRef<const std::string>(boot_class_path_).SubArray(bcp_index, 1u),
389           location,
390           boot_image_extension);
391       DCHECK_EQ(expanded.size(), 1u);
392       return expanded[0];
393     }
394 
ExpandLocation(const std::string & location,size_t bcp_index)395     std::string ExpandLocation(const std::string& location, size_t bcp_index) {
396       if (bcp_index == 0u) {
397         DCHECK_EQ(location,
398                   ExpandLocationImpl(location, bcp_index, /*boot_image_extension=*/false));
399         return location;
400       } else {
401         return ExpandLocationImpl(location, bcp_index, /*boot_image_extension=*/true);
402       }
403     }
404 
GetBcpComponentPath(size_t bcp_index)405     std::string GetBcpComponentPath(size_t bcp_index) {
406       DCHECK_LE(bcp_index, boot_class_path_.size());
407       size_t bcp_slash_pos = boot_class_path_[bcp_index].rfind('/');
408       DCHECK_NE(bcp_slash_pos, std::string::npos);
409       return boot_class_path_[bcp_index].substr(0u, bcp_slash_pos + 1u);
410     }
411 
412     bool VerifyImageLocation(ArrayRef<const std::string> components,
413                              /*out*/ size_t* named_components_count,
414                              /*out*/ std::string* error_msg);
415 
416     bool MatchNamedComponents(
417         ArrayRef<const std::string> named_components,
418         /*out*/ std::vector<NamedComponentLocation>* named_component_locations,
419         /*out*/ std::string* error_msg);
420 
421     bool ValidateBootImageChecksum(const char* file_description,
422                                    const ImageHeader& header,
423                                    /*out*/ std::string* error_msg);
424 
425     bool ValidateHeader(const ImageHeader& header,
426                         size_t bcp_index,
427                         const char* file_description,
428                         /*out*/ std::string* error_msg);
429 
430     bool ValidateOatFile(const std::string& base_location,
431                          const std::string& base_filename,
432                          size_t bcp_index,
433                          size_t component_count,
434                          /*out*/ std::string* error_msg);
435 
436     bool ReadHeader(const std::string& base_location,
437                     const std::string& base_filename,
438                     size_t bcp_index,
439                     /*out*/ std::string* error_msg);
440 
441     // Compiles a consecutive subsequence of bootclasspath dex files, whose contents are included in
442     // the profiles specified by `profile_filenames`, starting from `bcp_index`.
443     bool CompileBootclasspathElements(const std::string& base_location,
444                                       const std::string& base_filename,
445                                       size_t bcp_index,
446                                       const std::vector<std::string>& profile_filenames,
447                                       ArrayRef<const std::string> dependencies,
448                                       /*out*/ std::string* error_msg);
449 
450     // Returns true if a least one chuck has been loaded.
451     template <typename FilenameFn>
452     bool Load(FilenameFn&& filename_fn,
453               bool allow_in_memory_compilation,
454               /*out*/ std::string* error_msg);
455 
456     // This function prefers taking APEX versions from the input instead of from the runtime if
457     // possible. If the input is present, `ValidateFromSystem` can work without an active runtime.
GetApexVersions(const std::string * apex_versions)458     static const std::string& GetApexVersions(const std::string* apex_versions) {
459       if (apex_versions == nullptr) {
460         DCHECK(Runtime::Current() != nullptr);
461         return Runtime::Current()->GetApexVersions();
462       } else {
463         return *apex_versions;
464       }
465     }
466 
467     ArrayRef<const std::string> image_locations_;
468     ArrayRef<const std::string> boot_class_path_;
469     ArrayRef<const std::string> boot_class_path_locations_;
470     ArrayRef<const int> boot_class_path_fds_;
471     ArrayRef<const int> boot_class_path_image_fds_;
472     ArrayRef<const int> boot_class_path_vdex_fds_;
473     ArrayRef<const int> boot_class_path_oat_fds_;
474 
475     std::vector<ImageChunk> chunks_;
476     uint32_t base_address_ = 0u;
477     size_t next_bcp_index_ = 0u;
478     size_t total_component_count_ = 0u;
479     size_t total_reservation_size_ = 0u;
480     const std::string& apex_versions_;
481   };
482 
483  protected:
484   // Tries to initialize an ImageSpace from the given image path, returning null on error.
485   //
486   // If validate_oat_file is false (for /system), do not verify that image's OatFile is up-to-date
487   // relative to its DexFile inputs. Otherwise, validate `oat_file` and abandon it if the validation
488   // fails. If the oat_file is null, it uses the oat file from the image.
489   static std::unique_ptr<ImageSpace> Init(const char* image_filename,
490                                           const char* image_location,
491                                           bool validate_oat_file,
492                                           const OatFile* oat_file,
493                                           std::string* error_msg)
494       REQUIRES_SHARED(Locks::mutator_lock_);
495 
496   static Atomic<uint32_t> bitmap_index_;
497 
498   accounting::ContinuousSpaceBitmap live_bitmap_;
499 
500   ImageSpace(const std::string& name,
501              const char* image_location,
502              const std::vector<std::string>& profile_files,
503              MemMap&& mem_map,
504              accounting::ContinuousSpaceBitmap&& live_bitmap,
505              uint8_t* end);
506 
507   // The OatFile associated with the image during early startup to
508   // reserve space contiguous to the image. It is later released to
509   // the ClassLinker during it's initialization.
510   std::unique_ptr<OatFile> oat_file_;
511 
512   // There are times when we need to find the boot image oat file. As
513   // we release ownership during startup, keep a non-owned reference.
514   const OatFile* oat_file_non_owned_;
515 
516   const std::string image_location_;
517   const std::vector<std::string> profile_files_;
518 
519   friend class Space;
520 
521  private:
522   class BootImageLoader;
523   template <typename ReferenceVisitor>
524   class ClassTableVisitor;
525   class RemapInternedStringsVisitor;
526   class Loader;
527   template <typename PatchObjectVisitor>
528   class PatchArtFieldVisitor;
529   template <PointerSize kPointerSize, typename PatchObjectVisitor, typename PatchCodeVisitor>
530   class PatchArtMethodVisitor;
531   template <PointerSize kPointerSize, typename HeapVisitor, typename NativeVisitor>
532   class PatchObjectVisitor;
533 
534   DISALLOW_COPY_AND_ASSIGN(ImageSpace);
535 };
536 
537 }  // namespace space
538 }  // namespace gc
539 }  // namespace art
540 
541 #endif  // ART_RUNTIME_GC_SPACE_IMAGE_SPACE_H_
542