summaryrefslogtreecommitdiffstats
path: root/runtime
diff options
context:
space:
mode:
authorRichard Uhler <ruhler@google.com>2015-06-24 08:44:19 -0700
committerRichard Uhler <ruhler@google.com>2015-06-24 08:44:19 -0700
commitcb44b11a926696e34b3dc44288e762b4303cc128 (patch)
tree8ffd19eb220aa365fdcf292f495bc5d330f95c46 /runtime
parentad3359e77357cc5ce29ce529ab2ed9d0d8401da4 (diff)
downloadart-cb44b11a926696e34b3dc44288e762b4303cc128.zip
art-cb44b11a926696e34b3dc44288e762b4303cc128.tar.gz
art-cb44b11a926696e34b3dc44288e762b4303cc128.tar.bz2
Do not try to compile resource-only dex files.
This changes behavior in the case where we are asked to load a dex file that does not exist or has no classes.dex entry. Previously we would run dex2oat, which would log an error message and fail. Now we skip running dex2oat, we report the DexOptStatus as kNoDexOptNeeded, and we do not try to fall back to the missing original dex files. Bug: 21722039 Change-Id: I90b1f4165138daac57bb9d7a354319005652c593
Diffstat (limited to 'runtime')
-rw-r--r--runtime/class_linker.cc15
-rw-r--r--runtime/oat_file_assistant.cc28
-rw-r--r--runtime/oat_file_assistant.h15
-rw-r--r--runtime/oat_file_assistant_test.cc95
4 files changed, 109 insertions, 44 deletions
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 5240447..9ca6492 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -987,13 +987,18 @@ std::vector<std::unique_ptr<const DexFile>> ClassLinker::OpenDexFilesFromOat(
// Fall back to running out of the original dex file if we couldn't load any
// dex_files from the oat file.
if (dex_files.empty()) {
- if (Runtime::Current()->IsDexFileFallbackEnabled()) {
- if (!DexFile::Open(dex_location, dex_location, &error_msg, &dex_files)) {
- LOG(WARNING) << error_msg;
- error_msgs->push_back("Failed to open dex files from " + std::string(dex_location));
+ if (oat_file_assistant.HasOriginalDexFiles()) {
+ if (Runtime::Current()->IsDexFileFallbackEnabled()) {
+ if (!DexFile::Open(dex_location, dex_location, &error_msg, &dex_files)) {
+ LOG(WARNING) << error_msg;
+ error_msgs->push_back("Failed to open dex files from " + std::string(dex_location));
+ }
+ } else {
+ error_msgs->push_back("Fallback mode disabled, skipping dex files.");
}
} else {
- error_msgs->push_back("Fallback mode disabled, skipping dex files.");
+ error_msgs->push_back("No original dex files found for dex location "
+ + std::string(dex_location));
}
}
return dex_files;
diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index 094d8b7..b28adf9 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -151,7 +151,7 @@ OatFileAssistant::DexOptNeeded OatFileAssistant::GetDexOptNeeded() {
return kSelfPatchOatNeeded;
}
- return kDex2OatNeeded;
+ return HasOriginalDexFiles() ? kDex2OatNeeded : kNoDexOptNeeded;
}
bool OatFileAssistant::MakeUpToDate(std::string* error_msg) {
@@ -241,6 +241,14 @@ std::vector<std::unique_ptr<const DexFile>> OatFileAssistant::LoadDexFiles(
return dex_files;
}
+bool OatFileAssistant::HasOriginalDexFiles() {
+ // Ensure GetRequiredDexChecksum has been run so that
+ // has_original_dex_files_ is initialized. We don't care about the result of
+ // GetRequiredDexChecksum.
+ GetRequiredDexChecksum();
+ return has_original_dex_files_;
+}
+
const std::string* OatFileAssistant::OdexFileName() {
if (!cached_odex_file_name_attempted_) {
CHECK(dex_location_ != nullptr) << "OatFileAssistant: null dex location";
@@ -817,17 +825,19 @@ std::string OatFileAssistant::ImageLocation() {
}
const uint32_t* OatFileAssistant::GetRequiredDexChecksum() {
- if (!required_dex_checksum_attempted) {
- required_dex_checksum_attempted = true;
- required_dex_checksum_found = false;
+ if (!required_dex_checksum_attempted_) {
+ required_dex_checksum_attempted_ = true;
+ required_dex_checksum_found_ = false;
std::string error_msg;
CHECK(dex_location_ != nullptr) << "OatFileAssistant provided no dex location";
- if (DexFile::GetChecksum(dex_location_, &cached_required_dex_checksum, &error_msg)) {
- required_dex_checksum_found = true;
+ if (DexFile::GetChecksum(dex_location_, &cached_required_dex_checksum_, &error_msg)) {
+ required_dex_checksum_found_ = true;
+ has_original_dex_files_ = true;
} else {
// This can happen if the original dex file has been stripped from the
// apk.
VLOG(oat) << "OatFileAssistant: " << error_msg;
+ has_original_dex_files_ = false;
// Get the checksum from the odex if we can.
const OatFile* odex_file = GetOdexFile();
@@ -835,13 +845,13 @@ const uint32_t* OatFileAssistant::GetRequiredDexChecksum() {
const OatFile::OatDexFile* odex_dex_file = odex_file->GetOatDexFile(
dex_location_, nullptr, false);
if (odex_dex_file != nullptr) {
- cached_required_dex_checksum = odex_dex_file->GetDexFileLocationChecksum();
- required_dex_checksum_found = true;
+ cached_required_dex_checksum_ = odex_dex_file->GetDexFileLocationChecksum();
+ required_dex_checksum_found_ = true;
}
}
}
}
- return required_dex_checksum_found ? &cached_required_dex_checksum : nullptr;
+ return required_dex_checksum_found_ ? &cached_required_dex_checksum_ : nullptr;
}
const OatFile* OatFileAssistant::GetOdexFile() {
diff --git a/runtime/oat_file_assistant.h b/runtime/oat_file_assistant.h
index 4c0b0e2..7216fc7 100644
--- a/runtime/oat_file_assistant.h
+++ b/runtime/oat_file_assistant.h
@@ -174,6 +174,12 @@ class OatFileAssistant {
static std::vector<std::unique_ptr<const DexFile>> LoadDexFiles(
const OatFile& oat_file, const char* dex_location);
+ // Returns true if there are dex files in the original dex location that can
+ // be compiled with dex2oat for this dex location.
+ // Returns false if there is no original dex file, or if the original dex
+ // file is an apk/zip without a classes.dex entry.
+ bool HasOriginalDexFiles();
+
// If the dex file has been installed with a compiled oat file alongside
// it, the compiled oat file will have the extension .odex, and is referred
// to as the odex file. It is called odex for legacy reasons; the file is
@@ -312,6 +318,8 @@ class OatFileAssistant {
// Returns dex_checksum if a required checksum was located. Returns
// null if the required checksum was not found.
// The caller shouldn't clean up or free the returned pointer.
+ // This sets the has_original_dex_files_ field to true if a checksum was
+ // found for the dex_location_ dex file.
const uint32_t* GetRequiredDexChecksum();
// Returns the loaded odex file.
@@ -374,9 +382,10 @@ class OatFileAssistant {
// Cached value of the required dex checksum.
// This should be accessed only by the GetRequiredDexChecksum() method.
- uint32_t cached_required_dex_checksum;
- bool required_dex_checksum_attempted = false;
- bool required_dex_checksum_found;
+ uint32_t cached_required_dex_checksum_;
+ bool required_dex_checksum_attempted_ = false;
+ bool required_dex_checksum_found_;
+ bool has_original_dex_files_;
// Cached value of the odex file name.
// This should be accessed only by the OdexFileName() method.
diff --git a/runtime/oat_file_assistant_test.cc b/runtime/oat_file_assistant_test.cc
index d8e3797..570c59c 100644
--- a/runtime/oat_file_assistant_test.cc
+++ b/runtime/oat_file_assistant_test.cc
@@ -309,16 +309,24 @@ TEST_F(OatFileAssistantTest, DexNoOat) {
EXPECT_FALSE(oat_file_assistant.OatFileNeedsRelocation());
EXPECT_FALSE(oat_file_assistant.OatFileIsUpToDate());
EXPECT_EQ(OatFileAssistant::kOatOutOfDate, oat_file_assistant.OatFileStatus());
+ EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
}
// Case: We have no DEX file and no OAT file.
-// Expect: Status is kDex2OatNeeded. Loading should fail, but not crash.
+// Expect: Status is kNoDexOptNeeded. Loading should fail, but not crash.
TEST_F(OatFileAssistantTest, NoDexNoOat) {
std::string dex_location = GetScratchDir() + "/NoDexNoOat.jar";
OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
- EXPECT_EQ(OatFileAssistant::kDex2OatNeeded, oat_file_assistant.GetDexOptNeeded());
+ EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, oat_file_assistant.GetDexOptNeeded());
+ EXPECT_FALSE(oat_file_assistant.HasOriginalDexFiles());
+
+ // Trying to make the oat file up to date should not fail or crash.
+ std::string error_msg;
+ EXPECT_TRUE(oat_file_assistant.MakeUpToDate(&error_msg));
+
+ // Trying to get the best oat file should fail, but not crash.
std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
EXPECT_EQ(nullptr, oat_file.get());
}
@@ -342,6 +350,7 @@ TEST_F(OatFileAssistantTest, OatUpToDate) {
EXPECT_FALSE(oat_file_assistant.OatFileNeedsRelocation());
EXPECT_TRUE(oat_file_assistant.OatFileIsUpToDate());
EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OatFileStatus());
+ EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
}
// Case: We have a MultiDEX file and up-to-date OAT file for it.
@@ -353,6 +362,7 @@ TEST_F(OatFileAssistantTest, MultiDexOatUpToDate) {
OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, oat_file_assistant.GetDexOptNeeded());
+ EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
// Verify we can load both dex files.
std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
@@ -378,6 +388,7 @@ TEST_F(OatFileAssistantTest, MultiDexSecondaryOutOfDate) {
OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
EXPECT_EQ(OatFileAssistant::kDex2OatNeeded, oat_file_assistant.GetDexOptNeeded());
+ EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
}
// Case: We have a MultiDEX file and up-to-date OAT file for it with relative
@@ -432,6 +443,7 @@ TEST_F(OatFileAssistantTest, OatOutOfDate) {
EXPECT_TRUE(oat_file_assistant.OatFileExists());
EXPECT_TRUE(oat_file_assistant.OatFileIsOutOfDate());
EXPECT_FALSE(oat_file_assistant.OatFileIsUpToDate());
+ EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
}
// Case: We have a DEX file and an ODEX file, but no OAT file.
@@ -457,6 +469,7 @@ TEST_F(OatFileAssistantTest, DexOdexNoOat) {
EXPECT_FALSE(oat_file_assistant.OatFileExists());
EXPECT_TRUE(oat_file_assistant.OatFileIsOutOfDate());
EXPECT_FALSE(oat_file_assistant.OatFileIsUpToDate());
+ EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
}
// Case: We have a stripped DEX file and an ODEX file, but no OAT file.
@@ -484,6 +497,7 @@ TEST_F(OatFileAssistantTest, StrippedDexOdexNoOat) {
EXPECT_FALSE(oat_file_assistant.OatFileExists());
EXPECT_TRUE(oat_file_assistant.OatFileIsOutOfDate());
EXPECT_FALSE(oat_file_assistant.OatFileIsUpToDate());
+ EXPECT_FALSE(oat_file_assistant.HasOriginalDexFiles());
// Make the oat file up to date.
std::string error_msg;
@@ -498,6 +512,7 @@ TEST_F(OatFileAssistantTest, StrippedDexOdexNoOat) {
EXPECT_TRUE(oat_file_assistant.OatFileExists());
EXPECT_FALSE(oat_file_assistant.OatFileIsOutOfDate());
EXPECT_TRUE(oat_file_assistant.OatFileIsUpToDate());
+ EXPECT_FALSE(oat_file_assistant.HasOriginalDexFiles());
// Verify we can load the dex files from it.
std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
@@ -538,6 +553,7 @@ TEST_F(OatFileAssistantTest, StrippedDexOdexOat) {
EXPECT_TRUE(oat_file_assistant.OatFileExists());
EXPECT_TRUE(oat_file_assistant.OatFileIsOutOfDate());
EXPECT_FALSE(oat_file_assistant.OatFileIsUpToDate());
+ EXPECT_FALSE(oat_file_assistant.HasOriginalDexFiles());
// Make the oat file up to date.
std::string error_msg;
@@ -554,6 +570,7 @@ TEST_F(OatFileAssistantTest, StrippedDexOdexOat) {
EXPECT_FALSE(oat_file_assistant.OatFileIsOutOfDate());
EXPECT_FALSE(oat_file_assistant.OatFileNeedsRelocation());
EXPECT_TRUE(oat_file_assistant.OatFileIsUpToDate());
+ EXPECT_FALSE(oat_file_assistant.HasOriginalDexFiles());
// Verify we can load the dex files from it.
std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
@@ -564,6 +581,45 @@ TEST_F(OatFileAssistantTest, StrippedDexOdexOat) {
EXPECT_EQ(1u, dex_files.size());
}
+// Case: We have a stripped (or resource-only) DEX file, no ODEX file and no
+// OAT file. Expect: The status is kNoDexOptNeeded.
+TEST_F(OatFileAssistantTest, ResourceOnlyDex) {
+ std::string dex_location = GetScratchDir() + "/ResourceOnlyDex.jar";
+
+ Copy(GetStrippedDexSrc1(), dex_location);
+
+ // Verify the status.
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
+
+ EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, oat_file_assistant.GetDexOptNeeded());
+
+ EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
+ EXPECT_FALSE(oat_file_assistant.OdexFileExists());
+ EXPECT_TRUE(oat_file_assistant.OdexFileIsOutOfDate());
+ EXPECT_FALSE(oat_file_assistant.OdexFileNeedsRelocation());
+ EXPECT_FALSE(oat_file_assistant.OdexFileIsUpToDate());
+ EXPECT_FALSE(oat_file_assistant.OatFileExists());
+ EXPECT_TRUE(oat_file_assistant.OatFileIsOutOfDate());
+ EXPECT_FALSE(oat_file_assistant.OatFileIsUpToDate());
+ EXPECT_FALSE(oat_file_assistant.HasOriginalDexFiles());
+
+ // Make the oat file up to date. This should have no effect.
+ std::string error_msg;
+ EXPECT_TRUE(oat_file_assistant.MakeUpToDate(&error_msg)) << error_msg;
+
+ EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, oat_file_assistant.GetDexOptNeeded());
+
+ EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
+ EXPECT_FALSE(oat_file_assistant.OdexFileExists());
+ EXPECT_TRUE(oat_file_assistant.OdexFileIsOutOfDate());
+ EXPECT_FALSE(oat_file_assistant.OdexFileNeedsRelocation());
+ EXPECT_FALSE(oat_file_assistant.OdexFileIsUpToDate());
+ EXPECT_FALSE(oat_file_assistant.OatFileExists());
+ EXPECT_TRUE(oat_file_assistant.OatFileIsOutOfDate());
+ EXPECT_FALSE(oat_file_assistant.OatFileIsUpToDate());
+ EXPECT_FALSE(oat_file_assistant.HasOriginalDexFiles());
+}
+
// Case: We have a DEX file, no ODEX file and an OAT file that needs
// relocation.
// Expect: The status is kSelfPatchOatNeeded.
@@ -589,6 +645,7 @@ TEST_F(OatFileAssistantTest, SelfRelocation) {
EXPECT_TRUE(oat_file_assistant.OatFileNeedsRelocation());
EXPECT_FALSE(oat_file_assistant.OatFileIsOutOfDate());
EXPECT_FALSE(oat_file_assistant.OatFileIsUpToDate());
+ EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
// Make the oat file up to date.
std::string error_msg;
@@ -605,6 +662,7 @@ TEST_F(OatFileAssistantTest, SelfRelocation) {
EXPECT_FALSE(oat_file_assistant.OatFileIsOutOfDate());
EXPECT_FALSE(oat_file_assistant.OatFileNeedsRelocation());
EXPECT_TRUE(oat_file_assistant.OatFileIsUpToDate());
+ EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
ASSERT_TRUE(oat_file.get() != nullptr);
@@ -643,6 +701,7 @@ TEST_F(OatFileAssistantTest, OdexOatOverlap) {
EXPECT_TRUE(oat_file_assistant.OatFileExists());
EXPECT_FALSE(oat_file_assistant.OatFileIsOutOfDate());
EXPECT_FALSE(oat_file_assistant.OatFileIsUpToDate());
+ EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
// Things aren't relocated, so it should fall back to interpreted.
std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
@@ -688,6 +747,7 @@ TEST_F(OatFileAssistantTest, DexPicOdexNoOat) {
EXPECT_FALSE(oat_file_assistant.OatFileExists());
EXPECT_TRUE(oat_file_assistant.OatFileIsOutOfDate());
EXPECT_FALSE(oat_file_assistant.OatFileIsUpToDate());
+ EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
}
// Case: We have a DEX file and up-to-date OAT file for it.
@@ -756,27 +816,6 @@ TEST_F(OatFileAssistantTest, LoadDexNoAlternateOat) {
EXPECT_FALSE(ofm.OatFileExists());
}
-// Case: Non-existent Dex location.
-// Expect: The dex code is out of date, and trying to update it fails.
-TEST_F(OatFileAssistantTest, NonExsistentDexLocation) {
- std::string dex_location = GetScratchDir() + "/BadDexLocation.jar";
-
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
-
- EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
- EXPECT_EQ(OatFileAssistant::kDex2OatNeeded, oat_file_assistant.GetDexOptNeeded());
- EXPECT_FALSE(oat_file_assistant.OdexFileExists());
- EXPECT_FALSE(oat_file_assistant.OatFileExists());
- EXPECT_TRUE(oat_file_assistant.OdexFileIsOutOfDate());
- EXPECT_FALSE(oat_file_assistant.OdexFileIsUpToDate());
- EXPECT_TRUE(oat_file_assistant.OatFileIsOutOfDate());
- EXPECT_FALSE(oat_file_assistant.OatFileIsUpToDate());
-
- std::string error_msg;
- EXPECT_FALSE(oat_file_assistant.MakeUpToDate(&error_msg));
- EXPECT_FALSE(error_msg.empty());
-}
-
// Turn an absolute path into a path relative to the current working
// directory.
static std::string MakePathRelative(std::string target) {
@@ -833,24 +872,26 @@ TEST_F(OatFileAssistantTest, NonAbsoluteDexLocation) {
}
// Case: Very short, non-existent Dex location.
-// Expect: Dex code is out of date, and trying to update it fails.
+// Expect: kNoDexOptNeeded.
TEST_F(OatFileAssistantTest, ShortDexLocation) {
std::string dex_location = "/xx";
OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
- EXPECT_EQ(OatFileAssistant::kDex2OatNeeded, oat_file_assistant.GetDexOptNeeded());
+ EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, oat_file_assistant.GetDexOptNeeded());
EXPECT_FALSE(oat_file_assistant.OdexFileExists());
EXPECT_FALSE(oat_file_assistant.OatFileExists());
EXPECT_TRUE(oat_file_assistant.OdexFileIsOutOfDate());
EXPECT_FALSE(oat_file_assistant.OdexFileIsUpToDate());
EXPECT_TRUE(oat_file_assistant.OatFileIsOutOfDate());
EXPECT_FALSE(oat_file_assistant.OatFileIsUpToDate());
+ EXPECT_FALSE(oat_file_assistant.HasOriginalDexFiles());
+ // Trying to make it up to date should have no effect.
std::string error_msg;
- EXPECT_FALSE(oat_file_assistant.MakeUpToDate(&error_msg));
- EXPECT_FALSE(error_msg.empty());
+ EXPECT_TRUE(oat_file_assistant.MakeUpToDate(&error_msg));
+ EXPECT_TRUE(error_msg.empty());
}
// Case: Non-standard extension for dex file.