summaryrefslogtreecommitdiffstats
path: root/runtime/class_linker.cc
diff options
context:
space:
mode:
authorAndreas Gampe <agampe@google.com>2015-04-29 20:47:16 -0700
committerAndreas Gampe <agampe@google.com>2015-04-29 20:47:16 -0700
commit0cba004b97245300d7f39318d5921ee8edbef1ac (patch)
treeedef4ed18df47c3c033c33b14bdd2aa6652f8696 /runtime/class_linker.cc
parenteff3229ff3c8faead4b6d400e273ee27b7004dab (diff)
downloadart-0cba004b97245300d7f39318d5921ee8edbef1ac.zip
art-0cba004b97245300d7f39318d5921ee8edbef1ac.tar.gz
art-0cba004b97245300d7f39318d5921ee8edbef1ac.tar.bz2
ART: Allow oat files with duplicates classes in corner case
When the oat file is actually an odex file, that is, a preopted /system app, then it is impossible to fall back to the original APK, as that has been stripped. When it looks like it will be impossible to successfully open the original dex location, grudgingly allow to open the found oat file, even if it has duplicate classes, but warn accordingly. Bug: 20697582 Change-Id: I1dd459563d977a2e77806eacd03e49334d5b1f14
Diffstat (limited to 'runtime/class_linker.cc')
-rw-r--r--runtime/class_linker.cc82
1 files changed, 47 insertions, 35 deletions
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 962e821..b099088 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -82,10 +82,6 @@ namespace art {
static constexpr bool kSanityCheckObjects = kIsDebugBuild;
-// Do a simple class redefinition check in OpenDexFilesFromOat. This is a conservative check to
-// avoid problems with compile-time class-path != runtime class-path.
-static constexpr bool kCheckForDexCollisions = true;
-
static void ThrowNoClassDefFoundError(const char* fmt, ...)
__attribute__((__format__(__printf__, 1, 2)))
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -743,6 +739,8 @@ class DexFileAndClassPair : ValueObject {
const char* rhsDescriptor = rhs.cached_descriptor_;
int cmp = strcmp(lhsDescriptor, rhsDescriptor);
if (cmp != 0) {
+ // Note that the order must be reversed. We want to iterate over the classes in dex files.
+ // They are sorted lexicographically. Thus, the priority-queue must be a min-queue.
return cmp > 0;
}
return dex_file_ < rhs.dex_file_;
@@ -768,6 +766,11 @@ class DexFileAndClassPair : ValueObject {
return dex_file_;
}
+ void DeleteDexFile() {
+ delete dex_file_;
+ dex_file_ = nullptr;
+ }
+
private:
static const char* GetClassDescriptor(const DexFile* dex_file, size_t index) {
const DexFile::ClassDef& class_def = dex_file->GetClassDef(static_cast<uint16_t>(index));
@@ -799,13 +802,13 @@ static void AddDexFilesFromOat(const OatFile* oat_file, bool already_loaded,
}
}
-static void AddNext(const DexFileAndClassPair& original,
+static void AddNext(DexFileAndClassPair* original,
std::priority_queue<DexFileAndClassPair>* heap) {
- if (original.DexFileHasMoreClasses()) {
- heap->push(original.GetNext());
+ if (original->DexFileHasMoreClasses()) {
+ heap->push(original->GetNext());
} else {
// Need to delete the dex file.
- delete original.GetDexFile();
+ original->DeleteDexFile();
}
}
@@ -824,19 +827,17 @@ static void FreeDexFilesInHeap(std::priority_queue<DexFileAndClassPair>* heap) {
// the two elements agree on whether their dex file was from an already-loaded oat-file or the
// new oat file. Any disagreement indicates a collision.
bool ClassLinker::HasCollisions(const OatFile* oat_file, std::string* error_msg) {
- if (!kCheckForDexCollisions) {
- return false;
- }
-
// Dex files are registered late - once a class is actually being loaded. We have to compare
- // against the open oat files.
+ // against the open oat files. Take the dex_lock_ that protects oat_files_ accesses.
ReaderMutexLock mu(Thread::Current(), dex_lock_);
- std::priority_queue<DexFileAndClassPair> heap;
+ std::priority_queue<DexFileAndClassPair> queue;
// Add dex files from already loaded oat files, but skip boot.
{
- // To grab the boot oat, look at the dex files in the boot classpath.
+ // To grab the boot oat, look at the dex files in the boot classpath. Any of those is fine, as
+ // they were all compiled into the same oat file. So grab the first one, which is guaranteed to
+ // exist if the boot class-path isn't empty.
const OatFile* boot_oat = nullptr;
if (!boot_class_path_.empty()) {
const DexFile* boot_dex_file = boot_class_path_[0];
@@ -850,26 +851,26 @@ bool ClassLinker::HasCollisions(const OatFile* oat_file, std::string* error_msg)
if (loaded_oat_file == boot_oat) {
continue;
}
- AddDexFilesFromOat(loaded_oat_file, true, &heap);
+ AddDexFilesFromOat(loaded_oat_file, true, &queue);
}
}
- if (heap.empty()) {
+ if (queue.empty()) {
// No other oat files, return early.
return false;
}
// Add dex files from the oat file to check.
- AddDexFilesFromOat(oat_file, false, &heap);
+ AddDexFilesFromOat(oat_file, false, &queue);
- // Now drain the heap.
- while (!heap.empty()) {
- DexFileAndClassPair compare_pop = heap.top();
- heap.pop();
+ // Now drain the queue.
+ while (!queue.empty()) {
+ DexFileAndClassPair compare_pop = queue.top();
+ queue.pop();
// Compare against the following elements.
- while (!heap.empty()) {
- DexFileAndClassPair top = heap.top();
+ while (!queue.empty()) {
+ DexFileAndClassPair top = queue.top();
if (strcmp(compare_pop.GetCachedDescriptor(), top.GetCachedDescriptor()) == 0) {
// Same descriptor. Check whether it's crossing old-oat-files to new-oat-files.
@@ -879,18 +880,18 @@ bool ClassLinker::HasCollisions(const OatFile* oat_file, std::string* error_msg)
compare_pop.GetCachedDescriptor(),
compare_pop.GetDexFile()->GetLocation().c_str(),
top.GetDexFile()->GetLocation().c_str());
- FreeDexFilesInHeap(&heap);
+ FreeDexFilesInHeap(&queue);
return true;
}
// Pop it.
- heap.pop();
- AddNext(top, &heap);
+ queue.pop();
+ AddNext(&top, &queue);
} else {
// Something else. Done here.
break;
}
}
- AddNext(compare_pop, &heap);
+ AddNext(&compare_pop, &queue);
}
return false;
@@ -941,11 +942,10 @@ std::vector<std::unique_ptr<const DexFile>> ClassLinker::OpenDexFilesFromOat(
// Get the oat file on disk.
std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
if (oat_file.get() != nullptr) {
- // Take the file only if it has no collisions.
- if (!HasCollisions(oat_file.get(), &error_msg)) {
- source_oat_file = oat_file.release();
- RegisterOatFile(source_oat_file);
- } else {
+ // Take the file only if it has no collisions, or we must take it because of preopting.
+ bool accept_oat_file = !HasCollisions(oat_file.get(), &error_msg);
+ if (!accept_oat_file) {
+ // Failed the collision check. Print warning.
if (Runtime::Current()->IsDexFileFallbackEnabled()) {
LOG(WARNING) << "Found duplicate classes, falling back to interpreter mode for "
<< dex_location;
@@ -954,6 +954,19 @@ std::vector<std::unique_ptr<const DexFile>> ClassLinker::OpenDexFilesFromOat(
" load classes for " << dex_location;
}
LOG(WARNING) << error_msg;
+
+ // However, if the app was part of /system and preopted, there is no original dex file
+ // available. In that case grudgingly accept the oat file.
+ if (!DexFile::MaybeDex(dex_location)) {
+ accept_oat_file = true;
+ LOG(WARNING) << "Dex location " << dex_location << " does not seem to include dex file. "
+ << "Allow oat file use. This is potentially dangerous.";
+ }
+ }
+
+ if (accept_oat_file) {
+ source_oat_file = oat_file.release();
+ RegisterOatFile(source_oat_file);
}
}
}
@@ -975,8 +988,7 @@ std::vector<std::unique_ptr<const DexFile>> ClassLinker::OpenDexFilesFromOat(
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));
+ 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.");