• 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 "oat/image.h"
24 #include "runtime.h"
25 #include "space.h"
26 
27 namespace art HIDDEN {
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(const std::vector<std::string>& boot_class_path,
137                             const std::vector<std::string>& boot_class_path_locations,
138                             ArrayRef<File> boot_class_path_files,
139                             ArrayRef<File> boot_class_path_image_files,
140                             ArrayRef<File> boot_class_path_vdex_files,
141                             ArrayRef<File> boot_class_path_oat_files,
142                             const std::vector<std::string>& image_locations,
143                             const InstructionSet image_isa,
144                             bool relocate,
145                             bool executable,
146                             size_t extra_reservation_size,
147                             bool allow_in_memory_compilation,
148                             const std::string& apex_versions,
149                             /*out*/ std::vector<std::unique_ptr<ImageSpace>>* boot_image_spaces,
150                             /*out*/ MemMap* extra_reservation)
151       REQUIRES_SHARED(Locks::mutator_lock_);
152 
153   // Try to open an existing app image space for an oat file,
154   // using the boot image spaces from the current Runtime.
155   EXPORT static std::unique_ptr<ImageSpace> CreateFromAppImage(const char* image,
156                                                                const OatFile* oat_file,
157                                                                std::string* error_msg)
158       REQUIRES_SHARED(Locks::mutator_lock_);
159   // Try to open an existing app image space for an the oat file and given boot image spaces.
160   static std::unique_ptr<ImageSpace> CreateFromAppImage(
161       const char* image,
162       const OatFile* oat_file,
163       ArrayRef<ImageSpace* const> boot_image_spaces,
164       std::string* error_msg) REQUIRES_SHARED(Locks::mutator_lock_);
165 
166   // Checks whether we have a primary boot image on the disk.
167   static bool IsBootClassPathOnDisk(InstructionSet image_isa);
168 
169   // Give access to the OatFile.
170   EXPORT const OatFile* GetOatFile() const;
171 
172   // Releases the OatFile from the ImageSpace so it can be transfer to
173   // the caller, presumably the OatFileManager.
174   std::unique_ptr<const OatFile> ReleaseOatFile();
175 
176   void VerifyImageAllocations()
177       REQUIRES_SHARED(Locks::mutator_lock_);
178 
GetImageHeader()179   const ImageHeader& GetImageHeader() const {
180     return *reinterpret_cast<ImageHeader*>(Begin());
181   }
182 
183   // Actual filename where image was loaded from.
184   // For example: /system/framework/arm64/boot.art
GetImageFilename()185   const std::string GetImageFilename() const {
186     return GetName();
187   }
188 
189   // Symbolic location for image.
190   // For example: /system/framework/boot.art
GetImageLocation()191   const std::string GetImageLocation() const {
192     return image_location_;
193   }
194 
GetProfileFiles()195   const std::vector<std::string>& GetProfileFiles() const { return profile_files_; }
196 
GetLiveBitmap()197   accounting::ContinuousSpaceBitmap* GetLiveBitmap() override {
198     return &live_bitmap_;
199   }
200 
GetMarkBitmap()201   accounting::ContinuousSpaceBitmap* GetMarkBitmap() override {
202     // ImageSpaces have the same bitmap for both live and marked. This helps reduce the number of
203     // special cases to test against.
204     return &live_bitmap_;
205   }
206 
207   // Compute the number of components in the image (contributing jar files).
GetComponentCount()208   size_t GetComponentCount() const {
209     return GetImageHeader().GetComponentCount();
210   }
211 
212   void Dump(std::ostream& os) const override;
213 
214   // Sweeping image spaces is a NOP.
Sweep(bool,size_t *,size_t *)215   void Sweep(bool /* swap_bitmaps */, size_t* /* freed_objects */, size_t* /* freed_bytes */) {
216   }
217 
CanMoveObjects()218   bool CanMoveObjects() const override {
219     return false;
220   }
221 
222   // Returns the filename of the image corresponding to
223   // requested image_location, or the filename where a new image
224   // should be written if one doesn't exist. Looks for a generated
225   // image in the specified location.
226   //
227   // Returns true if an image was found, false otherwise.
228   static bool FindImageFilename(const char* image_location,
229                                 InstructionSet image_isa,
230                                 std::string* system_location,
231                                 bool* has_system);
232 
233   // The leading character in an image checksum part of boot class path checksums.
234   static constexpr char kImageChecksumPrefix = 'i';
235   // The leading character in a dex file checksum part of boot class path checksums.
236   static constexpr char kDexFileChecksumPrefix = 'd';
237 
238   // Returns the checksums for the boot image, extensions and extra boot class path dex files,
239   // based on the image spaces and boot class path dex files loaded in memory.
240   // The `image_spaces` must correspond to the head of the `boot_class_path`.
241   EXPORT static std::string GetBootClassPathChecksums(
242       ArrayRef<ImageSpace* const> image_spaces, ArrayRef<const DexFile* const> boot_class_path);
243 
244   // Returns the total number of components (jar files) associated with the image spaces.
245   static size_t GetNumberOfComponents(ArrayRef<gc::space::ImageSpace* const> image_spaces);
246 
247   // Returns whether the oat checksums and boot class path description are valid
248   // for the given boot image spaces and boot class path. Used for boot image extensions.
249   static bool VerifyBootClassPathChecksums(
250       std::string_view oat_checksums,
251       std::string_view oat_boot_class_path,
252       ArrayRef<const std::unique_ptr<ImageSpace>> image_spaces,
253       ArrayRef<const std::string> boot_class_path_locations,
254       ArrayRef<const std::string> boot_class_path,
255       /*out*/std::string* error_msg);
256 
257   // Expand a single image location to multi-image locations based on the dex locations.
258   EXPORT static std::vector<std::string> ExpandMultiImageLocations(
259       ArrayRef<const std::string> dex_locations,
260       const std::string& image_location,
261       bool boot_image_extension = false);
262 
263   // Returns true if the APEX versions in the OAT header match the given APEX versions.
264   static bool ValidateApexVersions(const OatHeader& oat_header,
265                                    const std::string& apex_versions,
266                                    const std::string& file_location,
267                                    std::string* error_msg);
268 
269   // Returns true if the dex checksums in the given oat file match the
270   // checksums of the original dex files on disk. This is intended to be used
271   // to validate the boot image oat file, which may contain dex entries from
272   // multiple different (possibly multidex) dex files on disk. Prefer the
273   // OatFileAssistant for validating regular app oat files because the
274   // OatFileAssistant caches dex checksums that are reused to check both the
275   // oat and odex file.
276   //
277   // This function is exposed for testing purposes.
278   //
279   // Calling this function requires an active runtime.
280   static bool ValidateOatFile(const OatFile& oat_file, std::string* error_msg);
281 
282   // Same as above, but allows to use `dex_filenames` and `dex_fds` to find the dex files instead of
283   // using the dex filenames in the header of the oat file, and also takes `apex_versions` from the
284   // input. This overload is useful when the actual dex filenames are different from what's in the
285   // header (e.g., when we run dex2oat on host), when the runtime can only access files through FDs
286   // (e.g., when we run dex2oat on target in a restricted SELinux domain), or when there is no
287   // active runtime.
288   //
289   // Calling this function does not require an active runtime.
290   static bool ValidateOatFile(const OatFile& oat_file,
291                               std::string* error_msg,
292                               ArrayRef<const std::string> dex_filenames,
293                               ArrayRef<File> dex_files,
294                               const std::string& apex_versions);
295 
296   // Return the end of the image which includes non-heap objects such as ArtMethods and ArtFields.
GetImageEnd()297   uint8_t* GetImageEnd() const {
298     return Begin() + GetImageHeader().GetImageSize();
299   }
300 
301   void DumpSections(std::ostream& os) const;
302 
303   // De-initialize the image-space by undoing the effects in Init().
304   virtual ~ImageSpace();
305 
306   void ReleaseMetadata() REQUIRES_SHARED(Locks::mutator_lock_);
307 
308   static void AppendImageChecksum(uint32_t component_count,
309                                   uint32_t checksum,
310                                   /*inout*/ std::string* checksums);
311 
312   static size_t CheckAndCountBCPComponents(std::string_view oat_boot_class_path,
313                                            ArrayRef<const std::string> boot_class_path,
314                                            /*out*/ std::string* error_msg);
315 
316   // Helper class to find the primary boot image and boot image extensions
317   // and determine the boot image layout.
318   class BootImageLayout {
319    public:
320     // Description of a "chunk" of the boot image, i.e. either primary boot image
321     // or a boot image extension, used in conjunction with the boot class path to
322     // load boot image components.
323     struct ImageChunk {
324       std::string base_location;
325       std::string base_filename;
326       std::vector<std::string> profile_files;
327       size_t start_index;
328       uint32_t component_count;
329       uint32_t image_space_count;
330       uint32_t reservation_size;
331       uint32_t checksum;
332       uint32_t boot_image_component_count;
333       uint32_t boot_image_checksum;
334       uint32_t boot_image_size;
335 
336       // The following file descriptors hold the memfd files for extensions compiled
337       // in memory and described by the above fields. We want to use them to mmap()
338       // the contents and then close them while treating the ImageChunk description
339       // as immutable (const), so make these fields explicitly mutable.
340       mutable android::base::unique_fd art_fd;
341       mutable android::base::unique_fd vdex_fd;
342       mutable android::base::unique_fd oat_fd;
343     };
344 
345     // Creates an instance.
346     // `apex_versions` is created from `Runtime::GetApexVersions` and must outlive this instance.
BootImageLayout(ArrayRef<const std::string> image_locations,ArrayRef<const std::string> boot_class_path,ArrayRef<const std::string> boot_class_path_locations,ArrayRef<File> boot_class_path_files,ArrayRef<File> boot_class_path_image_files,ArrayRef<File> boot_class_path_vdex_files,ArrayRef<File> boot_class_path_oat_files,const std::string * apex_versions)347     BootImageLayout(ArrayRef<const std::string> image_locations,
348                     ArrayRef<const std::string> boot_class_path,
349                     ArrayRef<const std::string> boot_class_path_locations,
350                     ArrayRef<File> boot_class_path_files,
351                     ArrayRef<File> boot_class_path_image_files,
352                     ArrayRef<File> boot_class_path_vdex_files,
353                     ArrayRef<File> boot_class_path_oat_files,
354                     const std::string* apex_versions)
355         : image_locations_(image_locations),
356           boot_class_path_(boot_class_path),
357           boot_class_path_locations_(boot_class_path_locations),
358           boot_class_path_files_(boot_class_path_files),
359           boot_class_path_image_files_(boot_class_path_image_files),
360           boot_class_path_vdex_files_(boot_class_path_vdex_files),
361           boot_class_path_oat_files_(boot_class_path_oat_files),
362           apex_versions_(*apex_versions) {}
363 
364     std::string GetPrimaryImageLocation();
365 
366     bool LoadFromSystem(InstructionSet image_isa,
367                         bool allow_in_memory_compilation,
368                         /*out*/ std::string* error_msg);
369 
GetChunks()370     ArrayRef<const ImageChunk> GetChunks() const { return ArrayRef<const ImageChunk>(chunks_); }
371 
GetBaseAddress()372     uint32_t GetBaseAddress() const { return base_address_; }
373 
GetNextBcpIndex()374     size_t GetNextBcpIndex() const { return next_bcp_index_; }
375 
GetTotalComponentCount()376     size_t GetTotalComponentCount() const { return total_component_count_; }
377 
GetTotalReservationSize()378     size_t GetTotalReservationSize() const { return total_reservation_size_; }
379 
380    private:
381     struct NamedComponentLocation {
382       std::string base_location;
383       size_t bcp_index;
384       std::vector<std::string> profile_filenames;
385     };
386 
ExpandLocationImpl(const std::string & location,size_t bcp_index,bool boot_image_extension)387     std::string ExpandLocationImpl(const std::string& location,
388                                    size_t bcp_index,
389                                    bool boot_image_extension) {
390       std::vector<std::string> expanded = ExpandMultiImageLocations(
391           ArrayRef<const std::string>(boot_class_path_).SubArray(bcp_index, 1u),
392           location,
393           boot_image_extension);
394       DCHECK_EQ(expanded.size(), 1u);
395       return expanded[0];
396     }
397 
ExpandLocation(const std::string & location,size_t bcp_index)398     std::string ExpandLocation(const std::string& location, size_t bcp_index) {
399       if (bcp_index == 0u) {
400         DCHECK_EQ(location,
401                   ExpandLocationImpl(location, bcp_index, /*boot_image_extension=*/false));
402         return location;
403       } else {
404         return ExpandLocationImpl(location, bcp_index, /*boot_image_extension=*/true);
405       }
406     }
407 
GetBcpComponentPath(size_t bcp_index)408     std::string GetBcpComponentPath(size_t bcp_index) {
409       DCHECK_LE(bcp_index, boot_class_path_.size());
410       size_t bcp_slash_pos = boot_class_path_[bcp_index].rfind('/');
411       DCHECK_NE(bcp_slash_pos, std::string::npos);
412       return boot_class_path_[bcp_index].substr(0u, bcp_slash_pos + 1u);
413     }
414 
415     bool VerifyImageLocation(ArrayRef<const std::string> components,
416                              /*out*/ size_t* named_components_count,
417                              /*out*/ std::string* error_msg);
418 
419     bool MatchNamedComponents(
420         ArrayRef<const std::string> named_components,
421         /*out*/ std::vector<NamedComponentLocation>* named_component_locations,
422         /*out*/ std::string* error_msg);
423 
424     bool ValidateBootImageChecksum(const char* file_description,
425                                    const ImageHeader& header,
426                                    /*out*/ std::string* error_msg);
427 
428     bool ValidateHeader(const ImageHeader& header,
429                         size_t bcp_index,
430                         const char* file_description,
431                         /*out*/ std::string* error_msg);
432 
433     bool ValidateOatFile(const std::string& base_location,
434                          const std::string& base_filename,
435                          size_t bcp_index,
436                          size_t component_count,
437                          /*out*/ std::string* error_msg);
438 
439     bool ReadHeader(const std::string& base_location,
440                     const std::string& base_filename,
441                     size_t bcp_index,
442                     /*out*/ std::string* error_msg);
443 
444     // Compiles a consecutive subsequence of bootclasspath dex files, whose contents are included in
445     // the profiles specified by `profile_filenames`, starting from `bcp_index`.
446     bool CompileBootclasspathElements(const std::string& base_location,
447                                       const std::string& base_filename,
448                                       size_t bcp_index,
449                                       const std::vector<std::string>& profile_filenames,
450                                       ArrayRef<const std::string> dependencies,
451                                       /*out*/ std::string* error_msg);
452 
453     // Returns true if a least one chuck has been loaded.
454     template <typename FilenameFn>
455     bool Load(FilenameFn&& filename_fn,
456               bool allow_in_memory_compilation,
457               /*out*/ std::string* error_msg);
458 
459     ArrayRef<const std::string> image_locations_;
460     ArrayRef<const std::string> boot_class_path_;
461     ArrayRef<const std::string> boot_class_path_locations_;
462     ArrayRef<File> boot_class_path_files_;
463     ArrayRef<File> boot_class_path_image_files_;
464     ArrayRef<File> boot_class_path_vdex_files_;
465     ArrayRef<File> boot_class_path_oat_files_;
466 
467     std::vector<ImageChunk> chunks_;
468     uint32_t base_address_ = 0u;
469     size_t next_bcp_index_ = 0u;
470     size_t total_component_count_ = 0u;
471     size_t total_reservation_size_ = 0u;
472     const std::string& apex_versions_;
473   };
474 
475  protected:
476   // Tries to initialize an ImageSpace from the given image path, returning null on error.
477   //
478   // If validate_oat_file is false (for /system), do not verify that image's OatFile is up-to-date
479   // relative to its DexFile inputs. Otherwise, validate `oat_file` and abandon it if the validation
480   // fails. If the oat_file is null, it uses the oat file from the image.
481   static std::unique_ptr<ImageSpace> Init(const char* image_filename,
482                                           const char* image_location,
483                                           bool validate_oat_file,
484                                           const OatFile* oat_file,
485                                           std::string* error_msg)
486       REQUIRES_SHARED(Locks::mutator_lock_);
487 
488   static Atomic<uint32_t> bitmap_index_;
489 
490   accounting::ContinuousSpaceBitmap live_bitmap_;
491 
492   ImageSpace(const std::string& name,
493              const char* image_location,
494              const std::vector<std::string>& profile_files,
495              MemMap&& mem_map,
496              accounting::ContinuousSpaceBitmap&& live_bitmap,
497              uint8_t* end);
498 
499   // The OatFile associated with the image during early startup to
500   // reserve space contiguous to the image. It is later released to
501   // the ClassLinker during it's initialization.
502   std::unique_ptr<OatFile> oat_file_;
503 
504   // There are times when we need to find the boot image oat file. As
505   // we release ownership during startup, keep a non-owned reference.
506   const OatFile* oat_file_non_owned_;
507 
508   const std::string image_location_;
509   const std::vector<std::string> profile_files_;
510 
511   friend class Space;
512 
513  private:
514   class BootImageLoader;
515   template <typename ReferenceVisitor>
516   class ClassTableVisitor;
517   class RemapInternedStringsVisitor;
518   class Loader;
519   template <typename PatchObjectVisitor>
520   class PatchArtFieldVisitor;
521   template <PointerSize kPointerSize, typename PatchObjectVisitor, typename PatchCodeVisitor>
522   class PatchArtMethodVisitor;
523   template <PointerSize kPointerSize, typename HeapVisitor, typename NativeVisitor>
524   class PatchObjectVisitor;
525 
526   DISALLOW_COPY_AND_ASSIGN(ImageSpace);
527 };
528 
529 }  // namespace space
530 }  // namespace gc
531 }  // namespace art
532 
533 #endif  // ART_RUNTIME_GC_SPACE_IMAGE_SPACE_H_
534