ART: Add boot/app image checksums.
And check app oat files against the boot image checksum
instead of checking the oat checksum. The oat checksums are
included in image checksum calculations and the primary
image checksum calculation includes the checksums of the
secondary images.
Also remove the obsolete "patch delta" to keep the size
of the ImageHeader 8-byte aligned, remove the key-value
store from secondary oat files and move the oat checksum
update code from oat.cc to the oat_writer.cc.
Test: m test-art-host-gtest
Test: testrunner.py --host
Test: Pixel 2 XL boots.
Test: m test-art-target-gtest
Change-Id: If74f5f18479c44ede0503bf1911ddb9ff8f3c4f8
diff --git a/dex2oat/Android.bp b/dex2oat/Android.bp
index 8ce96a4..f8bdb16 100644
--- a/dex2oat/Android.bp
+++ b/dex2oat/Android.bp
@@ -66,15 +66,20 @@
android: {
// For atrace.
shared_libs: ["libcutils"],
+ static_libs: [
+ "libz",
+ ],
+ },
+ host: {
+ shared_libs: [
+ "libz",
+ ],
},
},
generated_sources: ["art_dex2oat_operator_srcs"],
shared_libs: [
"libbase",
],
- include_dirs: [
- "external/zlib",
- ],
export_include_dirs: ["."],
// For SHA-1 checksumming of build ID
@@ -95,6 +100,7 @@
},
static_libs: [
"libbase",
+ "libz",
],
}
@@ -261,6 +267,14 @@
lto: {
thin: true,
},
+ static_libs: [
+ "libz",
+ ],
+ },
+ host: {
+ shared_libs: [
+ "libz",
+ ],
},
},
}
@@ -284,6 +298,18 @@
static_libs: [
"libartd-dex2oat",
],
+ target: {
+ android: {
+ static_libs: [
+ "libz",
+ ],
+ },
+ host: {
+ shared_libs: [
+ "libz",
+ ],
+ },
+ },
}
cc_defaults {
@@ -309,6 +335,7 @@
static_libs: [
"libbase",
"libsigchain_dummy",
+ "libz",
],
}
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 437bf36..b634598 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -621,7 +621,7 @@
explicit Dex2Oat(TimingLogger* timings) :
compiler_kind_(Compiler::kOptimizing),
// Take the default set of instruction features from the build.
- image_file_location_oat_checksum_(0),
+ boot_image_checksum_(0),
key_value_store_(nullptr),
verification_results_(nullptr),
runtime_(nullptr),
@@ -1493,7 +1493,7 @@
key_value_store_->Put(OatHeader::kCompilationReasonKey, compilation_reason_);
}
- if (IsBootImage() && image_filenames_.size() > 1) {
+ if (IsBootImage()) {
// If we're compiling the boot image, store the boot classpath into the Key-Value store.
// We need this for the multi-image case.
key_value_store_->Put(OatHeader::kBootClassPathKey,
@@ -1513,9 +1513,9 @@
TimingLogger::ScopedTiming t3("Loading image checksum", timings_);
std::vector<gc::space::ImageSpace*> image_spaces =
Runtime::Current()->GetHeap()->GetBootImageSpaces();
- image_file_location_oat_checksum_ = image_spaces[0]->GetImageHeader().GetOatChecksum();
+ boot_image_checksum_ = image_spaces[0]->GetImageHeader().GetImageChecksum();
} else {
- image_file_location_oat_checksum_ = 0u;
+ boot_image_checksum_ = 0u;
}
// Open dex files for class path.
@@ -1571,7 +1571,7 @@
if (!oat_writers_[i]->WriteAndOpenDexFiles(
vdex_files_[i].get(),
rodata_.back(),
- key_value_store_.get(),
+ (i == 0u) ? key_value_store_.get() : nullptr,
verify,
update_input_vdex_,
copy_dex_files_,
@@ -2037,14 +2037,6 @@
oat_writer->GetOatDataOffset(),
oat_writer->GetOatSize());
}
-
- if (IsBootImage()) {
- // Have the image_file_location_oat_checksum_ for boot oat files
- // depend on the contents of all the boot oat files. This way only
- // the primary image checksum needs to be checked to determine
- // whether any of the images are out of date.
- image_file_location_oat_checksum_ ^= oat_writer->GetOatHeader().GetChecksum();
- }
}
for (size_t i = 0, size = oat_files_.size(); i != size; ++i) {
@@ -2083,7 +2075,7 @@
elf_writer->EndDataBimgRelRo(data_bimg_rel_ro);
}
- if (!oat_writer->WriteHeader(elf_writer->GetStream(), image_file_location_oat_checksum_)) {
+ if (!oat_writer->WriteHeader(elf_writer->GetStream(), boot_image_checksum_)) {
LOG(ERROR) << "Failed to write oat header to the ELF file " << oat_file->GetPath();
return false;
}
@@ -2710,7 +2702,7 @@
std::unique_ptr<CompilerOptions> compiler_options_;
Compiler::Kind compiler_kind_;
- uint32_t image_file_location_oat_checksum_;
+ uint32_t boot_image_checksum_;
std::unique_ptr<SafeMap<std::string, std::string> > key_value_store_;
std::unique_ptr<VerificationResults> verification_results_;
diff --git a/dex2oat/linker/image_test.h b/dex2oat/linker/image_test.h
index 9ef2875..182f96c 100644
--- a/dex2oat/linker/image_test.h
+++ b/dex2oat/linker/image_test.h
@@ -341,7 +341,7 @@
}
bool header_ok = oat_writer->WriteHeader(elf_writer->GetStream(),
- /* image_file_location_oat_checksum */ 0u);
+ /*boot_image_checksum=*/ 0u);
ASSERT_TRUE(header_ok);
writer->UpdateOatFileHeader(i, oat_writer->GetOatHeader());
diff --git a/dex2oat/linker/image_writer.cc b/dex2oat/linker/image_writer.cc
index a3fc1cd..248a441 100644
--- a/dex2oat/linker/image_writer.cc
+++ b/dex2oat/linker/image_writer.cc
@@ -19,6 +19,7 @@
#include <lz4.h>
#include <lz4hc.h>
#include <sys/stat.h>
+#include <zlib.h>
#include <memory>
#include <numeric>
@@ -606,6 +607,58 @@
referred_obj->IsString();
}
+// Helper class that erases the image file if it isn't properly flushed and closed.
+class ImageWriter::ImageFileGuard {
+ public:
+ ImageFileGuard() noexcept = default;
+ ImageFileGuard(ImageFileGuard&& other) noexcept = default;
+ ImageFileGuard& operator=(ImageFileGuard&& other) noexcept = default;
+
+ ~ImageFileGuard() {
+ if (image_file_ != nullptr) {
+ // Failure, erase the image file.
+ image_file_->Erase();
+ }
+ }
+
+ void reset(File* image_file) {
+ image_file_.reset(image_file);
+ }
+
+ bool operator==(std::nullptr_t) {
+ return image_file_ == nullptr;
+ }
+
+ bool operator!=(std::nullptr_t) {
+ return image_file_ != nullptr;
+ }
+
+ File* operator->() const {
+ return image_file_.get();
+ }
+
+ bool WriteHeaderAndClose(const std::string& image_filename, const ImageHeader* image_header) {
+ // The header is uncompressed since it contains whether the image is compressed or not.
+ if (!image_file_->PwriteFully(image_header, sizeof(ImageHeader), 0)) {
+ PLOG(ERROR) << "Failed to write image file header " << image_filename;
+ return false;
+ }
+
+ // FlushCloseOrErase() takes care of erasing, so the destructor does not need
+ // to do that whether the FlushCloseOrErase() succeeds or fails.
+ std::unique_ptr<File> image_file = std::move(image_file_);
+ if (image_file->FlushCloseOrErase() != 0) {
+ PLOG(ERROR) << "Failed to flush and close image file " << image_filename;
+ return false;
+ }
+
+ return true;
+ }
+
+ private:
+ std::unique_ptr<File> image_file_;
+};
+
bool ImageWriter::Write(int image_fd,
const std::vector<const char*>& image_filenames,
const std::vector<const char*>& oat_filenames) {
@@ -651,10 +704,18 @@
CopyMetadata();
}
+ // Primary image header shall be written last for two reasons. First, this ensures
+ // that we shall not end up with a valid primary image and invalid secondary image.
+ // Second, its checksum shall include the checksums of the secondary images (XORed).
+ // This way only the primary image checksum needs to be checked to determine whether
+ // any of the images or oat files are out of date. (Oat file checksums are included
+ // in the image checksum calculation.)
+ ImageHeader* primary_header = reinterpret_cast<ImageHeader*>(image_infos_[0].image_.Begin());
+ ImageFileGuard primary_image_file;
for (size_t i = 0; i < image_filenames.size(); ++i) {
const char* image_filename = image_filenames[i];
ImageInfo& image_info = GetImageInfo(i);
- std::unique_ptr<File> image_file;
+ ImageFileGuard image_file;
if (image_fd != kInvalidFd) {
if (strlen(image_filename) == 0u) {
image_file.reset(new File(image_fd, unix_file::kCheckSafeUsage));
@@ -677,7 +738,6 @@
if (!compiler_options_.IsAppImage() && fchmod(image_file->Fd(), 0644) != 0) {
PLOG(ERROR) << "Failed to make image file world readable: " << image_filename;
- image_file->Erase();
return EXIT_FAILURE;
}
@@ -690,11 +750,11 @@
std::vector<uint8_t> compressed_data;
ArrayRef<const uint8_t> image_data =
MaybeCompressData(raw_image_data, image_storage_mode_, &compressed_data);
+ image_header->data_size_ = image_data.size(); // Fill in the data size.
// Write out the image + fields + methods.
if (!image_file->PwriteFully(image_data.data(), image_data.size(), sizeof(ImageHeader))) {
PLOG(ERROR) << "Failed to write image file data " << image_filename;
- image_file->Erase();
return false;
}
@@ -710,28 +770,25 @@
bitmap_section.Size(),
bitmap_position_in_file)) {
PLOG(ERROR) << "Failed to write image file bitmap " << image_filename;
- image_file->Erase();
return false;
}
int err = image_file->Flush();
if (err < 0) {
PLOG(ERROR) << "Failed to flush image file " << image_filename << " with result " << err;
- image_file->Erase();
return false;
}
- // Write header last in case the compiler gets killed in the middle of image writing.
- // We do not want to have a corrupted image with a valid header.
- // The header is uncompressed since it contains whether the image is compressed or not.
- image_header->data_size_ = image_data.size();
- if (!image_file->PwriteFully(reinterpret_cast<char*>(image_info.image_.Begin()),
- sizeof(ImageHeader),
- 0)) {
- PLOG(ERROR) << "Failed to write image file header " << image_filename;
- image_file->Erase();
- return false;
- }
+ // Calculate the image checksum.
+ uint32_t image_checksum = adler32(0L, Z_NULL, 0);
+ image_checksum = adler32(image_checksum,
+ reinterpret_cast<const uint8_t*>(image_header),
+ sizeof(ImageHeader));
+ image_checksum = adler32(image_checksum, image_data.data(), image_data.size());
+ image_checksum = adler32(image_checksum,
+ reinterpret_cast<const uint8_t*>(image_info.image_bitmap_->Begin()),
+ bitmap_section.Size());
+ image_header->SetImageChecksum(image_checksum);
if (VLOG_IS_ON(compiler)) {
size_t separately_written_section_size = bitmap_section.Size() + sizeof(ImageHeader);
@@ -748,11 +805,24 @@
CHECK_EQ(bitmap_position_in_file + bitmap_section.Size(),
static_cast<size_t>(image_file->GetLength()));
- if (image_file->FlushCloseOrErase() != 0) {
- PLOG(ERROR) << "Failed to flush and close image file " << image_filename;
- return false;
+ // Write header last in case the compiler gets killed in the middle of image writing.
+ // We do not want to have a corrupted image with a valid header.
+ // Delay the writing of the primary image header until after writing secondary images.
+ if (i == 0u) {
+ primary_image_file = std::move(image_file);
+ } else {
+ if (!image_file.WriteHeaderAndClose(image_filename, image_header)) {
+ return false;
+ }
+ // Update the primary image checksum with the secondary image checksum.
+ primary_header->SetImageChecksum(primary_header->GetImageChecksum() ^ image_checksum);
}
}
+ DCHECK(primary_image_file != nullptr);
+ if (!primary_image_file.WriteHeaderAndClose(image_filenames[0], primary_header)) {
+ return false;
+ }
+
return true;
}
@@ -3347,11 +3417,14 @@
size_t oat_loaded_size,
size_t oat_data_offset,
size_t oat_data_size) {
+ DCHECK_GE(oat_loaded_size, oat_data_offset);
+ DCHECK_GE(oat_loaded_size - oat_data_offset, oat_data_size);
+
const uint8_t* images_end = image_infos_.back().image_begin_ + image_infos_.back().image_size_;
+ DCHECK(images_end != nullptr); // Image space must be ready.
for (const ImageInfo& info : image_infos_) {
DCHECK_LE(info.image_begin_ + info.image_size_, images_end);
}
- DCHECK(images_end != nullptr); // Image space must be ready.
ImageInfo& cur_image_info = GetImageInfo(oat_index);
cur_image_info.oat_file_begin_ = images_end + cur_image_info.oat_offset_;
diff --git a/dex2oat/linker/image_writer.h b/dex2oat/linker/image_writer.h
index 3c377a3..8aabaa3 100644
--- a/dex2oat/linker/image_writer.h
+++ b/dex2oat/linker/image_writer.h
@@ -794,7 +794,7 @@
// Set of objects known to be dirty in the image. Can be nullptr if there are none.
const HashSet<std::string>* dirty_image_objects_;
- class ComputeLazyFieldsForClassesVisitor;
+ class ImageFileGuard;
class FixupClassVisitor;
class FixupRootVisitor;
class FixupVisitor;
diff --git a/dex2oat/linker/oat_writer.cc b/dex2oat/linker/oat_writer.cc
index 7f2877f..18528dc 100644
--- a/dex2oat/linker/oat_writer.cc
+++ b/dex2oat/linker/oat_writer.cc
@@ -99,13 +99,28 @@
return reinterpret_cast<const UnalignedDexFileHeader*>(raw_data);
}
-class ChecksumUpdatingOutputStream : public OutputStream {
+inline uint32_t CodeAlignmentSize(uint32_t header_offset, const CompiledMethod& compiled_method) {
+ // We want to align the code rather than the preheader.
+ uint32_t unaligned_code_offset = header_offset + sizeof(OatQuickMethodHeader);
+ uint32_t aligned_code_offset = compiled_method.AlignCode(unaligned_code_offset);
+ return aligned_code_offset - unaligned_code_offset;
+}
+
+} // anonymous namespace
+
+class OatWriter::ChecksumUpdatingOutputStream : public OutputStream {
public:
- ChecksumUpdatingOutputStream(OutputStream* out, OatHeader* oat_header)
- : OutputStream(out->GetLocation()), out_(out), oat_header_(oat_header) { }
+ ChecksumUpdatingOutputStream(OutputStream* out, OatWriter* writer)
+ : OutputStream(out->GetLocation()), out_(out), writer_(writer) { }
bool WriteFully(const void* buffer, size_t byte_count) override {
- oat_header_->UpdateChecksum(buffer, byte_count);
+ if (buffer != nullptr) {
+ const uint8_t* bytes = reinterpret_cast<const uint8_t*>(buffer);
+ uint32_t old_checksum = writer_->oat_checksum_;
+ writer_->oat_checksum_ = adler32(old_checksum, bytes, byte_count);
+ } else {
+ DCHECK_EQ(0U, byte_count);
+ }
return out_->WriteFully(buffer, byte_count);
}
@@ -119,18 +134,9 @@
private:
OutputStream* const out_;
- OatHeader* const oat_header_;
+ OatWriter* const writer_;
};
-inline uint32_t CodeAlignmentSize(uint32_t header_offset, const CompiledMethod& compiled_method) {
- // We want to align the code rather than the preheader.
- uint32_t unaligned_code_offset = header_offset + sizeof(OatQuickMethodHeader);
- uint32_t aligned_code_offset = compiled_method.AlignCode(unaligned_code_offset);
- return aligned_code_offset - unaligned_code_offset;
-}
-
-} // anonymous namespace
-
// Defines the location of the raw dex file to write.
class OatWriter::DexFileSource {
public:
@@ -379,6 +385,7 @@
vdex_dex_shared_data_offset_(0u),
vdex_verifier_deps_offset_(0u),
vdex_quickening_info_offset_(0u),
+ oat_checksum_(adler32(0L, Z_NULL, 0)),
code_size_(0u),
oat_size_(0u),
data_bimg_rel_ro_start_(0u),
@@ -675,7 +682,7 @@
oat_size_ = InitOatHeader(dchecked_integral_cast<uint32_t>(oat_dex_files_.size()),
key_value_store);
- ChecksumUpdatingOutputStream checksum_updating_rodata(oat_rodata, oat_header_.get());
+ ChecksumUpdatingOutputStream checksum_updating_rodata(oat_rodata, this);
std::unique_ptr<BufferedOutputStream> vdex_out =
std::make_unique<BufferedOutputStream>(std::make_unique<FileOutputStream>(vdex_file));
@@ -2349,7 +2356,7 @@
size_t relative_offset = current_offset - file_offset;
// Wrap out to update checksum with each write.
- ChecksumUpdatingOutputStream checksum_updating_out(out, oat_header_.get());
+ ChecksumUpdatingOutputStream checksum_updating_out(out, this);
out = &checksum_updating_out;
relative_offset = WriteClassOffsets(out, file_offset, relative_offset);
@@ -2658,7 +2665,7 @@
CHECK(write_state_ == WriteState::kWriteText);
// Wrap out to update checksum with each write.
- ChecksumUpdatingOutputStream checksum_updating_out(out, oat_header_.get());
+ ChecksumUpdatingOutputStream checksum_updating_out(out, this);
out = &checksum_updating_out;
SetMultiOatRelativePatcherAdjustment();
@@ -2694,7 +2701,7 @@
CHECK(write_state_ == WriteState::kWriteDataBimgRelRo);
// Wrap out to update checksum with each write.
- ChecksumUpdatingOutputStream checksum_updating_out(out, oat_header_.get());
+ ChecksumUpdatingOutputStream checksum_updating_out(out, this);
out = &checksum_updating_out;
const size_t file_offset = oat_data_offset_;
@@ -2800,11 +2807,18 @@
return true;
}
-bool OatWriter::WriteHeader(OutputStream* out, uint32_t image_file_location_oat_checksum) {
+bool OatWriter::WriteHeader(OutputStream* out, uint32_t boot_image_checksum) {
CHECK(write_state_ == WriteState::kWriteHeader);
- oat_header_->SetImageFileLocationOatChecksum(image_file_location_oat_checksum);
- oat_header_->UpdateChecksumWithHeaderData();
+ oat_header_->SetBootImageChecksum(boot_image_checksum);
+
+ // Update checksum with header data.
+ DCHECK_EQ(oat_header_->GetChecksum(), 0u); // For checksum calculation.
+ const uint8_t* header_begin = reinterpret_cast<const uint8_t*>(oat_header_.get());
+ const uint8_t* header_end = oat_header_->GetKeyValueStore() + oat_header_->GetKeyValueStoreSize();
+ uint32_t old_checksum = oat_checksum_;
+ oat_checksum_ = adler32(old_checksum, header_begin, header_end - header_begin);
+ oat_header_->SetChecksum(oat_checksum_);
const size_t file_offset = oat_data_offset_;
diff --git a/dex2oat/linker/oat_writer.h b/dex2oat/linker/oat_writer.h
index c049518..9cd2fd0 100644
--- a/dex2oat/linker/oat_writer.h
+++ b/dex2oat/linker/oat_writer.h
@@ -198,7 +198,7 @@
// Check the size of the written oat file.
bool CheckOatSize(OutputStream* out, size_t file_offset, size_t relative_offset);
// Write the oat header. This finalizes the oat file.
- bool WriteHeader(OutputStream* out, uint32_t image_file_location_oat_checksum);
+ bool WriteHeader(OutputStream* out, uint32_t boot_image_checksum);
// Returns whether the oat file has an associated image.
bool HasImage() const {
@@ -256,6 +256,7 @@
}
private:
+ class ChecksumUpdatingOutputStream;
class DexFileSource;
class OatClassHeader;
class OatClass;
@@ -400,6 +401,9 @@
// Offset of section holding quickening info inside Vdex.
size_t vdex_quickening_info_offset_;
+ // OAT checksum.
+ uint32_t oat_checksum_;
+
// Size of the .text segment.
size_t code_size_;
diff --git a/dex2oat/linker/oat_writer_test.cc b/dex2oat/linker/oat_writer_test.cc
index af02bfc..7450964 100644
--- a/dex2oat/linker/oat_writer_test.cc
+++ b/dex2oat/linker/oat_writer_test.cc
@@ -236,8 +236,7 @@
elf_writer->EndDataBimgRelRo(data_bimg_rel_ro);
}
- if (!oat_writer.WriteHeader(elf_writer->GetStream(),
- /*image_file_location_oat_checksum=*/ 42U)) {
+ if (!oat_writer.WriteHeader(elf_writer->GetStream(), /*boot_image_checksum=*/ 42u)) {
return false;
}
@@ -416,7 +415,7 @@
const OatHeader& oat_header = oat_file->GetOatHeader();
ASSERT_TRUE(oat_header.IsValid());
ASSERT_EQ(class_linker->GetBootClassPath().size(), oat_header.GetDexFileCount()); // core
- ASSERT_EQ(42U, oat_header.GetImageFileLocationOatChecksum());
+ ASSERT_EQ(42u, oat_header.GetBootImageChecksum());
ASSERT_TRUE(java_lang_dex_file_ != nullptr);
const DexFile& dex_file = *java_lang_dex_file_;
@@ -842,29 +841,5 @@
TestZipFileInputWithEmptyDex();
}
-TEST_F(OatTest, UpdateChecksum) {
- InstructionSet insn_set = InstructionSet::kX86;
- std::string error_msg;
- std::unique_ptr<const InstructionSetFeatures> insn_features(
- InstructionSetFeatures::FromVariant(insn_set, "default", &error_msg));
- ASSERT_TRUE(insn_features.get() != nullptr) << error_msg;
- std::unique_ptr<OatHeader> oat_header(OatHeader::Create(insn_set,
- insn_features.get(),
- 0u,
- nullptr));
- // The starting adler32 value is 1.
- EXPECT_EQ(1U, oat_header->GetChecksum());
-
- oat_header->UpdateChecksum(OatHeader::kOatMagic, sizeof(OatHeader::kOatMagic));
- EXPECT_EQ(64291151U, oat_header->GetChecksum());
-
- // Make sure that null data does not reset the checksum.
- oat_header->UpdateChecksum(nullptr, 0);
- EXPECT_EQ(64291151U, oat_header->GetChecksum());
-
- oat_header->UpdateChecksum(OatHeader::kOatMagic, sizeof(OatHeader::kOatMagic));
- EXPECT_EQ(216138397U, oat_header->GetChecksum());
-}
-
} // namespace linker
} // namespace art
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index e26ec95..dd1ff2a 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -473,8 +473,8 @@
GetQuickToInterpreterBridgeOffset);
#undef DUMP_OAT_HEADER_OFFSET
- os << "IMAGE FILE LOCATION OAT CHECKSUM:\n";
- os << StringPrintf("0x%08x\n\n", oat_header.GetImageFileLocationOatChecksum());
+ os << "BOOT IMAGE CHECKSUM:\n";
+ os << StringPrintf("0x%08x\n\n", oat_header.GetBootImageChecksum());
// Print the key-value store.
{
@@ -1771,27 +1771,27 @@
os << "IMAGE LOCATION: " << image_space_.GetImageLocation() << "\n\n";
- os << "IMAGE BEGIN: " << reinterpret_cast<void*>(image_header_.GetImageBegin()) << "\n\n";
+ os << "IMAGE BEGIN: " << reinterpret_cast<void*>(image_header_.GetImageBegin()) << "\n";
+ os << "IMAGE SIZE: " << image_header_.GetImageSize() << "\n";
+ os << "IMAGE CHECKSUM: " << std::hex << image_header_.GetImageChecksum() << std::dec << "\n\n";
- os << "IMAGE SIZE: " << image_header_.GetImageSize() << "\n\n";
+ os << "OAT CHECKSUM: " << StringPrintf("0x%08x\n\n", image_header_.GetOatChecksum()) << "\n";
+ os << "OAT FILE BEGIN:" << reinterpret_cast<void*>(image_header_.GetOatFileBegin()) << "\n";
+ os << "OAT DATA BEGIN:" << reinterpret_cast<void*>(image_header_.GetOatDataBegin()) << "\n";
+ os << "OAT DATA END:" << reinterpret_cast<void*>(image_header_.GetOatDataEnd()) << "\n";
+ os << "OAT FILE END:" << reinterpret_cast<void*>(image_header_.GetOatFileEnd()) << "\n\n";
+
+ os << "BOOT IMAGE BEGIN: " << reinterpret_cast<void*>(image_header_.GetBootImageBegin())
+ << "\n";
+ os << "BOOT IMAGE SIZE: " << image_header_.GetBootImageSize() << "\n";
+ os << "BOOT OAT BEGIN: " << reinterpret_cast<void*>(image_header_.GetBootOatBegin()) << "\n";
+ os << "BOOT OAT SIZE: " << image_header_.GetBootOatSize() << "\n\n";
for (size_t i = 0; i < ImageHeader::kSectionCount; ++i) {
auto section = static_cast<ImageHeader::ImageSections>(i);
os << "IMAGE SECTION " << section << ": " << image_header_.GetImageSection(section) << "\n\n";
}
- os << "OAT CHECKSUM: " << StringPrintf("0x%08x\n\n", image_header_.GetOatChecksum());
-
- os << "OAT FILE BEGIN:" << reinterpret_cast<void*>(image_header_.GetOatFileBegin()) << "\n\n";
-
- os << "OAT DATA BEGIN:" << reinterpret_cast<void*>(image_header_.GetOatDataBegin()) << "\n\n";
-
- os << "OAT DATA END:" << reinterpret_cast<void*>(image_header_.GetOatDataEnd()) << "\n\n";
-
- os << "OAT FILE END:" << reinterpret_cast<void*>(image_header_.GetOatFileEnd()) << "\n\n";
-
- os << "PATCH DELTA:" << image_header_.GetPatchDelta() << "\n\n";
-
{
os << "ROOTS: " << reinterpret_cast<void*>(image_header_.GetImageRoots().Ptr()) << "\n";
static_assert(arraysize(image_roots_descriptions_) ==
diff --git a/runtime/dexopt_test.cc b/runtime/dexopt_test.cc
index b11e368..f52a0f9 100644
--- a/runtime/dexopt_test.cc
+++ b/runtime/dexopt_test.cc
@@ -140,13 +140,13 @@
&error_msg));
ASSERT_TRUE(image_header != nullptr) << error_msg;
const OatHeader& oat_header = odex_file->GetOatHeader();
- uint32_t combined_checksum = image_header->GetOatChecksum();
+ uint32_t boot_image_checksum = image_header->GetImageChecksum();
if (CompilerFilter::DependsOnImageChecksum(filter)) {
if (with_alternate_image) {
- EXPECT_NE(combined_checksum, oat_header.GetImageFileLocationOatChecksum());
+ EXPECT_NE(boot_image_checksum, oat_header.GetBootImageChecksum());
} else {
- EXPECT_EQ(combined_checksum, oat_header.GetImageFileLocationOatChecksum());
+ EXPECT_EQ(boot_image_checksum, oat_header.GetBootImageChecksum());
}
}
}
diff --git a/runtime/image.cc b/runtime/image.cc
index 59ac283..f4c3fea 100644
--- a/runtime/image.cc
+++ b/runtime/image.cc
@@ -26,7 +26,7 @@
namespace art {
const uint8_t ImageHeader::kImageMagic[] = { 'a', 'r', 't', '\n' };
-const uint8_t ImageHeader::kImageVersion[] = { '0', '6', '7', '\0' }; // Added CRC32 intrinsic
+const uint8_t ImageHeader::kImageVersion[] = { '0', '6', '8', '\0' }; // Image checksums.
ImageHeader::ImageHeader(uint32_t image_begin,
uint32_t image_size,
@@ -46,6 +46,7 @@
size_t data_size)
: image_begin_(image_begin),
image_size_(image_size),
+ image_checksum_(0u),
oat_checksum_(oat_checksum),
oat_file_begin_(oat_file_begin),
oat_data_begin_(oat_data_begin),
@@ -55,7 +56,6 @@
boot_image_size_(boot_image_size),
boot_oat_begin_(boot_oat_begin),
boot_oat_size_(boot_oat_size),
- patch_delta_(0),
image_roots_(image_roots),
pointer_size_(pointer_size),
storage_mode_(storage_mode),
@@ -79,7 +79,6 @@
oat_data_begin_ += delta;
oat_data_end_ += delta;
oat_file_end_ += delta;
- patch_delta_ += delta;
RelocateImageObjects(delta);
RelocateImageMethods(delta);
}
@@ -115,9 +114,6 @@
if (oat_file_begin_ >= oat_data_begin_) {
return false;
}
- if (!IsAligned<kPageSize>(patch_delta_)) {
- return false;
- }
return true;
}
diff --git a/runtime/image.h b/runtime/image.h
index d925956..5245cea 100644
--- a/runtime/image.h
+++ b/runtime/image.h
@@ -96,6 +96,7 @@
ImageHeader()
: image_begin_(0U),
image_size_(0U),
+ image_checksum_(0u),
oat_checksum_(0U),
oat_file_begin_(0U),
oat_data_begin_(0U),
@@ -105,7 +106,6 @@
boot_image_size_(0U),
boot_oat_begin_(0U),
boot_oat_size_(0U),
- patch_delta_(0),
image_roots_(0U),
pointer_size_(0U),
storage_mode_(kDefaultStorageMode),
@@ -136,7 +136,15 @@
}
size_t GetImageSize() const {
- return static_cast<uint32_t>(image_size_);
+ return image_size_;
+ }
+
+ uint32_t GetImageChecksum() const {
+ return image_checksum_;
+ }
+
+ void SetImageChecksum(uint32_t image_checksum) {
+ image_checksum_ = image_checksum;
}
uint32_t GetOatChecksum() const {
@@ -171,14 +179,6 @@
return pointer_size_;
}
- int32_t GetPatchDelta() const {
- return patch_delta_;
- }
-
- void SetPatchDelta(int32_t patch_delta) {
- patch_delta_ = patch_delta;
- }
-
static std::string GetOatLocationFromImageLocation(const std::string& image) {
return GetLocationFromImageLocation(image, "oat");
}
@@ -395,6 +395,9 @@
// Image size, not page aligned.
uint32_t image_size_;
+ // Image file checksum (calculated with the checksum field set to 0).
+ uint32_t image_checksum_;
+
// Checksum of the oat file we link to for load time sanity check.
uint32_t oat_checksum_;
@@ -419,11 +422,6 @@
uint32_t boot_oat_begin_;
uint32_t boot_oat_size_;
- // TODO: We should probably insert a boot image checksum for app images.
-
- // The total delta that this image has been patched.
- int32_t patch_delta_;
-
// Absolute address of an Object[] of objects needed to reinitialize from an image.
uint32_t image_roots_;
diff --git a/runtime/oat.cc b/runtime/oat.cc
index 519eed7..e931b28 100644
--- a/runtime/oat.cc
+++ b/runtime/oat.cc
@@ -17,7 +17,6 @@
#include "oat.h"
#include <string.h>
-#include <zlib.h>
#include "android-base/stringprintf.h"
@@ -68,7 +67,7 @@
const InstructionSetFeatures* instruction_set_features,
uint32_t dex_file_count,
const SafeMap<std::string, std::string>* variable_data)
- : adler32_checksum_(adler32(0L, Z_NULL, 0)),
+ : oat_checksum_(0u),
instruction_set_(instruction_set),
instruction_set_features_bitmap_(instruction_set_features->AsBitmap()),
dex_file_count_(dex_file_count),
@@ -81,7 +80,7 @@
quick_imt_conflict_trampoline_offset_(0),
quick_resolution_trampoline_offset_(0),
quick_to_interpreter_bridge_offset_(0),
- image_file_location_oat_checksum_(0) {
+ boot_image_checksum_(0) {
// Don't want asserts in header as they would be checked in each file that includes it. But the
// fields are private, so we check inside a method.
static_assert(sizeof(magic_) == sizeof(kOatMagic),
@@ -143,47 +142,11 @@
uint32_t OatHeader::GetChecksum() const {
CHECK(IsValid());
- return adler32_checksum_;
+ return oat_checksum_;
}
-void OatHeader::UpdateChecksumWithHeaderData() {
- UpdateChecksum(&instruction_set_, sizeof(instruction_set_));
- UpdateChecksum(&instruction_set_features_bitmap_, sizeof(instruction_set_features_bitmap_));
- UpdateChecksum(&dex_file_count_, sizeof(dex_file_count_));
- UpdateChecksum(&image_file_location_oat_checksum_, sizeof(image_file_location_oat_checksum_));
-
- // Update checksum for variable data size.
- UpdateChecksum(&key_value_store_size_, sizeof(key_value_store_size_));
-
- // Update for data, if existing.
- if (key_value_store_size_ > 0U) {
- UpdateChecksum(&key_value_store_, key_value_store_size_);
- }
-
- UpdateChecksum(&executable_offset_, sizeof(executable_offset_));
- UpdateChecksum(&interpreter_to_interpreter_bridge_offset_,
- sizeof(interpreter_to_interpreter_bridge_offset_));
- UpdateChecksum(&interpreter_to_compiled_code_bridge_offset_,
- sizeof(interpreter_to_compiled_code_bridge_offset_));
- UpdateChecksum(&jni_dlsym_lookup_offset_, sizeof(jni_dlsym_lookup_offset_));
- UpdateChecksum(&quick_generic_jni_trampoline_offset_,
- sizeof(quick_generic_jni_trampoline_offset_));
- UpdateChecksum(&quick_imt_conflict_trampoline_offset_,
- sizeof(quick_imt_conflict_trampoline_offset_));
- UpdateChecksum(&quick_resolution_trampoline_offset_,
- sizeof(quick_resolution_trampoline_offset_));
- UpdateChecksum(&quick_to_interpreter_bridge_offset_,
- sizeof(quick_to_interpreter_bridge_offset_));
-}
-
-void OatHeader::UpdateChecksum(const void* data, size_t length) {
- DCHECK(IsValid());
- if (data != nullptr) {
- const uint8_t* bytes = reinterpret_cast<const uint8_t*>(data);
- adler32_checksum_ = adler32(adler32_checksum_, bytes, length);
- } else {
- DCHECK_EQ(0U, length);
- }
+void OatHeader::SetChecksum(uint32_t oat_checksum) {
+ oat_checksum_ = oat_checksum;
}
InstructionSet OatHeader::GetInstructionSet() const {
@@ -353,14 +316,14 @@
quick_to_interpreter_bridge_offset_ = offset;
}
-uint32_t OatHeader::GetImageFileLocationOatChecksum() const {
+uint32_t OatHeader::GetBootImageChecksum() const {
CHECK(IsValid());
- return image_file_location_oat_checksum_;
+ return boot_image_checksum_;
}
-void OatHeader::SetImageFileLocationOatChecksum(uint32_t image_file_location_oat_checksum) {
+void OatHeader::SetBootImageChecksum(uint32_t boot_image_checksum) {
CHECK(IsValid());
- image_file_location_oat_checksum_ = image_file_location_oat_checksum;
+ boot_image_checksum_ = boot_image_checksum;
}
uint32_t OatHeader::GetKeyValueStoreSize() const {
diff --git a/runtime/oat.h b/runtime/oat.h
index 3d6415e..ee46f42 100644
--- a/runtime/oat.h
+++ b/runtime/oat.h
@@ -31,8 +31,8 @@
class PACKED(4) OatHeader {
public:
static constexpr uint8_t kOatMagic[] = { 'o', 'a', 't', '\n' };
- // Last oat version changed reason: Remove interpreter alt tables.
- static constexpr uint8_t kOatVersion[] = { '1', '6', '3', '\0' };
+ // Last oat version changed reason: Image checksums.
+ static constexpr uint8_t kOatVersion[] = { '1', '6', '4', '\0' };
static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline";
static constexpr const char* kDebuggableKey = "debuggable";
@@ -56,8 +56,7 @@
std::string GetValidationErrorMessage() const;
const char* GetMagic() const;
uint32_t GetChecksum() const;
- void UpdateChecksumWithHeaderData();
- void UpdateChecksum(const void* data, size_t length);
+ void SetChecksum(uint32_t checksum);
uint32_t GetDexFileCount() const {
DCHECK(IsValid());
return dex_file_count_;
@@ -94,8 +93,8 @@
InstructionSet GetInstructionSet() const;
uint32_t GetInstructionSetFeaturesBitmap() const;
- uint32_t GetImageFileLocationOatChecksum() const;
- void SetImageFileLocationOatChecksum(uint32_t image_file_location_oat_checksum);
+ uint32_t GetBootImageChecksum() const;
+ void SetBootImageChecksum(uint32_t boot_image_checksum);
uint32_t GetKeyValueStoreSize() const;
const uint8_t* GetKeyValueStore() const;
@@ -123,7 +122,7 @@
uint8_t magic_[4];
uint8_t version_[4];
- uint32_t adler32_checksum_;
+ uint32_t oat_checksum_;
InstructionSet instruction_set_;
uint32_t instruction_set_features_bitmap_;
@@ -138,7 +137,7 @@
uint32_t quick_resolution_trampoline_offset_;
uint32_t quick_to_interpreter_bridge_offset_;
- uint32_t image_file_location_oat_checksum_;
+ uint32_t boot_image_checksum_;
uint32_t key_value_store_size_;
uint8_t key_value_store_[0]; // note variable width data at end
diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index a06be4c..6f32b98 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -419,7 +419,7 @@
// starts up.
LOG(WARNING) << "Dex location " << dex_location_ << " does not seem to include dex file. "
<< "Allow oat file use. This is potentially dangerous.";
- } else if (file.GetOatHeader().GetImageFileLocationOatChecksum() != image_info->oat_checksum) {
+ } else if (file.GetOatHeader().GetBootImageChecksum() != image_info->boot_image_checksum) {
VLOG(oat) << "Oat image checksum does not match image checksum.";
return kOatBootImageOutOfDate;
}
@@ -574,8 +574,7 @@
return nullptr;
}
- info->oat_checksum = image_header->GetOatChecksum();
- info->patch_delta = image_header->GetPatchDelta();
+ info->boot_image_checksum = image_header->GetImageChecksum();
return info;
}
diff --git a/runtime/oat_file_assistant.h b/runtime/oat_file_assistant.h
index 590ae22..09c9d3b 100644
--- a/runtime/oat_file_assistant.h
+++ b/runtime/oat_file_assistant.h
@@ -246,8 +246,7 @@
private:
struct ImageInfo {
- uint32_t oat_checksum = 0;
- int32_t patch_delta = 0;
+ uint32_t boot_image_checksum = 0;
std::string location;
static std::unique_ptr<ImageInfo> GetRuntimeImageInfo(InstructionSet isa,