Make system use patchoat to relocate during runtime.
Change dalvik_system_DexFile.cc so that isDexOptNeededInternal will be
able to indicate that a patchoat is required. Change default of relocate
option to be on.
Bug: 15358152
Change-Id: Ibe92d8b55a24bbf718b0416a21b76e5df7a2de26
diff --git a/Android.mk b/Android.mk
index e536a71..b006bfe 100644
--- a/Android.mk
+++ b/Android.mk
@@ -316,7 +316,8 @@
--dex-location=/$(1) --oat-file=$$@ \
--instruction-set=$(DEX2OAT_TARGET_ARCH) \
--instruction-set-features=$(DEX2OAT_TARGET_INSTRUCTION_SET_FEATURES) \
- --android-root=$(PRODUCT_OUT)/system --include-patch-information
+ --android-root=$(PRODUCT_OUT)/system --include-patch-information \
+ --runtime-arg -Xnorelocate
endif
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index f85bc65..ed126ad 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -933,13 +933,13 @@
}
*out_is_finalizable = resolved_class->IsFinalizable();
const bool compiling_boot = Runtime::Current()->GetHeap()->IsCompilingBoot();
+ const bool support_boot_image_fixup = GetSupportBootImageFixup();
if (compiling_boot) {
// boot -> boot class pointers.
// True if the class is in the image at boot compiling time.
const bool is_image_class = IsImage() && IsImageClass(
dex_file.StringDataByIdx(dex_file.GetTypeId(type_idx).descriptor_idx_));
// True if pc relative load works.
- const bool support_boot_image_fixup = GetSupportBootImageFixup();
if (is_image_class && support_boot_image_fixup) {
*is_type_initialized = resolved_class->IsInitialized();
*use_direct_type_ptr = false;
@@ -952,7 +952,7 @@
// True if the class is in the image at app compiling time.
const bool class_in_image =
Runtime::Current()->GetHeap()->FindSpaceFromObject(resolved_class, false)->IsImageSpace();
- if (class_in_image) {
+ if (class_in_image && support_boot_image_fixup) {
// boot -> app class pointers.
*is_type_initialized = resolved_class->IsInitialized();
// TODO This is somewhat hacky. We should refactor all of this invoke codepath.
diff --git a/compiler/elf_patcher.cc b/compiler/elf_patcher.cc
index 6112fbb..137110f 100644
--- a/compiler/elf_patcher.cc
+++ b/compiler/elf_patcher.cc
@@ -120,6 +120,7 @@
uint32_t* ElfPatcher::GetPatchLocation(uintptr_t patch_ptr) {
CHECK_GE(patch_ptr, reinterpret_cast<uintptr_t>(oat_file_->Begin()));
+ CHECK_LE(patch_ptr, reinterpret_cast<uintptr_t>(oat_file_->End()));
uintptr_t off = patch_ptr - reinterpret_cast<uintptr_t>(oat_file_->Begin());
uintptr_t ret = reinterpret_cast<uintptr_t>(oat_header_) + off;
@@ -144,20 +145,20 @@
cpatch->GetTargetDexFile()->GetMethodId(cpatch->GetTargetMethodIdx());
uint32_t expected = reinterpret_cast<uintptr_t>(&id) & 0xFFFFFFFF;
uint32_t actual = *patch_location;
- CHECK(actual == expected || actual == value) << std::hex
- << "actual=" << actual
- << "expected=" << expected
- << "value=" << value;
+ CHECK(actual == expected || actual == value) << "Patching call failed: " << std::hex
+ << " actual=" << actual
+ << " expected=" << expected
+ << " value=" << value;
}
if (patch->IsType()) {
const CompilerDriver::TypePatchInformation* tpatch = patch->AsType();
const DexFile::TypeId& id = tpatch->GetDexFile().GetTypeId(tpatch->GetTargetTypeIdx());
uint32_t expected = reinterpret_cast<uintptr_t>(&id) & 0xFFFFFFFF;
uint32_t actual = *patch_location;
- CHECK(actual == expected || actual == value) << std::hex
- << "actual=" << actual
- << "expected=" << expected
- << "value=" << value;
+ CHECK(actual == expected || actual == value) << "Patching type failed: " << std::hex
+ << " actual=" << actual
+ << " expected=" << expected
+ << " value=" << value;
}
}
*patch_location = value;
diff --git a/compiler/image_test.cc b/compiler/image_test.cc
index 3005e56..6b23345 100644
--- a/compiler/image_test.cc
+++ b/compiler/image_test.cc
@@ -141,6 +141,8 @@
std::string image("-Ximage:");
image.append(image_location.GetFilename());
options.push_back(std::make_pair(image.c_str(), reinterpret_cast<void*>(NULL)));
+ // By default the compiler this creates will not include patch information.
+ options.push_back(std::make_pair("-Xnorelocate", nullptr));
if (!Runtime::Create(options, false)) {
LOG(FATAL) << "Failed to create runtime";
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 99907e3..c1e3b25 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -615,6 +615,14 @@
argv.push_back("--compiler-filter=verify-none");
}
+ if (Runtime::Current()->MustRelocateIfPossible()) {
+ argv.push_back("--runtime-arg");
+ argv.push_back("-Xrelocate");
+ } else {
+ argv.push_back("--runtime-arg");
+ argv.push_back("-Xnorelocate");
+ }
+
if (!kIsTargetBuild) {
argv.push_back("--host");
}
@@ -986,11 +994,25 @@
return oat_file.release();
}
-bool ClassLinker::VerifyOatFileChecksums(const OatFile* oat_file,
- const char* dex_location,
- uint32_t dex_location_checksum,
- const InstructionSet instruction_set,
- std::string* error_msg) {
+bool ClassLinker::VerifyOatImageChecksum(const OatFile* oat_file,
+ const InstructionSet instruction_set) {
+ Runtime* runtime = Runtime::Current();
+ const gc::space::ImageSpace* image_space = runtime->GetHeap()->GetImageSpace();
+ uint32_t image_oat_checksum = 0;
+ if (instruction_set == kRuntimeISA) {
+ const ImageHeader& image_header = image_space->GetImageHeader();
+ image_oat_checksum = image_header.GetOatChecksum();
+ } else {
+ std::unique_ptr<ImageHeader> image_header(gc::space::ImageSpace::ReadImageHeaderOrDie(
+ image_space->GetImageLocation().c_str(), instruction_set));
+ image_oat_checksum = image_header->GetOatChecksum();
+ }
+ return oat_file->GetOatHeader().GetImageFileLocationOatChecksum() == image_oat_checksum;
+}
+
+bool ClassLinker::VerifyOatChecksums(const OatFile* oat_file,
+ const InstructionSet instruction_set,
+ std::string* error_msg) {
Runtime* runtime = Runtime::Current();
const gc::space::ImageSpace* image_space = runtime->GetHeap()->GetImageSpace();
@@ -1013,9 +1035,28 @@
image_patch_delta = image_header->GetPatchDelta();
}
const OatHeader& oat_header = oat_file->GetOatHeader();
- bool image_check = ((oat_header.GetImageFileLocationOatChecksum() == image_oat_checksum)
- && (oat_header.GetImageFileLocationOatDataBegin() == image_oat_data_begin)
- && (oat_header.GetImagePatchDelta() == image_patch_delta));
+ bool ret = ((oat_header.GetImageFileLocationOatChecksum() == image_oat_checksum)
+ && (oat_header.GetImagePatchDelta() == image_patch_delta)
+ && (oat_header.GetImageFileLocationOatDataBegin() == image_oat_data_begin));
+ if (!ret) {
+ *error_msg = StringPrintf("oat file '%s' mismatch (0x%x, %d, %d) with (0x%x, %" PRIdPTR ", %d)",
+ oat_file->GetLocation().c_str(),
+ oat_file->GetOatHeader().GetImageFileLocationOatChecksum(),
+ oat_file->GetOatHeader().GetImageFileLocationOatDataBegin(),
+ oat_file->GetOatHeader().GetImagePatchDelta(),
+ image_oat_checksum, image_oat_data_begin, image_patch_delta);
+ }
+ return ret;
+}
+
+bool ClassLinker::VerifyOatAndDexFileChecksums(const OatFile* oat_file,
+ const char* dex_location,
+ uint32_t dex_location_checksum,
+ const InstructionSet instruction_set,
+ std::string* error_msg) {
+ if (!VerifyOatChecksums(oat_file, instruction_set, error_msg)) {
+ return false;
+ }
const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_location,
&dex_location_checksum);
@@ -1031,27 +1072,15 @@
}
return false;
}
- bool dex_check = dex_location_checksum == oat_dex_file->GetDexFileLocationChecksum();
- if (image_check && dex_check) {
- return true;
- }
-
- if (!image_check) {
- ScopedObjectAccess soa(Thread::Current());
- *error_msg = StringPrintf("oat file '%s' mismatch (0x%x, %d) with (0x%x, %" PRIdPTR ")",
- oat_file->GetLocation().c_str(),
- oat_file->GetOatHeader().GetImageFileLocationOatChecksum(),
- oat_file->GetOatHeader().GetImageFileLocationOatDataBegin(),
- image_oat_checksum, image_oat_data_begin);
- }
- if (!dex_check) {
+ if (dex_location_checksum != oat_dex_file->GetDexFileLocationChecksum()) {
*error_msg = StringPrintf("oat file '%s' mismatch (0x%x) with '%s' (0x%x)",
oat_file->GetLocation().c_str(),
oat_dex_file->GetDexFileLocationChecksum(),
dex_location, dex_location_checksum);
+ return false;
}
- return false;
+ return true;
}
bool ClassLinker::VerifyOatWithDexFile(const OatFile* oat_file,
@@ -1074,8 +1103,8 @@
}
dex_file.reset(oat_dex_file->OpenDexFile(error_msg));
} else {
- bool verified = VerifyOatFileChecksums(oat_file, dex_location, dex_location_checksum,
- kRuntimeISA, error_msg);
+ bool verified = VerifyOatAndDexFileChecksums(oat_file, dex_location, dex_location_checksum,
+ kRuntimeISA, error_msg);
if (!verified) {
return false;
}
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 1bb1635..8c09042 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -274,12 +274,18 @@
std::vector<const DexFile*>* dex_files)
LOCKS_EXCLUDED(dex_lock_, Locks::mutator_lock_);
+ // Returns true if the given oat file has the same image checksum as the image it is paired with.
+ static bool VerifyOatImageChecksum(const OatFile* oat_file, const InstructionSet instruction_set);
+ // Returns true if the oat file checksums match with the image and the offsets are such that it
+ // could be loaded with it.
+ static bool VerifyOatChecksums(const OatFile* oat_file, const InstructionSet instruction_set,
+ std::string* error_msg);
// Returns true if oat file contains the dex file with the given location and checksum.
- static bool VerifyOatFileChecksums(const OatFile* oat_file,
- const char* dex_location,
- uint32_t dex_location_checksum,
- InstructionSet instruction_set,
- std::string* error_msg);
+ static bool VerifyOatAndDexFileChecksums(const OatFile* oat_file,
+ const char* dex_location,
+ uint32_t dex_location_checksum,
+ InstructionSet instruction_set,
+ std::string* error_msg);
// TODO: replace this with multiple methods that allocate the correct managed type.
template <class T>
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index fc6d2ef..1d10af2 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -166,7 +166,8 @@
return true;
}
-bool ImageSpace::RelocateImage(const char* image_location, const char* dest_filename,
+// Relocate the image at image_location to dest_filename and relocate it by a random amount.
+static bool RelocateImage(const char* image_location, const char* dest_filename,
InstructionSet isa, std::string* error_msg) {
std::string patchoat(Runtime::Current()->GetPatchoatExecutable());
diff --git a/runtime/gc/space/image_space.h b/runtime/gc/space/image_space.h
index debca52..6be3b8f 100644
--- a/runtime/gc/space/image_space.h
+++ b/runtime/gc/space/image_space.h
@@ -124,9 +124,6 @@
bool validate_oat_file, std::string* error_msg)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- static bool RelocateImage(const char* image_location, const char* dest_filename,
- InstructionSet isa, std::string* error_msg);
-
OatFile* OpenOatFile(const char* image, std::string* error_msg) const
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
diff --git a/runtime/globals.h b/runtime/globals.h
index 1d9f22c..107e064 100644
--- a/runtime/globals.h
+++ b/runtime/globals.h
@@ -118,6 +118,8 @@
static constexpr TraceClockSource kDefaultTraceClockSource = kTraceClockSourceWall;
#endif
+static constexpr bool kDefaultMustRelocate = true;
+
} // namespace art
#endif // ART_RUNTIME_GLOBALS_H_
diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc
index ac1a310..0af2c22 100644
--- a/runtime/native/dalvik_system_DexFile.cc
+++ b/runtime/native/dalvik_system_DexFile.cc
@@ -275,8 +275,96 @@
}
}
-static jboolean IsDexOptNeededInternal(JNIEnv* env, const char* filename,
+// Java: dalvik.system.DexFile.UP_TO_DATE
+static const jbyte kUpToDate = 0;
+// Java: dalvik.system.DexFile.DEXOPT_NEEDED
+static const jbyte kPatchoatNeeded = 1;
+// Java: dalvik.system.DexFile.PATCHOAT_NEEDED
+static const jbyte kDexoptNeeded = 2;
+
+template <const bool kVerboseLogging, const bool kReasonLogging>
+static jbyte IsDexOptNeededForFile(const std::string& oat_filename, const char* filename,
+ InstructionSet target_instruction_set) {
+ std::string error_msg;
+ std::unique_ptr<const OatFile> oat_file(OatFile::Open(oat_filename, oat_filename, nullptr,
+ false, &error_msg));
+ if (oat_file.get() == nullptr) {
+ if (kVerboseLogging) {
+ LOG(INFO) << "DexFile_isDexOptNeeded failed to open oat file '" << oat_filename
+ << "' for file location '" << filename << "': " << error_msg;
+ }
+ error_msg.clear();
+ return kDexoptNeeded;
+ }
+ bool should_relocate_if_possible = Runtime::Current()->ShouldRelocate();
+ uint32_t location_checksum = 0;
+ const art::OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(filename, nullptr,
+ kReasonLogging);
+ if (oat_dex_file != nullptr) {
+ // If its not possible to read the classes.dex assume up-to-date as we won't be able to
+ // compile it anyway.
+ if (!DexFile::GetChecksum(filename, &location_checksum, &error_msg)) {
+ if (kVerboseLogging) {
+ LOG(INFO) << "DexFile_isDexOptNeeded found precompiled stripped file: "
+ << filename << " for " << oat_filename << ": " << error_msg;
+ }
+ if (ClassLinker::VerifyOatChecksums(oat_file.get(), target_instruction_set, &error_msg)) {
+ if (kVerboseLogging) {
+ LOG(INFO) << "DexFile_isDexOptNeeded file " << oat_filename
+ << " is up-to-date for " << filename;
+ }
+ return kUpToDate;
+ } else if (should_relocate_if_possible &&
+ ClassLinker::VerifyOatImageChecksum(oat_file.get(), target_instruction_set)) {
+ if (kVerboseLogging) {
+ LOG(INFO) << "DexFile_isDexOptNeeded file " << oat_filename
+ << " needs to be relocated for " << filename;
+ }
+ return kPatchoatNeeded;
+ } else {
+ if (kVerboseLogging) {
+ LOG(INFO) << "DexFile_isDexOptNeeded file " << oat_filename
+ << " is out of date for " << filename;
+ }
+ return kDexoptNeeded;
+ }
+ // If we get here the file is out of date and we should use the system one to relocate.
+ } else {
+ if (ClassLinker::VerifyOatAndDexFileChecksums(oat_file.get(), filename, location_checksum,
+ target_instruction_set, &error_msg)) {
+ if (kVerboseLogging) {
+ LOG(INFO) << "DexFile_isDexOptNeeded file " << oat_filename
+ << " is up-to-date for " << filename;
+ }
+ return kUpToDate;
+ } else if (location_checksum == oat_dex_file->GetDexFileLocationChecksum()
+ && should_relocate_if_possible
+ && ClassLinker::VerifyOatImageChecksum(oat_file.get(), target_instruction_set)) {
+ if (kVerboseLogging) {
+ LOG(INFO) << "DexFile_isDexOptNeeded file " << oat_filename
+ << " needs to be relocated for " << filename;
+ }
+ return kPatchoatNeeded;
+ } else {
+ if (kVerboseLogging) {
+ LOG(INFO) << "DexFile_isDexOptNeeded file " << oat_filename
+ << " is out of date for " << filename;
+ }
+ return kDexoptNeeded;
+ }
+ }
+ } else {
+ if (kVerboseLogging) {
+ LOG(INFO) << "DexFile_isDexOptNeeded file " << oat_filename
+ << " does not contain " << filename;
+ }
+ return kDexoptNeeded;
+ }
+}
+
+static jbyte IsDexOptNeededInternal(JNIEnv* env, const char* filename,
const char* pkgname, const char* instruction_set, const jboolean defer) {
+ // TODO disable this logging.
const bool kVerboseLogging = false; // Spammy logging.
const bool kReasonLogging = true; // Logging of reason for returning JNI_TRUE.
@@ -285,7 +373,7 @@
ScopedLocalRef<jclass> fnfe(env, env->FindClass("java/io/FileNotFoundException"));
const char* message = (filename == nullptr) ? "<empty file name>" : filename;
env->ThrowNew(fnfe.get(), message);
- return JNI_FALSE;
+ return kUpToDate;
}
// Always treat elements of the bootclasspath as up-to-date. The
@@ -301,78 +389,45 @@
if (kVerboseLogging) {
LOG(INFO) << "DexFile_isDexOptNeeded ignoring boot class path file: " << filename;
}
- return JNI_FALSE;
+ return kUpToDate;
}
}
- const InstructionSet target_instruction_set = GetInstructionSetFromString(instruction_set);
-
- // Check if we have an odex file next to the dex file.
- std::string odex_filename(DexFilenameToOdexFilename(filename, kRuntimeISA));
- std::string error_msg;
- std::unique_ptr<const OatFile> oat_file(OatFile::Open(odex_filename, odex_filename, NULL, false,
- &error_msg));
- if (oat_file.get() == nullptr) {
- if (kVerboseLogging) {
- LOG(INFO) << "DexFile_isDexOptNeeded failed to open oat file '" << filename
- << "': " << error_msg;
- }
- error_msg.clear();
- } else {
- const art::OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(filename, NULL,
- kReasonLogging);
- if (oat_dex_file != nullptr) {
- uint32_t location_checksum;
- // If its not possible to read the classes.dex assume up-to-date as we won't be able to
- // compile it anyway.
- if (!DexFile::GetChecksum(filename, &location_checksum, &error_msg)) {
- if (kVerboseLogging) {
- LOG(INFO) << "DexFile_isDexOptNeeded ignoring precompiled stripped file: "
- << filename << ": " << error_msg;
- }
- return JNI_FALSE;
- }
- if (ClassLinker::VerifyOatFileChecksums(oat_file.get(), filename, location_checksum,
- target_instruction_set,
- &error_msg)) {
- if (kVerboseLogging) {
- LOG(INFO) << "DexFile_isDexOptNeeded precompiled file " << odex_filename
- << " has an up-to-date checksum compared to " << filename;
- }
- return JNI_FALSE;
- } else {
- if (kVerboseLogging) {
- LOG(INFO) << "DexFile_isDexOptNeeded found precompiled file " << odex_filename
- << " with an out-of-date checksum compared to " << filename
- << ": " << error_msg;
- }
- error_msg.clear();
- }
- }
- }
+ bool force_system_only = false;
+ bool require_system_version = false;
// Check the profile file. We need to rerun dex2oat if the profile has changed significantly
// since the last time, or it's new.
// If the 'defer' argument is true then this will be retried later. In this case we
// need to make sure that the profile file copy is not made so that we will get the
// same result second time.
+ std::string profile_file;
+ std::string prev_profile_file;
+ bool should_copy_profile = false;
if (Runtime::Current()->GetProfilerOptions().IsEnabled() && (pkgname != nullptr)) {
- const std::string profile_file = GetDalvikCacheOrDie("profiles", false /* create_if_absent */)
+ profile_file = GetDalvikCacheOrDie("profiles", false /* create_if_absent */)
+ std::string("/") + pkgname;
- const std::string prev_profile_file = profile_file + std::string("@old");
+ prev_profile_file = profile_file + std::string("@old");
struct stat profstat, prevstat;
int e1 = stat(profile_file.c_str(), &profstat);
+ int e1_errno = errno;
int e2 = stat(prev_profile_file.c_str(), &prevstat);
+ int e2_errno = errno;
if (e1 < 0) {
- // No profile file, need to run dex2oat
- if (kReasonLogging) {
- LOG(INFO) << "DexFile_isDexOptNeeded profile file " << profile_file << " doesn't exist";
+ if (e1_errno != EACCES) {
+ // No profile file, need to run dex2oat, unless we find a file in system
+ if (kReasonLogging) {
+ LOG(INFO) << "DexFile_isDexOptNeededInternal profile file " << profile_file << " doesn't exist. "
+ << "Will check odex to see if we can find a working version.";
+ }
+ // Force it to only accept system files/files with versions in system.
+ require_system_version = true;
+ } else {
+ LOG(INFO) << "DexFile_isDexOptNeededInternal recieved EACCES trying to stat profile file "
+ << profile_file;
}
- return JNI_TRUE;
- }
-
- if (e2 == 0) {
+ } else if (e2 == 0) {
// There is a previous profile file. Check if the profile has changed significantly.
// A change in profile is considered significant if X% (change_thr property) of the top K%
// (compile_thr property) samples has changed.
@@ -384,7 +439,7 @@
bool old_ok = old_profile.LoadFile(prev_profile_file);
if (!new_ok || !old_ok) {
if (kVerboseLogging) {
- LOG(INFO) << "DexFile_isDexOptNeeded Ignoring invalid profiles: "
+ LOG(INFO) << "DexFile_isDexOptNeededInternal Ignoring invalid profiles: "
<< (new_ok ? "" : profile_file) << " " << (old_ok ? "" : prev_profile_file);
}
} else {
@@ -393,7 +448,7 @@
old_profile.GetTopKSamples(old_top_k, top_k_threshold);
if (new_top_k.empty()) {
if (kVerboseLogging) {
- LOG(INFO) << "DexFile_isDexOptNeeded empty profile: " << profile_file;
+ LOG(INFO) << "DexFile_isDexOptNeededInternal empty profile: " << profile_file;
}
// If the new topK is empty we shouldn't optimize so we leave the change_percent at 0.0.
} else {
@@ -405,7 +460,7 @@
if (kVerboseLogging) {
std::set<std::string>::iterator end = diff.end();
for (std::set<std::string>::iterator it = diff.begin(); it != end; it++) {
- LOG(INFO) << "DexFile_isDexOptNeeded new in topK: " << *it;
+ LOG(INFO) << "DexFile_isDexOptNeededInternal new in topK: " << *it;
}
}
}
@@ -413,67 +468,84 @@
if (change_percent > change_threshold) {
if (kReasonLogging) {
- LOG(INFO) << "DexFile_isDexOptNeeded size of new profile file " << profile_file <<
+ LOG(INFO) << "DexFile_isDexOptNeededInternal size of new profile file " << profile_file <<
" is significantly different from old profile file " << prev_profile_file << " (top "
<< top_k_threshold << "% samples changed in proportion of " << change_percent << "%)";
}
- if (!defer) {
- CopyProfileFile(profile_file.c_str(), prev_profile_file.c_str());
- }
- return JNI_TRUE;
+ should_copy_profile = !defer;
+ // Force us to only accept system files.
+ force_system_only = true;
}
- } else {
+ } else if (e2_errno == ENOENT) {
// Previous profile does not exist. Make a copy of the current one.
if (kVerboseLogging) {
- LOG(INFO) << "DexFile_isDexOptNeeded previous profile doesn't exist: " << prev_profile_file;
+ LOG(INFO) << "DexFile_isDexOptNeededInternal previous profile doesn't exist: " << prev_profile_file;
}
- if (!defer) {
- CopyProfileFile(profile_file.c_str(), prev_profile_file.c_str());
- }
+ should_copy_profile = !defer;
+ } else {
+ PLOG(INFO) << "Unable to stat previous profile file " << prev_profile_file;
}
}
- // Check if we have an oat file in the cache
- const std::string cache_dir(GetDalvikCacheOrDie(instruction_set));
- const std::string cache_location(
- GetDalvikCacheFilenameOrDie(filename, cache_dir.c_str()));
- oat_file.reset(OatFile::Open(cache_location, filename, NULL, false, &error_msg));
- if (oat_file.get() == nullptr) {
- if (kReasonLogging) {
- LOG(INFO) << "DexFile_isDexOptNeeded cache file " << cache_location
- << " does not exist for " << filename << ": " << error_msg;
+ const InstructionSet target_instruction_set = GetInstructionSetFromString(instruction_set);
+
+ // Get the filename for odex file next to the dex file.
+ std::string odex_filename(DexFilenameToOdexFilename(filename, target_instruction_set));
+ // Get the filename for the dalvik-cache file
+ std::string cache_dir;
+ bool have_android_data = false;
+ bool dalvik_cache_exists = false;
+ GetDalvikCache(instruction_set, false, &cache_dir, &have_android_data, &dalvik_cache_exists);
+ std::string cache_filename; // was cache_location
+ bool have_cache_filename = false;
+ if (dalvik_cache_exists) {
+ std::string error_msg;
+ have_cache_filename = GetDalvikCacheFilename(filename, cache_dir.c_str(), &cache_filename,
+ &error_msg);
+ if (!have_cache_filename && kVerboseLogging) {
+ LOG(INFO) << "DexFile_isDexOptNeededInternal failed to find cache file for dex file " << filename
+ << ": " << error_msg;
}
- return JNI_TRUE;
}
- uint32_t location_checksum;
- if (!DexFile::GetChecksum(filename, &location_checksum, &error_msg)) {
- if (kReasonLogging) {
- LOG(ERROR) << "DexFile_isDexOptNeeded failed to compute checksum of " << filename
- << " (error " << error_msg << ")";
+ bool should_relocate_if_possible = Runtime::Current()->ShouldRelocate();
+
+ InstructionSet isa = Runtime::Current()->GetInstructionSet();
+ jbyte dalvik_cache_decision = -1;
+ // Lets try the cache first (since we want to load from there since thats where the relocated
+ // versions will be).
+ if (have_cache_filename && !force_system_only) {
+ // We can use the dalvik-cache if we find a good file.
+ dalvik_cache_decision =
+ IsDexOptNeededForFile<kVerboseLogging, kReasonLogging>(cache_filename, filename, isa);
+ // We will only return DexOptNeeded if both the cache and system return it.
+ if (dalvik_cache_decision != kDexoptNeeded && !require_system_version) {
+ CHECK(!(dalvik_cache_decision == kPatchoatNeeded && !should_relocate_if_possible))
+ << "May not return PatchoatNeeded when patching is disabled.";
+ return dalvik_cache_decision;
}
- return JNI_TRUE;
+ // We couldn't find one thats easy. We should now try the system.
}
- if (!ClassLinker::VerifyOatFileChecksums(oat_file.get(), filename, location_checksum,
- target_instruction_set, &error_msg)) {
- if (kReasonLogging) {
- LOG(INFO) << "DexFile_isDexOptNeeded cache file " << cache_location
- << " has out-of-date checksum compared to " << filename
- << " (error " << error_msg << ")";
- }
- return JNI_TRUE;
+ jbyte system_decision =
+ IsDexOptNeededForFile<kVerboseLogging, kReasonLogging>(odex_filename, filename, isa);
+ CHECK(!(system_decision == kPatchoatNeeded && !should_relocate_if_possible))
+ << "May not return PatchoatNeeded when patching is disabled.";
+
+ if (require_system_version && system_decision == kPatchoatNeeded
+ && dalvik_cache_decision == kUpToDate) {
+ // We have a version from system relocated to the cache. Return it.
+ return dalvik_cache_decision;
}
- if (kVerboseLogging) {
- LOG(INFO) << "DexFile_isDexOptNeeded cache file " << cache_location
- << " is up-to-date for " << filename;
+ if (should_copy_profile && system_decision == kDexoptNeeded) {
+ CopyProfileFile(profile_file.c_str(), prev_profile_file.c_str());
}
- CHECK(error_msg.empty()) << error_msg;
- return JNI_FALSE;
+
+ return system_decision;
}
-static jboolean DexFile_isDexOptNeededInternal(JNIEnv* env, jclass, jstring javaFilename,
+static jbyte DexFile_isDexOptNeededInternal(JNIEnv* env, jclass, jstring javaFilename,
jstring javaPkgname, jstring javaInstructionSet, jboolean defer) {
ScopedUtfChars filename(env, javaFilename);
NullableScopedUtfChars pkgname(env, javaPkgname);
@@ -487,8 +559,8 @@
static jboolean DexFile_isDexOptNeeded(JNIEnv* env, jclass, jstring javaFilename) {
const char* instruction_set = GetInstructionSetString(kRuntimeISA);
ScopedUtfChars filename(env, javaFilename);
- return IsDexOptNeededInternal(env, filename.c_str(), nullptr /* pkgname */,
- instruction_set, false /* defer */);
+ return kUpToDate != IsDexOptNeededInternal(env, filename.c_str(), nullptr /* pkgname */,
+ instruction_set, false /* defer */);
}
@@ -497,7 +569,7 @@
NATIVE_METHOD(DexFile, defineClassNative, "(Ljava/lang/String;Ljava/lang/ClassLoader;J)Ljava/lang/Class;"),
NATIVE_METHOD(DexFile, getClassNameList, "(J)[Ljava/lang/String;"),
NATIVE_METHOD(DexFile, isDexOptNeeded, "(Ljava/lang/String;)Z"),
- NATIVE_METHOD(DexFile, isDexOptNeededInternal, "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Z)Z"),
+ NATIVE_METHOD(DexFile, isDexOptNeededInternal, "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Z)B"),
NATIVE_METHOD(DexFile, openDexFile, "(Ljava/lang/String;Ljava/lang/String;I)J"),
};
diff --git a/runtime/parsed_options.h b/runtime/parsed_options.h
index 668ed9e..3dbe26f 100644
--- a/runtime/parsed_options.h
+++ b/runtime/parsed_options.h
@@ -48,8 +48,6 @@
std::string native_bridge_library_string_;
CompilerCallbacks* compiler_callbacks_;
bool is_zygote_;
- // TODO Change this to true when we want it on by default.
- static constexpr bool kDefaultMustRelocate = false;
bool must_relocate_;
std::string patchoat_executable_;
bool interpreter_only_;
diff --git a/runtime/utils.cc b/runtime/utils.cc
index 52cdcc1..4d49809 100644
--- a/runtime/utils.cc
+++ b/runtime/utils.cc
@@ -1236,7 +1236,7 @@
return false;
}
std::string cache_file(&location[1]); // skip leading slash
- if (!EndsWith(location, ".dex") && !EndsWith(location, ".art")) {
+ if (!EndsWith(location, ".dex") && !EndsWith(location, ".art") && !EndsWith(location, ".oat")) {
cache_file += "/";
cache_file += DexFile::kClassesDex;
}
diff --git a/runtime/utils_test.cc b/runtime/utils_test.cc
index 7cd5980..d6c90e1 100644
--- a/runtime/utils_test.cc
+++ b/runtime/utils_test.cc
@@ -350,6 +350,8 @@
GetDalvikCacheFilenameOrDie("/system/framework/core.jar", "/foo").c_str());
EXPECT_STREQ("/foo/system@framework@boot.art",
GetDalvikCacheFilenameOrDie("/system/framework/boot.art", "/foo").c_str());
+ EXPECT_STREQ("/foo/system@framework@boot.oat",
+ GetDalvikCacheFilenameOrDie("/system/framework/boot.oat", "/foo").c_str());
}
TEST_F(UtilsTest, GetSystemImageFilename) {