diff options
Diffstat (limited to 'runtime/oat/oat_file_assistant.cc')
| -rw-r--r-- | runtime/oat/oat_file_assistant.cc | 268 |
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() { |