summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Jiakai Zhang <jiakaiz@google.com> 2025-03-12 16:45:38 +0000
committer Treehugger Robot <android-test-infra-autosubmit@system.gserviceaccount.com> 2025-03-20 16:33:35 -0700
commit5045a8060a75ccccea94eac7363744ed63580ff9 (patch)
treeeeb8a7d5d62bbdd9d5968153a9c414bff2b1d7fd
parentb2d23dd55d0f1d16beb43a247d62bf09a8060665 (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.cc10
-rw-r--r--runtime/gc/space/image_space.cc40
-rw-r--r--runtime/gc/space/image_space.h10
-rw-r--r--runtime/oat/oat.cc2
-rw-r--r--runtime/oat/oat.h9
-rw-r--r--runtime/oat/oat_file.cc9
-rw-r--r--runtime/oat/oat_file.h6
-rw-r--r--runtime/oat/oat_file_assistant.cc5
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;
}
}