• 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(!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(!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 of the OAT file match the given APEX versions.
264   static bool ValidateApexVersions(const OatFile& oat_file,
265                                    std::string_view runtime_apex_versions,
266                                    std::string* error_msg);
267 
268   static bool ValidateApexVersions(std::string_view oat_apex_versions,
269                                    std::string_view runtime_apex_versions,
270                                    const std::string& file_location,
271                                    std::string* error_msg);
272 
273   // Returns true if the dex checksums in the given oat file match the
274   // checksums of the original dex files on disk. This is intended to be used
275   // to validate the boot image oat file, which may contain dex entries from
276   // multiple different (possibly multidex) dex files on disk. Prefer the
277   // OatFileAssistant for validating regular app oat files because the
278   // OatFileAssistant caches dex checksums that are reused to check both the
279   // oat and odex file.
280   //
281   // This function is exposed for testing purposes.
282   //
283   // Calling this function requires an active runtime.
284   static bool ValidateOatFile(const OatFile& oat_file, std::string* error_msg);
285 
286   // Same as above, but allows to use `dex_filenames` and `dex_fds` to find the dex files instead of
287   // using the dex filenames in the header of the oat file, and also takes `apex_versions` from the
288   // input. This overload is useful when the actual dex filenames are different from what's in the
289   // header (e.g., when we run dex2oat on host), when the runtime can only access files through FDs
290   // (e.g., when we run dex2oat on target in a restricted SELinux domain), or when there is no
291   // active runtime.
292   //
293   // Calling this function does not require an active runtime.
294   static bool ValidateOatFile(const OatFile& oat_file,
295                               std::string* error_msg,
296                               ArrayRef<const std::string> dex_filenames,
297                               ArrayRef<File> dex_files,
298                               const std::string& apex_versions);
299 
300   // Return the end of the image which includes non-heap objects such as ArtMethods and ArtFields.
GetImageEnd()301   uint8_t* GetImageEnd() const {
302     return Begin() + GetImageHeader().GetImageSize();
303   }
304 
305   void DumpSections(std::ostream& os) const;
306 
307   // De-initialize the image-space by undoing the effects in Init().
308   virtual ~ImageSpace();
309 
310   void ReleaseMetadata() REQUIRES_SHARED(Locks::mutator_lock_);
311 
312   static void AppendImageChecksum(uint32_t component_count,
313                                   uint32_t checksum,
314                                   /*inout*/ std::string* checksums);
315 
316   static size_t CheckAndCountBCPComponents(std::string_view oat_boot_class_path,
317                                            ArrayRef<const std::string> boot_class_path,
318                                            /*out*/ std::string* error_msg);
319 
320   // Helper class to find the primary boot image and boot image extensions
321   // and determine the boot image layout.
322   class BootImageLayout {
323    public:
324     // Description of a "chunk" of the boot image, i.e. either primary boot image
325     // or a boot image extension, used in conjunction with the boot class path to
326     // load boot image components.
327     struct ImageChunk {
328       std::string base_location;
329       std::string base_filename;
330       std::vector<std::string> profile_files;
331       size_t start_index;
332       uint32_t component_count;
333       uint32_t image_space_count;
334       uint32_t reservation_size;
335       uint32_t checksum;
336       uint32_t boot_image_component_count;
337       uint32_t boot_image_checksum;
338       uint32_t boot_image_size;
339 
340       // The following file descriptors hold the memfd files for extensions compiled
341       // in memory and described by the above fields. We want to use them to mmap()
342       // the contents and then close them while treating the ImageChunk description
343       // as immutable (const), so make these fields explicitly mutable.
344       mutable android::base::unique_fd art_fd;
345       mutable android::base::unique_fd vdex_fd;
346       mutable android::base::unique_fd oat_fd;
347     };
348 
349     // Creates an instance.
350     // `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)351     BootImageLayout(ArrayRef<const std::string> image_locations,
352                     ArrayRef<const std::string> boot_class_path,
353                     ArrayRef<const std::string> boot_class_path_locations,
354                     ArrayRef<File> boot_class_path_files,
355                     ArrayRef<File> boot_class_path_image_files,
356                     ArrayRef<File> boot_class_path_vdex_files,
357                     ArrayRef<File> boot_class_path_oat_files,
358                     const std::string* apex_versions)
359         : image_locations_(image_locations),
360           boot_class_path_(boot_class_path),
361           boot_class_path_locations_(boot_class_path_locations),
362           boot_class_path_files_(boot_class_path_files),
363           boot_class_path_image_files_(boot_class_path_image_files),
364           boot_class_path_vdex_files_(boot_class_path_vdex_files),
365           boot_class_path_oat_files_(boot_class_path_oat_files),
366           apex_versions_(*apex_versions) {}
367 
368     std::string GetPrimaryImageLocation();
369 
370     bool LoadFromSystem(InstructionSet image_isa,
371                         bool allow_in_memory_compilation,
372                         /*out*/ std::string* error_msg);
373 
GetChunks()374     ArrayRef<const ImageChunk> GetChunks() const { return ArrayRef<const ImageChunk>(chunks_); }
375 
GetBaseAddress()376     uint32_t GetBaseAddress() const { return base_address_; }
377 
GetNextBcpIndex()378     size_t GetNextBcpIndex() const { return next_bcp_index_; }
379 
GetTotalComponentCount()380     size_t GetTotalComponentCount() const { return total_component_count_; }
381 
GetTotalReservationSize()382     size_t GetTotalReservationSize() const { return total_reservation_size_; }
383 
384    private:
385     struct NamedComponentLocation {
386       std::string base_location;
387       size_t bcp_index;
388       std::vector<std::string> profile_filenames;
389     };
390 
ExpandLocationImpl(const std::string & location,size_t bcp_index,bool boot_image_extension)391     std::string ExpandLocationImpl(const std::string& location,
392                                    size_t bcp_index,
393                                    bool boot_image_extension) {
394       std::vector<std::string> expanded = ExpandMultiImageLocations(
395           ArrayRef<const std::string>(boot_class_path_).SubArray(bcp_index, 1u),
396           location,
397           boot_image_extension);
398       DCHECK_EQ(expanded.size(), 1u);
399       return expanded[0];
400     }
401 
ExpandLocation(const std::string & location,size_t bcp_index)402     std::string ExpandLocation(const std::string& location, size_t bcp_index) {
403       if (bcp_index == 0u) {
404         DCHECK_EQ(location,
405                   ExpandLocationImpl(location, bcp_index, /*boot_image_extension=*/false));
406         return location;
407       } else {
408         return ExpandLocationImpl(location, bcp_index, /*boot_image_extension=*/true);
409       }
410     }
411 
GetBcpComponentPath(size_t bcp_index)412     std::string GetBcpComponentPath(size_t bcp_index) {
413       DCHECK_LE(bcp_index, boot_class_path_.size());
414       size_t bcp_slash_pos = boot_class_path_[bcp_index].rfind('/');
415       DCHECK_NE(bcp_slash_pos, std::string::npos);
416       return boot_class_path_[bcp_index].substr(0u, bcp_slash_pos + 1u);
417     }
418 
419     bool VerifyImageLocation(ArrayRef<const std::string> components,
420                              /*out*/ size_t* named_components_count,
421                              /*out*/ std::string* error_msg);
422 
423     bool MatchNamedComponents(
424         ArrayRef<const std::string> named_components,
425         /*out*/ std::vector<NamedComponentLocation>* named_component_locations,
426         /*out*/ std::string* error_msg);
427 
428     bool ValidateBootImageChecksum(const char* file_description,
429                                    const ImageHeader& header,
430                                    /*out*/ std::string* error_msg);
431 
432     bool ValidateHeader(const ImageHeader& header,
433                         size_t bcp_index,
434                         const char* file_description,
435                         /*out*/ std::string* error_msg);
436 
437     bool ValidateOatFile(const std::string& base_location,
438                          const std::string& base_filename,
439                          size_t bcp_index,
440                          size_t component_count,
441                          /*out*/ std::string* error_msg);
442 
443     bool ReadHeader(const std::string& base_location,
444                     const std::string& base_filename,
445                     size_t bcp_index,
446                     /*out*/ std::string* error_msg);
447 
448     // Compiles a consecutive subsequence of bootclasspath dex files, whose contents are included in
449     // the profiles specified by `profile_filenames`, starting from `bcp_index`.
450     bool CompileBootclasspathElements(const std::string& base_location,
451                                       const std::string& base_filename,
452                                       size_t bcp_index,
453                                       const std::vector<std::string>& profile_filenames,
454                                       ArrayRef<const std::string> dependencies,
455                                       /*out*/ std::string* error_msg);
456 
457     // Returns true if a least one chuck has been loaded.
458     template <typename FilenameFn>
459     bool Load(FilenameFn&& filename_fn,
460               bool allow_in_memory_compilation,
461               /*out*/ std::string* error_msg);
462 
463     ArrayRef<const std::string> image_locations_;
464     ArrayRef<const std::string> boot_class_path_;
465     ArrayRef<const std::string> boot_class_path_locations_;
466     ArrayRef<File> boot_class_path_files_;
467     ArrayRef<File> boot_class_path_image_files_;
468     ArrayRef<File> boot_class_path_vdex_files_;
469     ArrayRef<File> boot_class_path_oat_files_;
470 
471     std::vector<ImageChunk> chunks_;
472     uint32_t base_address_ = 0u;
473     size_t next_bcp_index_ = 0u;
474     size_t total_component_count_ = 0u;
475     size_t total_reservation_size_ = 0u;
476     const std::string& apex_versions_;
477   };
478 
479  protected:
480   // Tries to initialize an ImageSpace from the given image path, returning null on error.
481   //
482   // If validate_oat_file is false (for /system), do not verify that image's OatFile is up-to-date
483   // relative to its DexFile inputs. Otherwise, validate `oat_file` and abandon it if the validation
484   // fails. If the oat_file is null, it uses the oat file from the image.
485   static std::unique_ptr<ImageSpace> Init(const char* image_filename,
486                                           const char* image_location,
487                                           bool validate_oat_file,
488                                           const OatFile* oat_file,
489                                           std::string* error_msg)
490       REQUIRES_SHARED(Locks::mutator_lock_);
491 
492   static Atomic<uint32_t> bitmap_index_;
493 
494   accounting::ContinuousSpaceBitmap live_bitmap_;
495 
496   ImageSpace(const std::string& name,
497              const char* image_location,
498              const std::vector<std::string>& profile_files,
499              MemMap&& mem_map,
500              accounting::ContinuousSpaceBitmap&& live_bitmap,
501              uint8_t* end);
502 
503   // The OatFile associated with the image during early startup to
504   // reserve space contiguous to the image. It is later released to
505   // the ClassLinker during it's initialization.
506   std::unique_ptr<OatFile> oat_file_;
507 
508   // There are times when we need to find the boot image oat file. As
509   // we release ownership during startup, keep a non-owned reference.
510   const OatFile* oat_file_non_owned_;
511 
512   const std::string image_location_;
513   const std::vector<std::string> profile_files_;
514 
515   friend class Space;
516 
517  private:
518   class BootImageLoader;
519   template <typename ReferenceVisitor>
520   class ClassTableVisitor;
521   class RemapInternedStringsVisitor;
522   class Loader;
523   template <typename PatchObjectVisitor>
524   class PatchArtFieldVisitor;
525   template <PointerSize kPointerSize, typename PatchObjectVisitor, typename PatchCodeVisitor>
526   class PatchArtMethodVisitor;
527   template <PointerSize kPointerSize, typename HeapVisitor, typename NativeVisitor>
528   class PatchObjectVisitor;
529 
530   DISALLOW_COPY_AND_ASSIGN(ImageSpace);
531 };
532 
533 }  // namespace space
534 }  // namespace gc
535 }  // namespace art
536 
537 #endif  // ART_RUNTIME_GC_SPACE_IMAGE_SPACE_H_
538