Revert "Revert "Add support for LZ4 compressed image files""
Needed to call compiler_driver_->SetSupportBootImageFixup(false).
Bug: 22858531
This reverts commit 83d4d72aa0e4170209ab50c67ba22e46b71352c1.
Change-Id: Iaed6a810a0c088f1f2c57cf2f12087f3978a3de1
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index e2b2431..8f67c21 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -17,12 +17,12 @@
#include "image_space.h"
#include <dirent.h>
+#include <lz4.h>
+#include <random>
#include <sys/statvfs.h>
#include <sys/types.h>
#include <unistd.h>
-#include <random>
-
#include "art_method.h"
#include "base/macros.h"
#include "base/stl_util.h"
@@ -677,11 +677,12 @@
*error_msg = StringPrintf("Invalid image header in '%s'", image_filename);
return nullptr;
}
- // Check that the file is large enough.
- uint64_t image_file_size = static_cast<uint64_t>(file->GetLength());
- if (image_header.GetImageSize() > image_file_size) {
- *error_msg = StringPrintf("Image file too small for image heap: %" PRIu64 " vs. %zu.",
- image_file_size, image_header.GetImageSize());
+ // Check that the file is larger or equal to the header size + data size.
+ const uint64_t image_file_size = static_cast<uint64_t>(file->GetLength());
+ if (image_file_size < sizeof(ImageHeader) + image_header.GetDataSize()) {
+ *error_msg = StringPrintf("Image file truncated: %" PRIu64 " vs. %" PRIu64 ".",
+ image_file_size,
+ image_header.GetDataSize());
return nullptr;
}
@@ -697,7 +698,11 @@
}
const auto& bitmap_section = image_header.GetImageSection(ImageHeader::kSectionImageBitmap);
- auto end_of_bitmap = static_cast<size_t>(bitmap_section.End());
+ // The location we want to map from is the first aligned page after the end of the stored
+ // (possibly compressed) data.
+ const size_t image_bitmap_offset = RoundUp(sizeof(image_header) + image_header.GetDataSize(),
+ kPageSize);
+ const size_t end_of_bitmap = image_bitmap_offset + bitmap_section.Size();
if (end_of_bitmap != image_file_size) {
*error_msg = StringPrintf(
"Image file size does not equal end of bitmap: size=%" PRIu64 " vs. %zu.", image_file_size,
@@ -706,16 +711,60 @@
}
// Note: The image header is part of the image due to mmap page alignment required of offset.
- std::unique_ptr<MemMap> map(MemMap::MapFileAtAddress(image_header.GetImageBegin(),
- image_header.GetImageSize(),
- PROT_READ | PROT_WRITE,
+ std::unique_ptr<MemMap> map;
+ if (image_header.GetStorageMode() == ImageHeader::kStorageModeUncompressed) {
+ map.reset(MemMap::MapFileAtAddress(image_header.GetImageBegin(),
+ image_header.GetImageSize(),
+ PROT_READ | PROT_WRITE,
+ MAP_PRIVATE,
+ file->Fd(),
+ 0,
+ /*low_4gb*/false,
+ /*reuse*/false,
+ image_filename,
+ error_msg));
+ } else {
+ // Reserve output and decompress into it.
+ map.reset(MemMap::MapAnonymous(image_location,
+ image_header.GetImageBegin(),
+ image_header.GetImageSize(),
+ PROT_READ | PROT_WRITE,
+ /*low_4gb*/false,
+ /*reuse*/false,
+ error_msg));
+ if (map != nullptr) {
+ const size_t stored_size = image_header.GetDataSize();
+ const size_t write_offset = sizeof(image_header); // Skip the header.
+ std::unique_ptr<MemMap> temp_map(MemMap::MapFile(sizeof(ImageHeader) + stored_size,
+ PROT_READ,
MAP_PRIVATE,
file->Fd(),
- 0,
+ /*offset*/0,
/*low_4gb*/false,
- /*reuse*/false,
image_filename,
error_msg));
+ if (temp_map == nullptr) {
+ DCHECK(!error_msg->empty());
+ return nullptr;
+ }
+ memcpy(map->Begin(), &image_header, sizeof(image_header));
+ const uint64_t start = NanoTime();
+ const size_t decompressed_size = LZ4_decompress_safe(
+ reinterpret_cast<char*>(temp_map->Begin()) + sizeof(ImageHeader),
+ reinterpret_cast<char*>(map->Begin()) + write_offset,
+ stored_size,
+ map->Size());
+ // TODO: VLOG(image)
+ VLOG(class_linker) << "Decompressing image took " << PrettyDuration(NanoTime() - start);
+ if (decompressed_size + sizeof(ImageHeader) != image_header.GetImageSize()) {
+ *error_msg = StringPrintf("Decompressed size does not match expected image size %zu vs %zu",
+ decompressed_size + sizeof(ImageHeader),
+ image_header.GetImageSize());
+ return nullptr;
+ }
+ }
+ }
+
if (map == nullptr) {
DCHECK(!error_msg->empty());
return nullptr;
@@ -723,16 +772,16 @@
CHECK_EQ(image_header.GetImageBegin(), map->Begin());
DCHECK_EQ(0, memcmp(&image_header, map->Begin(), sizeof(ImageHeader)));
- std::unique_ptr<MemMap> image_map(MemMap::MapFileAtAddress(nullptr,
- bitmap_section.Size(),
- PROT_READ, MAP_PRIVATE,
- file->Fd(),
- bitmap_section.Offset(),
- /*low_4gb*/false,
- /*reuse*/false,
- image_filename,
- error_msg));
- if (image_map.get() == nullptr) {
+ std::unique_ptr<MemMap> image_bitmap_map(MemMap::MapFileAtAddress(nullptr,
+ bitmap_section.Size(),
+ PROT_READ, MAP_PRIVATE,
+ file->Fd(),
+ image_bitmap_offset,
+ /*low_4gb*/false,
+ /*reuse*/false,
+ image_filename,
+ error_msg));
+ if (image_bitmap_map == nullptr) {
*error_msg = StringPrintf("Failed to map image bitmap: %s", error_msg->c_str());
return nullptr;
}
@@ -741,9 +790,11 @@
bitmap_index));
std::unique_ptr<accounting::ContinuousSpaceBitmap> bitmap(
accounting::ContinuousSpaceBitmap::CreateFromMemMap(
- bitmap_name, image_map.release(), reinterpret_cast<uint8_t*>(map->Begin()),
+ bitmap_name,
+ image_bitmap_map.release(),
+ reinterpret_cast<uint8_t*>(map->Begin()),
accounting::ContinuousSpaceBitmap::ComputeHeapSize(bitmap_section.Size())));
- if (bitmap.get() == nullptr) {
+ if (bitmap == nullptr) {
*error_msg = StringPrintf("Could not create bitmap '%s'", bitmap_name.c_str());
return nullptr;
}