diff options
| -rw-r--r-- | libdexfile/dex/art_dex_file_loader.cc | 4 | ||||
| -rw-r--r-- | runtime/class_loader_context.cc | 5 | ||||
| -rw-r--r-- | runtime/oat_file_assistant.cc | 43 | ||||
| -rw-r--r-- | runtime/oat_file_assistant.h | 9 | ||||
| -rw-r--r-- | runtime/oat_file_assistant_test.cc | 97 | ||||
| -rw-r--r-- | runtime/oat_file_manager.cc | 57 |
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); |