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