diff options
author | 2025-03-12 16:45:38 +0000 | |
---|---|---|
committer | 2025-03-20 16:33:35 -0700 | |
commit | 5045a8060a75ccccea94eac7363744ed63580ff9 (patch) | |
tree | eeb8a7d5d62bbdd9d5968153a9c414bff2b1d7fd | |
parent | b2d23dd55d0f1d16beb43a247d62bf09a8060665 (diff) |
Allow APEX versions in the OAT header to be overriden.
APEX versions are stringified mtime's of the APEXes installed on device,
for detecting samegrade placebos (go/samegrade-placebos). In the case of
Cloud Compilation, we cannot put the APEX versions in the OAT header
because the OAT file is generated on the server. Instead, we put the
APEX versions in a separate file (SDC file) when the SDM file is being
installed on device. Therefore, we need a way to override the APEX
versions in the OAT header.
This is a no-op change.
Bug: 377474232
Test: m test-art-host-gtest-art_runtime_tests
Change-Id: I69658b61942979ff7f56e4908ce3204bd0a2116e
-rw-r--r-- | runtime/class_linker.cc | 10 | ||||
-rw-r--r-- | runtime/gc/space/image_space.cc | 40 | ||||
-rw-r--r-- | runtime/gc/space/image_space.h | 10 | ||||
-rw-r--r-- | runtime/oat/oat.cc | 2 | ||||
-rw-r--r-- | runtime/oat/oat.h | 9 | ||||
-rw-r--r-- | runtime/oat/oat_file.cc | 9 | ||||
-rw-r--r-- | runtime/oat/oat_file.h | 6 | ||||
-rw-r--r-- | runtime/oat/oat_file_assistant.cc | 5 |
8 files changed, 64 insertions, 27 deletions
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 009d705caf..b14eaae51b 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -2240,8 +2240,16 @@ bool ClassLinker::AddImageSpace(gc::space::ImageSpace* space, return false; } + const char* oat_apex_versions = + oat_header->GetStoreValueByKeyUnsafe(OatHeader::kApexVersionsKey); + if (oat_apex_versions == nullptr) { + *error_msg = StringPrintf("Missing apex versions in special root in runtime image '%s'", + space->GetImageLocation().c_str()); + return false; + } + // Validate the apex versions. - if (!gc::space::ImageSpace::ValidateApexVersions(*oat_header, + if (!gc::space::ImageSpace::ValidateApexVersions(oat_apex_versions, runtime->GetApexVersions(), space->GetImageLocation(), error_msg)) { diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc index 97512bc79c..f557f3c8a9 100644 --- a/runtime/gc/space/image_space.cc +++ b/runtime/gc/space/image_space.cc @@ -26,6 +26,7 @@ #include <optional> #include <random> #include <string> +#include <string_view> #include <vector> #include "android-base/logging.h" @@ -3415,31 +3416,39 @@ void ImageSpace::Dump(std::ostream& os) const { << ",name=\"" << GetName() << "\"]"; } -bool ImageSpace::ValidateApexVersions(const OatHeader& oat_header, - const std::string& apex_versions, - const std::string& file_location, +bool ImageSpace::ValidateApexVersions(const OatFile& oat_file, + std::string_view runtime_apex_versions, std::string* error_msg) { // For a boot image, the key value store only exists in the first OAT file. Skip other OAT files. - if (oat_header.GetKeyValueStoreSize() == 0) { + if (oat_file.GetOatHeader().GetKeyValueStoreSize() == 0) { return true; } - const char* oat_apex_versions = oat_header.GetStoreValueByKey(OatHeader::kApexVersionsKey); - if (oat_apex_versions == nullptr) { + std::optional<std::string_view> oat_apex_versions = oat_file.GetApexVersions(); + if (!oat_apex_versions.has_value()) { *error_msg = StringPrintf("ValidateApexVersions failed to get APEX versions from oat file '%s'", - file_location.c_str()); + oat_file.GetLocation().c_str()); return false; } + + return ValidateApexVersions( + *oat_apex_versions, runtime_apex_versions, oat_file.GetLocation(), error_msg); +} + +bool ImageSpace::ValidateApexVersions(std::string_view oat_apex_versions, + std::string_view runtime_apex_versions, + const std::string& file_location, + std::string* error_msg) { // For a boot image, it can be generated from a subset of the bootclasspath. // For an app image, some dex files get compiled with a subset of the bootclasspath. // For such cases, the OAT APEX versions will be a prefix of the runtime APEX versions. - if (!apex_versions.starts_with(oat_apex_versions)) { - *error_msg = StringPrintf( - "ValidateApexVersions found APEX versions mismatch between oat file '%s' and the runtime " - "(Oat file: '%s', Runtime: '%s')", - file_location.c_str(), + if (!runtime_apex_versions.starts_with(oat_apex_versions)) { + *error_msg = ART_FORMAT( + "ValidateApexVersions found APEX versions mismatch between oat file '{}' and the runtime " + "(Oat file: '{}', Runtime: '{}')", + file_location, oat_apex_versions, - apex_versions.c_str()); + runtime_apex_versions); return false; } return true; @@ -3455,10 +3464,7 @@ bool ImageSpace::ValidateOatFile(const OatFile& oat_file, ArrayRef<const std::string> dex_filenames, ArrayRef<File> dex_files, const std::string& apex_versions) { - if (!ValidateApexVersions(oat_file.GetOatHeader(), - apex_versions, - oat_file.GetLocation(), - error_msg)) { + if (!ValidateApexVersions(oat_file, apex_versions, error_msg)) { return false; } diff --git a/runtime/gc/space/image_space.h b/runtime/gc/space/image_space.h index 266b1d5925..4d0ce8181e 100644 --- a/runtime/gc/space/image_space.h +++ b/runtime/gc/space/image_space.h @@ -260,9 +260,13 @@ class ImageSpace : public MemMapSpace { const std::string& image_location, bool boot_image_extension = false); - // Returns true if the APEX versions in the OAT header match the given APEX versions. - static bool ValidateApexVersions(const OatHeader& oat_header, - const std::string& apex_versions, + // Returns true if the APEX versions of the OAT file match the given APEX versions. + static bool ValidateApexVersions(const OatFile& oat_file, + std::string_view runtime_apex_versions, + std::string* error_msg); + + static bool ValidateApexVersions(std::string_view oat_apex_versions, + std::string_view runtime_apex_versions, const std::string& file_location, std::string* error_msg); diff --git a/runtime/oat/oat.cc b/runtime/oat/oat.cc index 840825cea8..9882b0fa51 100644 --- a/runtime/oat/oat.cc +++ b/runtime/oat/oat.cc @@ -373,7 +373,7 @@ const uint8_t* OatHeader::GetKeyValueStore() const { return key_value_store_; } -const char* OatHeader::GetStoreValueByKey(const char* key) const { +const char* OatHeader::GetStoreValueByKeyUnsafe(const char* key) const { std::string_view key_view(key); uint32_t offset = 0; diff --git a/runtime/oat/oat.h b/runtime/oat/oat.h index 0061c90da9..2069b569e3 100644 --- a/runtime/oat/oat.h +++ b/runtime/oat/oat.h @@ -164,7 +164,14 @@ class EXPORT PACKED(4) OatHeader { uint32_t GetKeyValueStoreSize() const; const uint8_t* GetKeyValueStore() const; - const char* GetStoreValueByKey(const char* key) const; + const char* GetStoreValueByKeyUnsafe(const char* key) const; + + const char* GetStoreValueByKey(const char* key) const { + // Do not get apex versions from the oat header directly. Use `OatFile::GetApexVersions` + // instead. + DCHECK_NE(std::string_view(key), kApexVersionsKey); + return GetStoreValueByKeyUnsafe(key); + } // Returns the next key-value pair, at the given offset. On success, updates `offset`. // The expected use case is to start the iteration with an offset initialized to zero and diff --git a/runtime/oat/oat_file.cc b/runtime/oat/oat_file.cc index 1ecad4abf9..3f72401f43 100644 --- a/runtime/oat/oat_file.cc +++ b/runtime/oat/oat_file.cc @@ -2586,4 +2586,13 @@ bool OatFile::IsBackedByVdexOnly() const { return oat_dex_files_storage_.size() >= 1 && oat_dex_files_storage_[0]->IsBackedByVdexOnly(); } +std::optional<std::string_view> OatFile::GetApexVersions() const { + if (override_apex_versions_.has_value()) { + return override_apex_versions_; + } + const char* oat_apex_versions = + GetOatHeader().GetStoreValueByKeyUnsafe(OatHeader::kApexVersionsKey); + return oat_apex_versions != nullptr ? std::make_optional(oat_apex_versions) : std::nullopt; +} + } // namespace art diff --git a/runtime/oat/oat_file.h b/runtime/oat/oat_file.h index 9e66e1d4a7..53f1d173d1 100644 --- a/runtime/oat/oat_file.h +++ b/runtime/oat/oat_file.h @@ -19,6 +19,7 @@ #include <list> #include <memory> +#include <optional> #include <string> #include <string_view> #include <vector> @@ -426,6 +427,8 @@ class OatFile { // Returns the mapping info of `dex_file` if found in the BcpBssInfo, or nullptr otherwise. const BssMappingInfo* FindBcpMappingInfo(const DexFile* dex_file) const; + std::optional<std::string_view> GetApexVersions() const; + protected: OatFile(const std::string& filename, bool executable); @@ -518,6 +521,9 @@ class OatFile { // by the `dex_filenames` parameter, in case the OatFile does not embed the dex code. std::vector<std::unique_ptr<const DexFile>> external_dex_files_; + // If set, overrides the APEX versions in the header. + std::optional<std::string> override_apex_versions_ = std::nullopt; + friend class gc::collector::FakeOatFile; // For modifying begin_ and end_. friend class OatClass; friend class art::OatDexFile; diff --git a/runtime/oat/oat_file_assistant.cc b/runtime/oat/oat_file_assistant.cc index f5d6832cff..8df8459589 100644 --- a/runtime/oat/oat_file_assistant.cc +++ b/runtime/oat/oat_file_assistant.cc @@ -491,10 +491,7 @@ OatFileAssistant::OatStatus OatFileAssistant::GivenOatFileStatus(const OatFile& return kOatBootImageOutOfDate; } if (!gc::space::ImageSpace::ValidateApexVersions( - file.GetOatHeader(), - GetOatFileAssistantContext()->GetApexVersions(), - file.GetLocation(), - error_msg)) { + file, GetOatFileAssistantContext()->GetApexVersions(), error_msg)) { return kOatBootImageOutOfDate; } } |