summaryrefslogtreecommitdiff
path: root/runtime/oat/oat_file_assistant.cc
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/oat/oat_file_assistant.cc')
-rw-r--r--runtime/oat/oat_file_assistant.cc268
1 files changed, 142 insertions, 126 deletions
diff --git a/runtime/oat/oat_file_assistant.cc b/runtime/oat/oat_file_assistant.cc
index 98e46644c8..e6f9cb15a3 100644
--- a/runtime/oat/oat_file_assistant.cc
+++ b/runtime/oat/oat_file_assistant.cc
@@ -21,6 +21,8 @@
#include <memory>
#include <optional>
#include <sstream>
+#include <string_view>
+#include <utility>
#include <vector>
#include "android-base/file.h"
@@ -49,6 +51,7 @@
#include "gc/space/image_space.h"
#include "image.h"
#include "oat.h"
+#include "oat/oat_file.h"
#include "oat_file_assistant_context.h"
#include "runtime.h"
#include "scoped_thread_state_change-inl.h"
@@ -420,55 +423,51 @@ bool OatFileAssistant::DexChecksumUpToDate(const OatFile& file, std::string* err
return true;
}
-OatFileAssistant::OatStatus OatFileAssistant::GivenOatFileStatus(const OatFile& file) {
+OatFileAssistant::OatStatus OatFileAssistant::GivenOatFileStatus(const OatFile& file,
+ /*out*/ std::string* error_msg) {
// Verify the ART_USE_READ_BARRIER state.
// TODO: Don't fully reject files due to read barrier state. If they contain
// compiled code and are otherwise okay, we should return something like
// kOatRelocationOutOfDate. If they don't contain compiled code, the read
// barrier state doesn't matter.
if (file.GetOatHeader().IsConcurrentCopying() != gUseReadBarrier) {
+ *error_msg = "Read barrier state mismatch";
return kOatCannotOpen;
}
// Verify the dex checksum.
- std::string error_msg;
- if (!DexChecksumUpToDate(file, &error_msg)) {
- LOG(ERROR) << error_msg;
+ if (!DexChecksumUpToDate(file, error_msg)) {
+ LOG(ERROR) << *error_msg;
return kOatDexOutOfDate;
}
CompilerFilter::Filter current_compiler_filter = file.GetCompilerFilter();
// Verify the image checksum
- if (file.IsBackedByVdexOnly()) {
- VLOG(oat) << "Image checksum test skipped for vdex file " << file.GetLocation();
- } else if (CompilerFilter::DependsOnImageChecksum(current_compiler_filter)) {
- if (!ValidateBootClassPathChecksums(file)) {
- VLOG(oat) << "Oat image checksum does not match image checksum.";
+ if (!file.IsBackedByVdexOnly() &&
+ CompilerFilter::DependsOnImageChecksum(current_compiler_filter)) {
+ if (!ValidateBootClassPathChecksums(file, error_msg)) {
return kOatBootImageOutOfDate;
}
if (!gc::space::ImageSpace::ValidateApexVersions(
file.GetOatHeader(),
GetOatFileAssistantContext()->GetApexVersions(),
file.GetLocation(),
- &error_msg)) {
- VLOG(oat) << error_msg;
+ error_msg)) {
return kOatBootImageOutOfDate;
}
- } else {
- VLOG(oat) << "Image checksum test skipped for compiler filter " << current_compiler_filter;
}
// The constraint is only enforced if the zip has uncompressed dex code.
if (only_load_trusted_executable_ &&
!LocationIsTrusted(file.GetLocation(), !GetRuntimeOptions().deny_art_apex_data_files) &&
file.ContainsDexCode() && ZipFileOnlyContainsUncompressedDex()) {
- LOG(ERROR) << "Not loading " << dex_location_
- << ": oat file has dex code, but APK has uncompressed dex code";
+ *error_msg = "Oat file has dex code, but APK has uncompressed dex code";
+ LOG(ERROR) << "Not loading " << dex_location_ << ": " << *error_msg;
return kOatDexOutOfDate;
}
- if (!ClassLoaderContextIsOkay(file)) {
+ if (!ClassLoaderContextIsOkay(file, error_msg)) {
return kOatContextOutOfDate;
}
@@ -762,29 +761,23 @@ bool OatFileAssistant::ValidateBootClassPathChecksums(OatFileAssistantContext* o
return true;
}
-bool OatFileAssistant::ValidateBootClassPathChecksums(const OatFile& oat_file) {
+bool OatFileAssistant::ValidateBootClassPathChecksums(const OatFile& oat_file,
+ /*out*/ std::string* error_msg) {
// Get the checksums and the BCP from the oat file.
const char* oat_boot_class_path_checksums =
oat_file.GetOatHeader().GetStoreValueByKey(OatHeader::kBootClassPathChecksumsKey);
const char* oat_boot_class_path =
oat_file.GetOatHeader().GetStoreValueByKey(OatHeader::kBootClassPathKey);
if (oat_boot_class_path_checksums == nullptr || oat_boot_class_path == nullptr) {
+ *error_msg = "Missing boot image information from oat file";
return false;
}
- std::string error_msg;
- bool result = ValidateBootClassPathChecksums(GetOatFileAssistantContext(),
- isa_,
- oat_boot_class_path_checksums,
- oat_boot_class_path,
- &error_msg);
- if (!result) {
- VLOG(oat) << "Failed to verify checksums of oat file " << oat_file.GetLocation()
- << " error: " << error_msg;
- return false;
- }
-
- return true;
+ return ValidateBootClassPathChecksums(GetOatFileAssistantContext(),
+ isa_,
+ oat_boot_class_path_checksums,
+ oat_boot_class_path,
+ error_msg);
}
bool OatFileAssistant::IsPrimaryBootImageUsable() {
@@ -794,12 +787,31 @@ bool OatFileAssistant::IsPrimaryBootImageUsable() {
OatFileAssistant::OatFileInfo& OatFileAssistant::GetBestInfo() {
ScopedTrace trace("GetBestInfo");
+ auto log_status = [&](std::string_view location, OatFileInfo* info) {
+ if (!VLOG_IS_ON(oat)) {
+ return;
+ }
+ std::string error_msg;
+ OatStatus status = info->Status(&error_msg);
+ std::string message = ART_FORMAT(
+ "GetBestInfo: {} ({}) is {}", location, info->DisplayFilename(), fmt::streamed(status));
+ const OatFile* file = info->GetFile();
+ if (file != nullptr) {
+ message += ART_FORMAT(" with filter '{}' executable '{}'",
+ fmt::streamed(file->GetCompilerFilter()),
+ file->IsExecutable());
+ }
+ if (!info->IsUseable()) {
+ message += ": " + error_msg;
+ }
+ VLOG(oat) << message;
+ };
+
// If the oat location is useable, take it. This must be an app on a readonly filesystem
// (typically, a system app or an incremental app). This must be prioritized over the odex
// location, because the odex location probably has the dexpreopt artifacts.
if (oat_.FileExists()) {
- VLOG(oat) << ART_FORMAT("GetBestInfo checking odex in dalvik-cache ({})",
- oat_.DisplayFilename());
+ log_status("odex in dalvik-cache", &oat_);
if (oat_.IsUseable()) {
return oat_;
}
@@ -807,8 +819,7 @@ OatFileAssistant::OatFileInfo& OatFileAssistant::GetBestInfo() {
// The odex location, which is the most common.
if (odex_.FileExists()) {
- VLOG(oat) << ART_FORMAT("GetBestInfo checking odex next to the dex file ({})",
- odex_.DisplayFilename());
+ log_status("odex next to the dex file", &odex_);
if (odex_.IsUseable()) {
return odex_;
}
@@ -816,8 +827,7 @@ OatFileAssistant::OatFileInfo& OatFileAssistant::GetBestInfo() {
// No odex/oat available, look for a useable vdex file.
if (vdex_for_oat_.FileExists()) {
- VLOG(oat) << ART_FORMAT("GetBestInfo checking vdex in dalvik-cache ({})",
- vdex_for_oat_.DisplayFilename());
+ log_status("vdex in dalvik-cache", &vdex_for_oat_);
if (vdex_for_oat_.IsUseable()) {
return vdex_for_oat_;
}
@@ -832,14 +842,14 @@ OatFileAssistant::OatFileInfo& OatFileAssistant::GetBestInfo() {
// A .dm file may be available, look for it.
if (dm_.FileExists()) {
- VLOG(oat) << ART_FORMAT("GetBestInfo checking dm ({})", dm_.DisplayFilename());
+ log_status("dm", &dm_);
if (dm_.IsUseable()) {
return dm_;
}
}
// No usable artifact. Pick the odex if it exists, or the oat if not.
- VLOG(oat) << "GetBestInfo no usable artifacts";
+ VLOG(oat) << ART_FORMAT("GetBestInfo: {} has no usable artifacts", dex_location_);
return (odex_.Status() == kOatCannotOpen) ? oat_ : odex_;
}
@@ -886,20 +896,22 @@ bool OatFileAssistant::OatFileInfo::IsUseable() {
}
}
-OatFileAssistant::OatStatus OatFileAssistant::OatFileInfo::Status() {
+OatFileAssistant::OatStatus OatFileAssistant::OatFileInfo::Status(/*out*/ std::string* error_msg) {
ScopedTrace trace("Status");
- if (!status_attempted_) {
- status_attempted_ = true;
- const OatFile* file = GetFile();
+ if (!status_.has_value()) {
+ std::string temp_error_msg;
+ const OatFile* file = GetFile(&temp_error_msg);
if (file == nullptr) {
- status_ = kOatCannotOpen;
+ status_ = std::make_pair(kOatCannotOpen, std::move(temp_error_msg));
} else {
- status_ = oat_file_assistant_->GivenOatFileStatus(*file);
- VLOG(oat) << file->GetLocation() << " is " << status_ << " with filter "
- << file->GetCompilerFilter();
+ status_ = std::make_pair(oat_file_assistant_->GivenOatFileStatus(*file, &temp_error_msg),
+ std::move(temp_error_msg));
}
}
- return status_;
+ if (error_msg != nullptr) {
+ *error_msg = status_->second;
+ }
+ return status_->first;
}
OatFileAssistant::DexOptNeeded OatFileAssistant::OatFileInfo::GetDexOptNeeded(
@@ -939,107 +951,110 @@ bool OatFileAssistant::OatFileInfo::FileExists() const {
return use_fd_ || (!filename_.empty() && OS::FileExists(filename_.c_str()));
}
-const OatFile* OatFileAssistant::OatFileInfo::GetFile() {
+const OatFile* OatFileAssistant::OatFileInfo::GetFile(/*out*/ std::string* error_msg) {
CHECK(!file_released_) << "GetFile called after oat file released.";
- if (load_attempted_) {
- return file_.get();
- }
- load_attempted_ = true;
if (!filename_provided_) {
return nullptr;
}
- if (LocationIsOnArtApexData(filename_) &&
- oat_file_assistant_->GetRuntimeOptions().deny_art_apex_data_files) {
- LOG(WARNING) << "OatFileAssistant rejected file " << filename_
- << ": ART apexdata is untrusted.";
- return nullptr;
+ if (!file_.has_value()) {
+ if (LocationIsOnArtApexData(filename_) &&
+ oat_file_assistant_->GetRuntimeOptions().deny_art_apex_data_files) {
+ file_ = std::make_pair(nullptr, "ART apexdata is untrusted");
+ LOG(WARNING) << "OatFileAssistant rejected file " << filename_ << ": " << file_->second;
+ } else {
+ std::string temp_error_msg;
+ file_ = std::make_pair(LoadFile(&temp_error_msg), std::move(temp_error_msg));
+ }
}
- std::string error_msg;
- bool executable = oat_file_assistant_->load_executable_;
+ if (error_msg != nullptr) {
+ *error_msg = file_->second;
+ }
+ return file_->first.get();
+}
+
+std::unique_ptr<OatFile> OatFileAssistant::OatFileInfo::LoadFile(std::string* error_msg) const {
if (filename_.ends_with(kVdexExtension)) {
- executable = false;
// Check to see if there is a vdex file we can make use of.
std::unique_ptr<VdexFile> vdex;
if (use_fd_) {
- if (vdex_fd_ >= 0) {
- struct stat s;
- int rc = TEMP_FAILURE_RETRY(fstat(vdex_fd_, &s));
- if (rc == -1) {
- error_msg = StringPrintf("Failed getting length of the vdex file %s.", strerror(errno));
- } else {
- vdex = VdexFile::Open(vdex_fd_,
- s.st_size,
- filename_,
- /*low_4gb=*/false,
- &error_msg);
- }
+ if (vdex_fd_ < 0) {
+ *error_msg = "vdex_fd not provided";
+ return nullptr;
+ }
+ struct stat s;
+ if (fstat(vdex_fd_, &s) < 0) {
+ *error_msg = ART_FORMAT("Failed getting length of the vdex file: {}", strerror(errno));
+ return nullptr;
}
+ vdex = VdexFile::Open(vdex_fd_,
+ s.st_size,
+ filename_,
+ /*low_4gb=*/false,
+ error_msg);
} else {
vdex = VdexFile::Open(filename_,
/*low_4gb=*/false,
- &error_msg);
+ error_msg);
}
if (vdex == nullptr) {
- VLOG(oat) << "unable to open vdex file " << filename_ << ": " << error_msg;
- } else {
- file_.reset(OatFile::OpenFromVdex(zip_fd_,
- std::move(vdex),
- oat_file_assistant_->dex_location_,
- oat_file_assistant_->context_,
- &error_msg));
+ *error_msg = ART_FORMAT("Unable to open vdex file: {}", *error_msg);
+ return nullptr;
}
+ return std::unique_ptr<OatFile>(OatFile::OpenFromVdex(zip_fd_,
+ std::move(vdex),
+ oat_file_assistant_->dex_location_,
+ oat_file_assistant_->context_,
+ error_msg));
} else if (filename_.ends_with(kDmExtension)) {
- executable = false;
// Check to see if there is a vdex file we can make use of.
- std::unique_ptr<ZipArchive> dm_file(ZipArchive::Open(filename_.c_str(), &error_msg));
- if (dm_file != nullptr) {
- std::unique_ptr<VdexFile> vdex(VdexFile::OpenFromDm(filename_, *dm_file, &error_msg));
- if (vdex != nullptr) {
- file_.reset(OatFile::OpenFromVdex(zip_fd_,
- std::move(vdex),
- oat_file_assistant_->dex_location_,
- oat_file_assistant_->context_,
- &error_msg));
- }
+ std::unique_ptr<ZipArchive> dm_file(ZipArchive::Open(filename_.c_str(), error_msg));
+ if (dm_file == nullptr) {
+ return nullptr;
+ }
+ std::unique_ptr<VdexFile> vdex(VdexFile::OpenFromDm(filename_, *dm_file, error_msg));
+ if (vdex == nullptr) {
+ return nullptr;
}
+ return std::unique_ptr<OatFile>(OatFile::OpenFromVdex(/*zip_fd=*/-1,
+ std::move(vdex),
+ oat_file_assistant_->dex_location_,
+ oat_file_assistant_->context_,
+ error_msg));
} else {
+ bool executable = oat_file_assistant_->load_executable_;
if (executable && oat_file_assistant_->only_load_trusted_executable_) {
executable = LocationIsTrusted(filename_, /*trust_art_apex_data_files=*/true);
}
- VLOG(oat) << "Loading " << filename_ << " with executable: " << executable;
+
if (use_fd_) {
- if (oat_fd_ >= 0 && vdex_fd_ >= 0) {
- ArrayRef<const std::string> dex_locations(&oat_file_assistant_->dex_location_,
- /*size=*/1u);
- file_.reset(OatFile::Open(zip_fd_,
- vdex_fd_,
- oat_fd_,
- filename_,
- executable,
- /*low_4gb=*/false,
- dex_locations,
- /*dex_files=*/{},
- /*reservation=*/nullptr,
- &error_msg));
+ if (oat_fd_ < 0 || vdex_fd_ < 0) {
+ *error_msg = "oat_fd or vdex_fd not provided";
+ return nullptr;
}
+ ArrayRef<const std::string> dex_locations(&oat_file_assistant_->dex_location_,
+ /*size=*/1u);
+ return std::unique_ptr<OatFile>(OatFile::Open(zip_fd_,
+ vdex_fd_,
+ oat_fd_,
+ filename_,
+ executable,
+ /*low_4gb=*/false,
+ dex_locations,
+ /*dex_files=*/{},
+ /*reservation=*/nullptr,
+ error_msg));
} else {
- file_.reset(OatFile::Open(/*zip_fd=*/-1,
- filename_,
- filename_,
- executable,
- /*low_4gb=*/false,
- oat_file_assistant_->dex_location_,
- &error_msg));
+ return std::unique_ptr<OatFile>(OatFile::Open(/*zip_fd=*/-1,
+ filename_,
+ filename_,
+ executable,
+ /*low_4gb=*/false,
+ oat_file_assistant_->dex_location_,
+ error_msg));
}
}
- if (file_.get() == nullptr) {
- VLOG(oat) << "OatFileAssistant test for existing oat file " << filename_ << ": " << error_msg;
- } else {
- VLOG(oat) << "Successfully loaded " << filename_ << " with executable: " << executable;
- }
- return file_.get();
}
bool OatFileAssistant::OatFileInfo::ShouldRecompileForFilter(CompilerFilter::Filter target,
@@ -1103,7 +1118,8 @@ bool OatFileAssistant::OatFileInfo::ShouldRecompileForFilter(CompilerFilter::Fil
return false;
}
-bool OatFileAssistant::ClassLoaderContextIsOkay(const OatFile& oat_file) const {
+bool OatFileAssistant::ClassLoaderContextIsOkay(const OatFile& oat_file,
+ /*out*/ std::string* error_msg) const {
if (context_ == nullptr) {
// The caller requests to skip the check.
return true;
@@ -1125,9 +1141,10 @@ bool OatFileAssistant::ClassLoaderContextIsOkay(const OatFile& oat_file) const {
/*verify_names=*/true,
/*verify_checksums=*/true);
if (matches == ClassLoaderContext::VerificationResult::kMismatch) {
- VLOG(oat) << "ClassLoaderContext check failed. Context was " << oat_file.GetClassLoaderContext()
- << ". The expected context is "
- << context_->EncodeContextForOatFile(android::base::Dirname(dex_location_));
+ *error_msg =
+ ART_FORMAT("ClassLoaderContext check failed. Context was {}. The expected context is {}",
+ oat_file.GetClassLoaderContext(),
+ context_->EncodeContextForOatFile(android::base::Dirname(dex_location_)));
return false;
}
return true;
@@ -1139,9 +1156,8 @@ bool OatFileAssistant::OatFileInfo::IsExecutable() {
}
void OatFileAssistant::OatFileInfo::Reset() {
- load_attempted_ = false;
- file_.reset();
- status_attempted_ = false;
+ file_ = std::nullopt;
+ status_ = std::nullopt;
}
void OatFileAssistant::OatFileInfo::Reset(
@@ -1157,7 +1173,7 @@ void OatFileAssistant::OatFileInfo::Reset(
std::unique_ptr<OatFile> OatFileAssistant::OatFileInfo::ReleaseFile() {
file_released_ = true;
- return std::move(file_);
+ return std::move(file_->first);
}
std::unique_ptr<OatFile> OatFileAssistant::OatFileInfo::ReleaseFileForUse() {