summaryrefslogtreecommitdiff
path: root/runtime/oat_file_assistant.cc
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/oat_file_assistant.cc')
-rw-r--r--runtime/oat_file_assistant.cc167
1 files changed, 122 insertions, 45 deletions
diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index 914d2dd08b..81aaad580a 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -16,15 +16,16 @@
#include "oat_file_assistant.h"
-#include <sstream>
-
#include <sys/stat.h>
-#include "zlib.h"
+
+#include <memory>
+#include <sstream>
#include "android-base/file.h"
#include "android-base/stringprintf.h"
#include "android-base/strings.h"
-
+#include "arch/instruction_set.h"
+#include "base/array_ref.h"
#include "base/compiler_filter.h"
#include "base/file_utils.h"
#include "base/logging.h" // For VLOG.
@@ -47,6 +48,7 @@
#include "runtime.h"
#include "scoped_thread_state_change-inl.h"
#include "vdex_file.h"
+#include "zlib.h"
namespace art {
@@ -82,22 +84,24 @@ OatFileAssistant::OatFileAssistant(const char* dex_location,
const InstructionSet isa,
ClassLoaderContext* context,
bool load_executable,
- bool only_load_trusted_executable)
+ bool only_load_trusted_executable,
+ std::unique_ptr<RuntimeOptions> runtime_options)
: OatFileAssistant(dex_location,
isa,
context,
load_executable,
only_load_trusted_executable,
+ std::move(runtime_options),
/*vdex_fd=*/ -1,
/*oat_fd=*/ -1,
/*zip_fd=*/ -1) {}
-
OatFileAssistant::OatFileAssistant(const char* dex_location,
const InstructionSet isa,
ClassLoaderContext* context,
bool load_executable,
bool only_load_trusted_executable,
+ std::unique_ptr<RuntimeOptions> runtime_options,
int vdex_fd,
int oat_fd,
int zip_fd)
@@ -105,6 +109,7 @@ OatFileAssistant::OatFileAssistant(const char* dex_location,
isa_(isa),
load_executable_(load_executable),
only_load_trusted_executable_(only_load_trusted_executable),
+ runtime_options_(std::move(runtime_options)),
odex_(this, /*is_oat_location=*/ false),
oat_(this, /*is_oat_location=*/ true),
vdex_for_odex_(this, /*is_oat_location=*/ false),
@@ -127,12 +132,47 @@ OatFileAssistant::OatFileAssistant(const char* dex_location,
dex_location_.assign(dex_location);
+ Runtime* runtime = Runtime::Current();
+
+ if (load_executable_ && runtime == nullptr) {
+ LOG(WARNING) << "OatFileAssistant: Load executable specified, "
+ << "but no active runtime is found. Will not attempt to load executable.";
+ load_executable_ = false;
+ }
+
if (load_executable_ && isa != kRuntimeISA) {
LOG(WARNING) << "OatFileAssistant: Load executable specified, "
<< "but isa is not kRuntimeISA. Will not attempt to load executable.";
load_executable_ = false;
}
+ if (runtime_options_ == nullptr) {
+ CHECK(runtime != nullptr) << "runtime_options is not provided, and no active runtime is found.";
+
+ runtime_options_ = std::make_unique<RuntimeOptions>(RuntimeOptions{
+ .image_locations = runtime->GetImageLocations(),
+ .boot_class_path = runtime->GetBootClassPath(),
+ .boot_class_path_locations = runtime->GetBootClassPathLocations(),
+ .boot_class_path_fds = &runtime->GetBootClassPathFds(),
+ .use_jit_zygote = runtime->HasImageWithProfile(),
+ .deny_art_apex_data_files = runtime->DenyArtApexDataFiles(),
+ .apex_versions = runtime->GetApexVersions(),
+ });
+
+ if (isa == kRuntimeISA) {
+ // For the fast path that checks the OAT files against the runtime boot classpath checksums
+ // and boot classpath locations.
+ cached_boot_class_path_ = android::base::Join(runtime->GetBootClassPathLocations(), ":");
+ cached_boot_class_path_checksums_ = runtime->GetBootClassPathChecksums();
+ }
+ }
+
+ if (runtime == nullptr) {
+ // We need `MemMap` for mapping files. We don't have to initialize it when there is a runtime
+ // because the runtime initializes it.
+ MemMap::Init();
+ }
+
// Get the odex filename.
std::string error_msg;
std::string odex_file_name;
@@ -159,7 +199,11 @@ OatFileAssistant::OatFileAssistant(const char* dex_location,
if (!UseFdToReadFiles()) {
// Get the oat filename.
std::string oat_file_name;
- if (DexLocationToOatFilename(dex_location_, isa_, &oat_file_name, &error_msg)) {
+ if (DexLocationToOatFilename(dex_location_,
+ isa_,
+ runtime_options_->deny_art_apex_data_files,
+ &oat_file_name,
+ &error_msg)) {
oat_.Reset(oat_file_name, /*use_fd=*/ false);
std::string vdex_file_name = GetVdexFilename(oat_file_name);
vdex_for_oat_.Reset(vdex_file_name, UseFdToReadFiles(), zip_fd, vdex_fd, oat_fd);
@@ -199,11 +243,8 @@ bool OatFileAssistant::IsInBootClassPath() {
// specified by the user. This is okay, because the boot class path should
// be the same for all ISAs.
// TODO: Can we verify the boot class path is the same for all ISAs?
- Runtime* runtime = Runtime::Current();
- ClassLinker* class_linker = runtime->GetClassLinker();
- const auto& boot_class_path = class_linker->GetBootClassPath();
- for (size_t i = 0; i < boot_class_path.size(); i++) {
- if (boot_class_path[i]->GetLocation() == dex_location_) {
+ for (const std::string& boot_class_path_location : runtime_options_->boot_class_path_locations) {
+ if (boot_class_path_location == dex_location_) {
VLOG(oat) << "Dex location " << dex_location_ << " is in boot class path";
return true;
}
@@ -443,7 +484,8 @@ OatFileAssistant::OatStatus OatFileAssistant::GivenOatFileStatus(const OatFile&
VLOG(oat) << "Oat image checksum does not match image checksum.";
return kOatBootImageOutOfDate;
}
- if (!gc::space::ImageSpace::ValidateApexVersions(file, &error_msg)) {
+ if (!gc::space::ImageSpace::ValidateApexVersions(
+ file, runtime_options_->apex_versions, &error_msg)) {
VLOG(oat) << error_msg;
return kOatBootImageOutOfDate;
}
@@ -454,9 +496,8 @@ OatFileAssistant::OatStatus OatFileAssistant::GivenOatFileStatus(const OatFile&
// zip_file_only_contains_uncompressed_dex_ is only set during fetching the dex checksums.
DCHECK(required_dex_checksums_attempted_);
if (only_load_trusted_executable_ &&
- !LocationIsTrusted(file.GetLocation(), !Runtime::Current()->DenyArtApexDataFiles()) &&
- file.ContainsDexCode() &&
- zip_file_only_contains_uncompressed_dex_) {
+ !LocationIsTrusted(file.GetLocation(), !runtime_options_->deny_art_apex_data_files) &&
+ file.ContainsDexCode() && zip_file_only_contains_uncompressed_dex_) {
LOG(ERROR) << "Not loading "
<< dex_location_
<< ": oat file has dex code, but APK has uncompressed dex code";
@@ -474,6 +515,11 @@ bool OatFileAssistant::AnonymousDexVdexLocation(const std::vector<const DexFile:
InstructionSet isa,
/* out */ std::string* dex_location,
/* out */ std::string* vdex_filename) {
+ // Normally, OatFileAssistant should not assume that there is an active runtime. However, we
+ // reference the runtime here. This is okay because we are in a static function that is unrelated
+ // to other parts of OatFileAssistant.
+ DCHECK(Runtime::Current() != nullptr);
+
uint32_t checksum = adler32(0L, Z_NULL, 0);
for (const DexFile::Header* header : headers) {
checksum = adler32_combine(checksum,
@@ -571,13 +617,23 @@ bool OatFileAssistant::DexLocationToOatFilename(const std::string& location,
InstructionSet isa,
std::string* oat_filename,
std::string* error_msg) {
+ DCHECK(Runtime::Current() != nullptr);
+ return DexLocationToOatFilename(
+ location, isa, Runtime::Current()->DenyArtApexDataFiles(), oat_filename, error_msg);
+}
+
+bool OatFileAssistant::DexLocationToOatFilename(const std::string& location,
+ InstructionSet isa,
+ bool deny_art_apex_data_files,
+ std::string* oat_filename,
+ std::string* error_msg) {
CHECK(oat_filename != nullptr);
CHECK(error_msg != nullptr);
// Check if `location` could have an oat file in the ART APEX data directory. If so, and the
// file exists, use it.
const std::string apex_data_file = GetApexDataOdexFilename(location, isa);
- if (!apex_data_file.empty() && !Runtime::Current()->DenyArtApexDataFiles()) {
+ if (!apex_data_file.empty() && !deny_art_apex_data_files) {
if (OS::FileExists(apex_data_file.c_str(), /*check_file_type=*/true)) {
*oat_filename = apex_data_file;
return true;
@@ -656,26 +712,19 @@ bool OatFileAssistant::ValidateBootClassPathChecksums(const OatFile& oat_file) {
return true;
}
- Runtime* runtime = Runtime::Current();
std::string error_msg;
- bool result = false;
- // Fast path when the runtime boot classpath cheksums and boot classpath
- // locations directly match.
- if (oat_boot_class_path_checksums_view == runtime->GetBootClassPathChecksums() &&
- isa_ == kRuntimeISA &&
- oat_boot_class_path_view == android::base::Join(runtime->GetBootClassPathLocations(), ":")) {
- result = true;
- } else {
- result = gc::space::ImageSpace::VerifyBootClassPathChecksums(
- oat_boot_class_path_checksums_view,
- oat_boot_class_path_view,
- ArrayRef<const std::string>(runtime->GetImageLocations()),
- ArrayRef<const std::string>(runtime->GetBootClassPathLocations()),
- ArrayRef<const std::string>(runtime->GetBootClassPath()),
- ArrayRef<const int>(runtime->GetBootClassPathFds()),
- isa_,
- &error_msg);
- }
+ bool result = gc::space::ImageSpace::VerifyBootClassPathChecksums(
+ oat_boot_class_path_checksums_view,
+ oat_boot_class_path_view,
+ ArrayRef<const std::string>(runtime_options_->image_locations),
+ ArrayRef<const std::string>(runtime_options_->boot_class_path_locations),
+ ArrayRef<const std::string>(runtime_options_->boot_class_path),
+ runtime_options_->boot_class_path_fds != nullptr ?
+ ArrayRef<const int>(*runtime_options_->boot_class_path_fds) :
+ ArrayRef<const int>(),
+ isa_,
+ runtime_options_->apex_versions,
+ &error_msg);
if (!result) {
VLOG(oat) << "Failed to verify checksums of oat file " << oat_file.GetLocation()
<< " error: " << error_msg;
@@ -688,6 +737,31 @@ bool OatFileAssistant::ValidateBootClassPathChecksums(const OatFile& oat_file) {
return true;
}
+bool OatFileAssistant::IsPrimaryBootImageUsable() {
+ if (cached_is_boot_image_usable_.has_value()) {
+ return cached_is_boot_image_usable_.value();
+ }
+
+ if (runtime_options_->image_locations.empty() || runtime_options_->use_jit_zygote) {
+ return false;
+ }
+
+ std::string ignored_error_msg;
+ // Only verify the primary boot image.
+ cached_is_boot_image_usable_ = gc::space::ImageSpace::VerifyBootImages(
+ ArrayRef<const std::string>(runtime_options_->image_locations)
+ .SubArray(/*pos=*/0u, /*size=*/1u),
+ ArrayRef<const std::string>(runtime_options_->boot_class_path_locations),
+ ArrayRef<const std::string>(runtime_options_->boot_class_path),
+ runtime_options_->boot_class_path_fds != nullptr ?
+ ArrayRef<const int>(*runtime_options_->boot_class_path_fds) :
+ ArrayRef<const int>(),
+ isa_,
+ runtime_options_->apex_versions,
+ &ignored_error_msg);
+ return cached_is_boot_image_usable_.value();
+}
+
OatFileAssistant::OatFileInfo& OatFileAssistant::GetBestInfo() {
ScopedTrace trace("GetBestInfo");
// TODO(calin): Document the side effects of class loading when
@@ -840,7 +914,8 @@ const OatFile* OatFileAssistant::OatFileInfo::GetFile() {
return nullptr;
}
- if (LocationIsOnArtApexData(filename_) && Runtime::Current()->DenyArtApexDataFiles()) {
+ if (LocationIsOnArtApexData(filename_) &&
+ oat_file_assistant_->runtime_options_->deny_art_apex_data_files) {
LOG(WARNING) << "OatFileAssistant rejected file " << filename_
<< ": ART apexdata is untrusted.";
return nullptr;
@@ -961,7 +1036,7 @@ bool OatFileAssistant::OatFileInfo::CompilerFilterIsOkay(
file->GetOatHeader().GetStoreValueByKey(OatHeader::kBootClassPathChecksumsKey);
if (oat_boot_class_path_checksums != nullptr &&
!StartsWith(oat_boot_class_path_checksums, "i") &&
- !Runtime::Current()->HasImageWithProfile()) {
+ oat_file_assistant_->IsPrimaryBootImageUsable()) {
DCHECK(!file->GetOatHeader().RequiresImage());
return false;
}
@@ -1044,17 +1119,19 @@ std::unique_ptr<OatFile> OatFileAssistant::OatFileInfo::ReleaseFileForUse() {
// TODO(calin): we could provide a more refined status here
// (e.g. run from uncompressed apk, run with vdex but not oat etc). It will allow us to
// track more experiments but adds extra complexity.
-void OatFileAssistant::GetOptimizationStatus(
- const std::string& filename,
- InstructionSet isa,
- std::string* out_compilation_filter,
- std::string* out_compilation_reason) {
+void OatFileAssistant::GetOptimizationStatus(const std::string& filename,
+ InstructionSet isa,
+ std::string* out_compilation_filter,
+ std::string* out_compilation_reason,
+ std::unique_ptr<RuntimeOptions> runtime_options) {
// It may not be possible to load an oat file executable (e.g., selinux restrictions). Load
// non-executable and check the status manually.
OatFileAssistant oat_file_assistant(filename.c_str(),
isa,
- /* context= */ nullptr,
- /*load_executable=*/ false);
+ /*context=*/nullptr,
+ /*load_executable=*/false,
+ /*only_load_trusted_executable=*/false,
+ std::move(runtime_options));
std::string out_odex_location; // unused
std::string out_odex_status; // unused
oat_file_assistant.GetOptimizationStatus(