summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libdexfile/dex/art_dex_file_loader.cc4
-rw-r--r--runtime/class_loader_context.cc5
-rw-r--r--runtime/oat_file_assistant.cc43
-rw-r--r--runtime/oat_file_assistant.h9
-rw-r--r--runtime/oat_file_assistant_test.cc97
-rw-r--r--runtime/oat_file_manager.cc57
6 files changed, 180 insertions, 35 deletions
diff --git a/libdexfile/dex/art_dex_file_loader.cc b/libdexfile/dex/art_dex_file_loader.cc
index 971b99c588..62014aa67f 100644
--- a/libdexfile/dex/art_dex_file_loader.cc
+++ b/libdexfile/dex/art_dex_file_loader.cc
@@ -431,6 +431,10 @@ std::unique_ptr<const DexFile> ArtDexFileLoader::OpenOneDexFileFromZip(
}
}
+ ScopedTrace map_extract_trace(StringPrintf("Mapped=%s Extracted=%s",
+ map.IsValid() ? "true" : "false",
+ map.IsValid() ? "false" : "true")); // this is redundant but much easier to read in traces.
+
if (!map.IsValid()) {
// Default path for compressed ZIP entries,
// and fallback for stored ZIP entries.
diff --git a/runtime/class_loader_context.cc b/runtime/class_loader_context.cc
index 5b99add68b..929cf8c31d 100644
--- a/runtime/class_loader_context.cc
+++ b/runtime/class_loader_context.cc
@@ -26,6 +26,7 @@
#include "base/dchecked_vector.h"
#include "base/file_utils.h"
#include "base/stl_util.h"
+#include "base/systrace.h"
#include "class_linker.h"
#include "class_loader_utils.h"
#include "class_root-inl.h"
@@ -1177,8 +1178,9 @@ bool ClassLoaderContext::CreateInfoFromClassLoader(
std::unique_ptr<ClassLoaderContext> ClassLoaderContext::CreateContextForClassLoader(
jobject class_loader,
jobjectArray dex_elements) {
- CHECK(class_loader != nullptr);
+ ScopedTrace trace(__FUNCTION__);
+ CHECK(class_loader != nullptr);
ScopedObjectAccess soa(Thread::Current());
StackHandleScope<2> hs(soa.Self());
Handle<mirror::ClassLoader> h_class_loader =
@@ -1229,6 +1231,7 @@ ClassLoaderContext::VerificationResult ClassLoaderContext::VerifyClassLoaderCont
const std::string& context_spec,
bool verify_names,
bool verify_checksums) const {
+ ScopedTrace trace(__FUNCTION__);
if (verify_names || verify_checksums) {
DCHECK(dex_files_state_ == kDexFilesChecksumsRead || dex_files_state_ == kDexFilesOpened)
<< "dex_files_state_=" << dex_files_state_;
diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index 4cd1f1d04f..97254d223d 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -951,34 +951,63 @@ void OatFileAssistant::GetOptimizationStatus(
// 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, /*load_executable=*/ false);
- std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
+ std::string out_odex_location; // unused
+ std::string out_odex_status; // unused
+ oat_file_assistant.GetOptimizationStatus(
+ &out_odex_location,
+ out_compilation_filter,
+ out_compilation_reason,
+ &out_odex_status);
+}
+
+void OatFileAssistant::GetOptimizationStatus(
+ std::string* out_odex_location,
+ std::string* out_compilation_filter,
+ std::string* out_compilation_reason,
+ std::string* out_odex_status) {
+ OatFileInfo& oat_file_info = GetBestInfo();
+ const OatFile* oat_file = GetBestInfo().GetFile();
if (oat_file == nullptr) {
+ *out_odex_location = "error";
*out_compilation_filter = "run-from-apk";
*out_compilation_reason = "unknown";
+ // This mostly happens when we cannot open the oat file.
+ // Note that it's different than kOatCannotOpen.
+ // TODO: The design of getting the BestInfo is not ideal,
+ // as it's not very clear what's the difference between
+ // a nullptr and kOatcannotOpen. The logic should be revised
+ // and improved.
+ *out_odex_status = "io-error-no-oat";
return;
}
- OatStatus status = oat_file_assistant.GivenOatFileStatus(*oat_file);
+ *out_odex_location = oat_file->GetLocation();
+ OatStatus status = oat_file_info.Status();
const char* reason = oat_file->GetCompilationReason();
*out_compilation_reason = reason == nullptr ? "unknown" : reason;
switch (status) {
- case OatStatus::kOatUpToDate:
+ case kOatUpToDate:
*out_compilation_filter = CompilerFilter::NameOfFilter(oat_file->GetCompilerFilter());
+ *out_odex_status = "up-to-date";
return;
case kOatCannotOpen: // This should never happen, but be robust.
*out_compilation_filter = "error";
*out_compilation_reason = "error";
+ // This mostly happens when we cannot open the vdex file,
+ // or the file is corrupt.
+ *out_odex_status = "io-error-or-corruption";
return;
- // kOatBootImageOutOfDate - The oat file is up to date with respect to the
- // dex file, but is out of date with respect to the boot image.
case kOatBootImageOutOfDate:
- FALLTHROUGH_INTENDED;
+ *out_compilation_filter = "run-from-apk-fallback";
+ *out_odex_status = "boot-image-more-recent";
+ return;
+
case kOatDexOutOfDate:
- DCHECK(oat_file_assistant.HasDexFiles());
*out_compilation_filter = "run-from-apk-fallback";
+ *out_odex_status = "apk-more-recent";
return;
}
LOG(FATAL) << "Unreachable";
diff --git a/runtime/oat_file_assistant.h b/runtime/oat_file_assistant.h
index 51f58ad342..19c625b84a 100644
--- a/runtime/oat_file_assistant.h
+++ b/runtime/oat_file_assistant.h
@@ -165,13 +165,22 @@ class OatFileAssistant {
// Computes the optimization status of the given dex file. The result is
// returned via the two output parameters.
+ // - out_odex_location: the location of the (best) odex that will be used
+ // for loading. See GetBestInfo().
// - out_compilation_filter: the level of optimizations (compiler filter)
// - out_compilation_reason: the optimization reason. The reason might
// be "unknown" if the compiler artifacts were not annotated during optimizations.
+ // - out_odex_status: a human readable refined status of the validity of the odex file.
+ // E.g. up-to-date, boot-image-more-recent, apk-more-recent.
//
// This method will try to mimic the runtime effect of loading the dex file.
// For example, if there is no usable oat file, the compiler filter will be set
// to "run-from-apk".
+ void GetOptimizationStatus(std::string* out_odex_location,
+ std::string* out_compilation_filter,
+ std::string* out_compilation_reason,
+ std::string* out_odex_status);
+
static void GetOptimizationStatus(const std::string& filename,
InstructionSet isa,
std::string* out_compilation_filter,
diff --git a/runtime/oat_file_assistant_test.cc b/runtime/oat_file_assistant_test.cc
index a1aa6433d5..902e5afdc3 100644
--- a/runtime/oat_file_assistant_test.cc
+++ b/runtime/oat_file_assistant_test.cc
@@ -44,23 +44,49 @@ namespace art {
class OatFileAssistantTest : public DexoptTest {
public:
- void VerifyOptimizationStatus(const std::string& file,
+ void VerifyOptimizationStatus(OatFileAssistant* assistant,
+ const std::string& file,
const std::string& expected_filter,
- const std::string& expected_reason) {
- std::string compilation_filter;
- std::string compilation_reason;
- OatFileAssistant::GetOptimizationStatus(
- file, kRuntimeISA, &compilation_filter, &compilation_reason);
+ const std::string& expected_reason,
+ const std::string& expected_odex_status) {
+ // Verify the static methods (called from PM for dexOptNeeded).
+ std::string compilation_filter1;
+ std::string compilation_reason1;
- ASSERT_EQ(expected_filter, compilation_filter);
- ASSERT_EQ(expected_reason, compilation_reason);
+ OatFileAssistant::GetOptimizationStatus(
+ file, kRuntimeISA, &compilation_filter1, &compilation_reason1);
+
+ ASSERT_EQ(expected_filter, compilation_filter1);
+ ASSERT_EQ(expected_reason, compilation_reason1);
+
+ // Verify the instance methods (called at runtime for systrace).
+ std::string odex_location2; // ignored
+ std::string compilation_filter2;
+ std::string compilation_reason2;
+ std::string odex_status2;
+
+ assistant->GetOptimizationStatus(
+ &odex_location2,
+ &compilation_filter2,
+ &compilation_reason2,
+ &odex_status2);
+
+ ASSERT_EQ(expected_filter, compilation_filter2);
+ ASSERT_EQ(expected_reason, compilation_reason2);
+ ASSERT_EQ(expected_odex_status, odex_status2);
}
- void VerifyOptimizationStatus(const std::string& file,
+ void VerifyOptimizationStatus(OatFileAssistant* assistant,
+ const std::string& file,
CompilerFilter::Filter expected_filter,
- const std::string& expected_reason) {
+ const std::string& expected_reason,
+ const std::string& expected_odex_status) {
VerifyOptimizationStatus(
- file, CompilerFilter::NameOfFilter(expected_filter), expected_reason);
+ assistant,
+ file,
+ CompilerFilter::NameOfFilter(expected_filter),
+ expected_reason,
+ expected_odex_status);
}
void InsertNewBootClasspathEntry() {
@@ -244,7 +270,12 @@ TEST_F(OatFileAssistantTest, DexNoOat) {
EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
EXPECT_TRUE(oat_file_assistant.HasDexFiles());
- VerifyOptimizationStatus(dex_location, "run-from-apk", "unknown");
+ VerifyOptimizationStatus(
+ &oat_file_assistant,
+ dex_location,
+ "run-from-apk",
+ "unknown",
+ "io-error-no-oat");
}
// Case: We have no DEX file and no OAT file.
@@ -289,7 +320,12 @@ TEST_F(OatFileAssistantTest, OdexUpToDate) {
EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
EXPECT_TRUE(oat_file_assistant.HasDexFiles());
- VerifyOptimizationStatus(dex_location, CompilerFilter::kSpeed, "install");
+ VerifyOptimizationStatus(
+ &oat_file_assistant,
+ dex_location,
+ CompilerFilter::kSpeed,
+ "install",
+ "up-to-date");
}
// Case: We have an ODEX file compiled against partial boot image.
@@ -321,7 +357,12 @@ TEST_F(OatFileAssistantTest, OdexUpToDatePartialBootImage) {
EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
EXPECT_TRUE(oat_file_assistant.HasDexFiles());
- VerifyOptimizationStatus(dex_location, CompilerFilter::kSpeed, "install");
+ VerifyOptimizationStatus(
+ &oat_file_assistant,
+ dex_location,
+ CompilerFilter::kSpeed,
+ "install",
+ "up-to-date");
}
// Case: We have a DEX file and a PIC ODEX file, but no OAT file. We load the dex
@@ -390,7 +431,12 @@ TEST_F(OatFileAssistantTest, OatUpToDate) {
EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OatFileStatus());
EXPECT_TRUE(oat_file_assistant.HasDexFiles());
- VerifyOptimizationStatus(dex_location, CompilerFilter::kSpeed, "unknown");
+ VerifyOptimizationStatus(
+ &oat_file_assistant,
+ dex_location,
+ CompilerFilter::kSpeed,
+ "unknown",
+ "up-to-date");
}
// Case: Passing valid file descriptors of updated odex/vdex files along with the dex file.
@@ -545,7 +591,12 @@ TEST_F(OatFileAssistantTest, VdexUpToDateNoOdex) {
// care what the actual dumped value is.
oat_file_assistant.GetStatusDump();
- VerifyOptimizationStatus(dex_location, "run-from-apk", "unknown");
+ VerifyOptimizationStatus(
+ &oat_file_assistant,
+ dex_location,
+ "run-from-apk",
+ "unknown",
+ "io-error-no-oat");
}
// Case: We have a DEX file and empty VDEX and ODEX files.
@@ -717,6 +768,13 @@ TEST_F(OatFileAssistantTest, OatDexOutOfDate) {
EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
EXPECT_EQ(OatFileAssistant::kOatDexOutOfDate, oat_file_assistant.OatFileStatus());
EXPECT_TRUE(oat_file_assistant.HasDexFiles());
+
+ VerifyOptimizationStatus(
+ &oat_file_assistant,
+ dex_location,
+ "run-from-apk-fallback",
+ "unknown",
+ "apk-more-recent");
}
// Case: We have a DEX file and an (ODEX) VDEX file out of date with respect
@@ -784,6 +842,13 @@ TEST_F(OatFileAssistantTest, OatImageOutOfDate) {
EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
EXPECT_EQ(OatFileAssistant::kOatBootImageOutOfDate, oat_file_assistant.OatFileStatus());
EXPECT_TRUE(oat_file_assistant.HasDexFiles());
+
+ VerifyOptimizationStatus(
+ &oat_file_assistant,
+ dex_location,
+ "run-from-apk-fallback",
+ "unknown",
+ "boot-image-more-recent");
}
// Case: We have a DEX file and a verify-at-runtime OAT file out of date with
diff --git a/runtime/oat_file_manager.cc b/runtime/oat_file_manager.cc
index 1c715817d1..af41a11f79 100644
--- a/runtime/oat_file_manager.cc
+++ b/runtime/oat_file_manager.cc
@@ -222,7 +222,7 @@ std::vector<std::unique_ptr<const DexFile>> OatFileManager::OpenDexFilesFromOat(
jobjectArray dex_elements,
const OatFile** out_oat_file,
std::vector<std::string>* error_msgs) {
- ScopedTrace trace(__FUNCTION__);
+ ScopedTrace trace(StringPrintf("%s(%s)", __FUNCTION__, dex_location));
CHECK(dex_location != nullptr);
CHECK(error_msgs != nullptr);
@@ -248,23 +248,56 @@ std::vector<std::unique_ptr<const DexFile>> OatFileManager::OpenDexFilesFromOat(
runtime->GetOatFilesExecutable(),
only_use_system_oat_files_);
- // Get the oat file on disk.
+ // Get the current optimization status for trace debugging.
+ // Implementation detail note: GetOptimizationStatus will select the same
+ // oat file as GetBestOatFile used below, and in doing so it already pre-populates
+ // some OatFileAssistant internal fields.
+ std::string odex_location;
+ std::string compilation_filter;
+ std::string compilation_reason;
+ std::string odex_status;
+ oat_file_assistant.GetOptimizationStatus(
+ &odex_location,
+ &compilation_filter,
+ &compilation_reason,
+ &odex_status);
+
+ ScopedTrace odex_loading(StringPrintf(
+ "location=%s status=%s filter=%s reason=%s",
+ odex_location.c_str(),
+ odex_status.c_str(),
+ compilation_filter.c_str(),
+ compilation_reason.c_str()));
+
+ // Proceed with oat file loading.
std::unique_ptr<const OatFile> oat_file(oat_file_assistant.GetBestOatFile().release());
VLOG(oat) << "OatFileAssistant(" << dex_location << ").GetBestOatFile()="
<< reinterpret_cast<uintptr_t>(oat_file.get())
<< " (executable=" << (oat_file != nullptr ? oat_file->IsExecutable() : false) << ")";
+ CHECK(oat_file == nullptr || odex_location == oat_file->GetLocation())
+ << "OatFileAssistant non-determinism in choosing best oat files. "
+ << "optimization-status-location=" << odex_location
+ << " best_oat_file-location=" << oat_file->GetLocation();
+
const OatFile* source_oat_file = nullptr;
std::string error_msg;
bool is_special_shared_library = false;
bool class_loader_context_matches = false;
- if (oat_file != nullptr &&
- context != nullptr &&
- ClassLoaderContextMatches(oat_file.get(),
- context.get(),
- /*out*/ &is_special_shared_library,
- /*out*/ &error_msg)) {
- class_loader_context_matches = true;
+ bool check_context = oat_file != nullptr && context != nullptr;
+ if (check_context) {
+ class_loader_context_matches =
+ ClassLoaderContextMatches(oat_file.get(),
+ context.get(),
+ /*out*/ &is_special_shared_library,
+ /*out*/ &error_msg);
+ }
+ ScopedTrace context_results(StringPrintf(
+ "check_context=%s contex-ok=%s",
+ check_context ? "true" : "false",
+ class_loader_context_matches ? "true" : "false"));
+
+ if (class_loader_context_matches) {
// Load the dex files from the oat file.
bool added_image_space = false;
if (oat_file->IsExecutable()) {
@@ -295,8 +328,7 @@ std::vector<std::unique_ptr<const DexFile>> OatFileManager::OpenDexFilesFromOat(
runtime->GetHeap()->AddSpace(image_space.get());
}
{
- ScopedTrace image_space_timing(
- StringPrintf("Adding image space for location %s", dex_location));
+ ScopedTrace image_space_timing("Adding image space");
added_image_space = runtime->GetClassLinker()->AddImageSpace(image_space.get(),
h_loader,
/*out*/&dex_files,
@@ -350,6 +382,7 @@ std::vector<std::unique_ptr<const DexFile>> OatFileManager::OpenDexFilesFromOat(
}
}
if (dex_files.empty()) {
+ ScopedTrace failed_to_open_dex_files("FailedToOpenDexFilesFromOat");
error_msgs->push_back("Failed to open dex files from " + oat_file->GetLocation());
} else {
// Opened dex files from an oat file, madvise them to their loaded state.
@@ -373,6 +406,7 @@ std::vector<std::unique_ptr<const DexFile>> OatFileManager::OpenDexFilesFromOat(
std::set<const DexFile*> already_exists_in_classpath =
context->CheckForDuplicateDexFiles(MakeNonOwningPointerVector(dex_files));
if (!already_exists_in_classpath.empty()) {
+ ScopedTrace duplicate_dex_files("DuplicateDexFilesInContext");
auto duplicate_it = already_exists_in_classpath.begin();
std::string duplicates = (*duplicate_it)->GetLocation();
for (duplicate_it++ ; duplicate_it != already_exists_in_classpath.end(); duplicate_it++) {
@@ -414,6 +448,7 @@ std::vector<std::unique_ptr<const DexFile>> OatFileManager::OpenDexFilesFromOat(
kVerifyChecksum,
/*out*/ &error_msg,
&dex_files)) {
+ ScopedTrace fail_to_open_dex_from_apk("FailedToOpenDexFilesFromApk");
LOG(WARNING) << error_msg;
error_msgs->push_back("Failed to open dex files from " + std::string(dex_location)
+ " because: " + error_msg);