Verify the class loader context when loading oat files
Previously, the oat_file_manager would expect and perform validation on a
simple classpath: a list of dex files separated by ':'.
This is no longer enough since the oat file may encode a chain of class
loaders now. The CL moves the validation logic in ClassLoaderContext and
extends it to verify the complete chain of class loaders.
Test: m test-art-host
Bug: 38138251
Change-Id: I8ac9c65db1a14909aaecb04fa7a7115ddedc673f
diff --git a/runtime/class_loader_context.cc b/runtime/class_loader_context.cc
index a6e5c21..678ae8f 100644
--- a/runtime/class_loader_context.cc
+++ b/runtime/class_loader_context.cc
@@ -353,38 +353,6 @@
<< "attempt=" << dex_files_open_attempted_ << ", result=" << dex_files_open_result_;
}
-bool ClassLoaderContext::DecodePathClassLoaderContextFromOatFileKey(
- const std::string& context_spec,
- std::vector<std::string>* out_classpath,
- std::vector<uint32_t>* out_checksums,
- bool* out_is_special_shared_library) {
- ClassLoaderContext context;
- if (!context.Parse(context_spec, /*parse_checksums*/ true)) {
- LOG(ERROR) << "Invalid class loader context: " << context_spec;
- return false;
- }
-
- *out_is_special_shared_library = context.special_shared_library_;
- if (context.special_shared_library_) {
- return true;
- }
-
- if (context.class_loader_chain_.empty()) {
- return true;
- }
-
- // TODO(calin): assert that we only have a PathClassLoader until the logic for
- // checking the context covers all case.
- CHECK_EQ(1u, context.class_loader_chain_.size());
- const ClassLoaderInfo& info = context.class_loader_chain_[0];
- CHECK_EQ(kPathClassLoader, info.type);
- DCHECK_EQ(info.classpath.size(), info.checksums.size());
-
- *out_classpath = info.classpath;
- *out_checksums = info.checksums;
- return true;
-}
-
// Collects the dex files from the give Java dex_file object. Only the dex files with
// at least 1 class are collected. If a null java_dex_file is passed this method does nothing.
static bool CollectDexFilesFromJavaDexFile(ObjPtr<mirror::Object> java_dex_file,
@@ -583,6 +551,8 @@
std::unique_ptr<ClassLoaderContext> ClassLoaderContext::CreateContextForClassLoader(
jobject class_loader,
jobjectArray dex_elements) {
+ CHECK(class_loader != nullptr);
+
ScopedObjectAccess soa(Thread::Current());
StackHandleScope<2> hs(soa.Self());
Handle<mirror::ClassLoader> h_class_loader =
@@ -590,8 +560,6 @@
Handle<mirror::ObjectArray<mirror::Object>> h_dex_elements =
hs.NewHandle(soa.Decode<mirror::ObjectArray<mirror::Object>>(dex_elements));
- CHECK(h_class_loader != nullptr);
-
std::unique_ptr<ClassLoaderContext> result(new ClassLoaderContext(/*owns_the_dex_files*/ false));
if (result->AddInfoToContextFromClassLoader(soa, h_class_loader, h_dex_elements)) {
return result;
@@ -600,5 +568,60 @@
}
}
+bool ClassLoaderContext::VerifyClassLoaderContextMatch(const std::string& context_spec) {
+ ClassLoaderContext expected_context;
+ if (!expected_context.Parse(context_spec, /*parse_checksums*/ true)) {
+ LOG(WARNING) << "Invalid class loader context: " << context_spec;
+ return false;
+ }
+
+ if (expected_context.special_shared_library_) {
+ return true;
+ }
+
+ if (expected_context.class_loader_chain_.size() != class_loader_chain_.size()) {
+ LOG(WARNING) << "ClassLoaderContext size mismatch. expected="
+ << expected_context.class_loader_chain_.size()
+ << ", actual=" << class_loader_chain_.size();
+ return false;
+ }
+
+ for (size_t i = 0; i < class_loader_chain_.size(); i++) {
+ const ClassLoaderInfo& info = class_loader_chain_[i];
+ const ClassLoaderInfo& expected_info = expected_context.class_loader_chain_[i];
+ if (info.type != expected_info.type) {
+ LOG(WARNING) << "ClassLoaderContext type mismatch for position " << i
+ << ". expected=" << GetClassLoaderTypeName(expected_info.type)
+ << ", found=" << GetClassLoaderTypeName(info.type);
+ return false;
+ }
+ if (info.classpath.size() != expected_info.classpath.size()) {
+ LOG(WARNING) << "ClassLoaderContext classpath size mismatch for position " << i
+ << ". expected=" << expected_info.classpath.size()
+ << ", found=" << info.classpath.size();
+ return false;
+ }
+
+ DCHECK_EQ(info.classpath.size(), info.checksums.size());
+ DCHECK_EQ(expected_info.classpath.size(), expected_info.checksums.size());
+
+ for (size_t k = 0; k < info.classpath.size(); k++) {
+ if (info.classpath[k] != expected_info.classpath[k]) {
+ LOG(WARNING) << "ClassLoaderContext classpath element mismatch for position " << i
+ << ". expected=" << expected_info.classpath[k]
+ << ", found=" << info.classpath[k];
+ return false;
+ }
+ if (info.checksums[k] != expected_info.checksums[k]) {
+ LOG(WARNING) << "ClassLoaderContext classpath element checksum mismatch for position " << i
+ << ". expected=" << expected_info.checksums[k]
+ << ", found=" << info.checksums[k];
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
} // namespace art
diff --git a/runtime/class_loader_context.h b/runtime/class_loader_context.h
index 81c8903..8c65e2e 100644
--- a/runtime/class_loader_context.h
+++ b/runtime/class_loader_context.h
@@ -78,6 +78,13 @@
// Should only be called if OpenDexFiles() returned true.
std::vector<const DexFile*> FlattenOpenedDexFiles() const;
+ // Verifies that the current context is identical to the context encoded as `context_spec`.
+ // Identical means:
+ // - the number and type of the class loaders from the chain matches
+ // - the class loader from the same position have the same classpath
+ // (the order and checksum of the dex files matches)
+ bool VerifyClassLoaderContextMatch(const std::string& context_spec);
+
// Creates the class loader context from the given string.
// The format: ClassLoaderType1[ClasspathElem1:ClasspathElem2...];ClassLoaderType2[...]...
// ClassLoaderType is either "PCL" (PathClassLoader) or "DLC" (DelegateLastClassLoader).
@@ -86,17 +93,6 @@
// class loader for the source dex files.
static std::unique_ptr<ClassLoaderContext> Create(const std::string& spec);
- // Decodes the class loader context stored in the oat file with EncodeContextForOatFile.
- // Returns true if the format matches, or false otherwise. If the return is true, the out
- // arguments will contain the classpath dex files, their checksums and whether or not the
- // context is a special shared library.
- // The method asserts that the context is made out of only one PathClassLoader.
- static bool DecodePathClassLoaderContextFromOatFileKey(
- const std::string& context_spec,
- std::vector<std::string>* out_classpath,
- std::vector<uint32_t>* out_checksums,
- bool* out_is_special_shared_library);
-
// Creates a context for the given class_loader and dex_elements.
// The method will walk the parent chain starting from `class_loader` and add their dex files
// to the current class loaders chain. The `dex_elements` will be added at the end of the
diff --git a/runtime/class_loader_context_test.cc b/runtime/class_loader_context_test.cc
index 50905c4..659db4b 100644
--- a/runtime/class_loader_context_test.cc
+++ b/runtime/class_loader_context_test.cc
@@ -101,6 +101,14 @@
return ClassLoaderContext::CreateContextForClassLoader(class_loader, nullptr);
}
+ std::unique_ptr<ClassLoaderContext> ParseContextWithChecksums(const std::string& context_spec) {
+ std::unique_ptr<ClassLoaderContext> context(new ClassLoaderContext());
+ if (!context->Parse(context_spec, /*parse_checksums*/ true)) {
+ return nullptr;
+ }
+ return context;
+ }
+
void VerifyContextForClassLoader(ClassLoaderContext* context) {
ASSERT_TRUE(context != nullptr);
ASSERT_TRUE(context->dex_files_open_attempted_);
@@ -336,42 +344,6 @@
ASSERT_EQ(expected_encoding, context->EncodeContextForOatFile(""));
}
-TEST_F(ClassLoaderContextTest, DecodeOatFileKey) {
- std::string oat_file_encoding = "PCL[a.dex*123:b.dex*456]";
- std::vector<std::string> classpath;
- std::vector<uint32_t> checksums;
- bool is_special_shared_library;
- bool result = ClassLoaderContext::DecodePathClassLoaderContextFromOatFileKey(
- oat_file_encoding,
- &classpath,
- &checksums,
- &is_special_shared_library);
- ASSERT_TRUE(result);
- ASSERT_FALSE(is_special_shared_library);
- ASSERT_EQ(2u, classpath.size());
- ASSERT_EQ(2u, checksums.size());
- ASSERT_EQ("a.dex", classpath[0]);
- ASSERT_EQ(123u, checksums[0]);
- ASSERT_EQ("b.dex", classpath[1]);
- ASSERT_EQ(456u, checksums[1]);
-}
-
-TEST_F(ClassLoaderContextTest, DecodeOatFileKeySpecialLibrary) {
- std::string oat_file_encoding = "&";
- std::vector<std::string> classpath;
- std::vector<uint32_t> checksums;
- bool is_special_shared_library;
- bool result = ClassLoaderContext::DecodePathClassLoaderContextFromOatFileKey(
- oat_file_encoding,
- &classpath,
- &checksums,
- &is_special_shared_library);
- ASSERT_TRUE(result);
- ASSERT_TRUE(is_special_shared_library);
- ASSERT_TRUE(classpath.empty());
- ASSERT_TRUE(checksums.empty());
-}
-
// TODO(calin) add a test which creates the context for a class loader together with dex_elements.
TEST_F(ClassLoaderContextTest, CreateContextForClassLoader) {
// The chain is
@@ -402,4 +374,47 @@
VerifyClassLoaderPCLFromTestDex(context.get(), 3, "ForClassLoaderA");
}
+TEST_F(ClassLoaderContextTest, VerifyClassLoaderContextMatch) {
+ std::string context_spec = "PCL[a.dex*123:b.dex*456];DLC[c.dex*890]";
+ std::unique_ptr<ClassLoaderContext> context = ParseContextWithChecksums(context_spec);
+
+ VerifyContextSize(context.get(), 2);
+ VerifyClassLoaderPCL(context.get(), 0, "a.dex:b.dex");
+ VerifyClassLoaderDLC(context.get(), 1, "c.dex");
+
+ ASSERT_TRUE(context->VerifyClassLoaderContextMatch(context_spec));
+
+ std::string wrong_class_loader_type = "PCL[a.dex*123:b.dex*456];PCL[c.dex*890]";
+ ASSERT_FALSE(context->VerifyClassLoaderContextMatch(wrong_class_loader_type));
+
+ std::string wrong_class_loader_order = "DLC[c.dex*890];PCL[a.dex*123:b.dex*456]";
+ ASSERT_FALSE(context->VerifyClassLoaderContextMatch(wrong_class_loader_order));
+
+ std::string wrong_classpath_order = "PCL[b.dex*456:a.dex*123];DLC[c.dex*890]";
+ ASSERT_FALSE(context->VerifyClassLoaderContextMatch(wrong_classpath_order));
+
+ std::string wrong_checksum = "PCL[a.dex*999:b.dex*456];DLC[c.dex*890]";
+ ASSERT_FALSE(context->VerifyClassLoaderContextMatch(wrong_checksum));
+
+ std::string wrong_extra_class_loader = "PCL[a.dex*123:b.dex*456];DLC[c.dex*890];PCL[d.dex*321]";
+ ASSERT_FALSE(context->VerifyClassLoaderContextMatch(wrong_extra_class_loader));
+
+ std::string wrong_extra_classpath = "PCL[a.dex*123:b.dex*456];DLC[c.dex*890:d.dex*321]";
+ ASSERT_FALSE(context->VerifyClassLoaderContextMatch(wrong_extra_classpath));
+
+ std::string wrong_spec = "PCL[a.dex*999:b.dex*456];DLC[";
+ ASSERT_FALSE(context->VerifyClassLoaderContextMatch(wrong_spec));
+}
+
+TEST_F(ClassLoaderContextTest, VerifyClassLoaderContextMatchAfterEncoding) {
+ jobject class_loader_a = LoadDexInPathClassLoader("ForClassLoaderA", nullptr);
+ jobject class_loader_b = LoadDexInDelegateLastClassLoader("ForClassLoaderB", class_loader_a);
+ jobject class_loader_c = LoadDexInPathClassLoader("ForClassLoaderC", class_loader_b);
+ jobject class_loader_d = LoadDexInDelegateLastClassLoader("ForClassLoaderD", class_loader_c);
+
+ std::unique_ptr<ClassLoaderContext> context = CreateContextForClassLoader(class_loader_d);
+
+ ASSERT_TRUE(context->VerifyClassLoaderContextMatch(context->EncodeContextForOatFile("")));
+}
+
} // namespace art
diff --git a/runtime/oat_file_manager.cc b/runtime/oat_file_manager.cc
index b166961..cba85ad 100644
--- a/runtime/oat_file_manager.cc
+++ b/runtime/oat_file_manager.cc
@@ -264,212 +264,6 @@
}
}
-template <typename T>
-static void IterateOverJavaDexFile(ObjPtr<mirror::Object> dex_file,
- ArtField* const cookie_field,
- const T& fn)
- REQUIRES_SHARED(Locks::mutator_lock_) {
- if (dex_file != nullptr) {
- mirror::LongArray* long_array = cookie_field->GetObject(dex_file)->AsLongArray();
- if (long_array == nullptr) {
- // This should never happen so log a warning.
- LOG(WARNING) << "Null DexFile::mCookie";
- return;
- }
- int32_t long_array_size = long_array->GetLength();
- // Start from 1 to skip the oat file.
- for (int32_t j = 1; j < long_array_size; ++j) {
- const DexFile* cp_dex_file = reinterpret_cast<const DexFile*>(static_cast<uintptr_t>(
- long_array->GetWithoutChecks(j)));
- if (!fn(cp_dex_file)) {
- return;
- }
- }
- }
-}
-
-template <typename T>
-static void IterateOverPathClassLoader(
- Handle<mirror::ClassLoader> class_loader,
- MutableHandle<mirror::ObjectArray<mirror::Object>> dex_elements,
- const T& fn) REQUIRES_SHARED(Locks::mutator_lock_) {
- // Handle this step.
- // Handle as if this is the child PathClassLoader.
- // The class loader is a PathClassLoader which inherits from BaseDexClassLoader.
- // We need to get the DexPathList and loop through it.
- ArtField* const cookie_field =
- jni::DecodeArtField(WellKnownClasses::dalvik_system_DexFile_cookie);
- ArtField* const dex_file_field =
- jni::DecodeArtField(WellKnownClasses::dalvik_system_DexPathList__Element_dexFile);
- ObjPtr<mirror::Object> dex_path_list =
- jni::DecodeArtField(WellKnownClasses::dalvik_system_BaseDexClassLoader_pathList)->
- GetObject(class_loader.Get());
- if (dex_path_list != nullptr && dex_file_field != nullptr && cookie_field != nullptr) {
- // DexPathList has an array dexElements of Elements[] which each contain a dex file.
- ObjPtr<mirror::Object> dex_elements_obj =
- jni::DecodeArtField(WellKnownClasses::dalvik_system_DexPathList_dexElements)->
- GetObject(dex_path_list);
- // Loop through each dalvik.system.DexPathList$Element's dalvik.system.DexFile and look
- // at the mCookie which is a DexFile vector.
- if (dex_elements_obj != nullptr) {
- dex_elements.Assign(dex_elements_obj->AsObjectArray<mirror::Object>());
- for (int32_t i = 0; i < dex_elements->GetLength(); ++i) {
- mirror::Object* element = dex_elements->GetWithoutChecks(i);
- if (element == nullptr) {
- // Should never happen, fall back to java code to throw a NPE.
- break;
- }
- ObjPtr<mirror::Object> dex_file = dex_file_field->GetObject(element);
- IterateOverJavaDexFile(dex_file, cookie_field, fn);
- }
- }
- }
-}
-
-static bool GetDexFilesFromClassLoader(
- ScopedObjectAccessAlreadyRunnable& soa,
- mirror::ClassLoader* class_loader,
- std::vector<const DexFile*>* dex_files)
- REQUIRES_SHARED(Locks::mutator_lock_) {
- if (ClassLinker::IsBootClassLoader(soa, class_loader)) {
- // The boot class loader. We don't load any of these files, as we know we compiled against
- // them correctly.
- return true;
- }
-
- // Unsupported class-loader?
- if (soa.Decode<mirror::Class>(WellKnownClasses::dalvik_system_PathClassLoader) !=
- class_loader->GetClass()) {
- VLOG(class_linker) << "Unsupported class-loader "
- << mirror::Class::PrettyClass(class_loader->GetClass());
- return false;
- }
-
- bool recursive_result = GetDexFilesFromClassLoader(soa, class_loader->GetParent(), dex_files);
- if (!recursive_result) {
- // Something wrong up the chain.
- return false;
- }
-
- // Collect all the dex files.
- auto GetDexFilesFn = [&] (const DexFile* cp_dex_file)
- REQUIRES_SHARED(Locks::mutator_lock_) {
- if (cp_dex_file->NumClassDefs() > 0) {
- dex_files->push_back(cp_dex_file);
- }
- return true; // Continue looking.
- };
-
- // Handle for dex-cache-element.
- StackHandleScope<3> hs(soa.Self());
- MutableHandle<mirror::ObjectArray<mirror::Object>> dex_elements(
- hs.NewHandle<mirror::ObjectArray<mirror::Object>>(nullptr));
- Handle<mirror::ClassLoader> h_class_loader(hs.NewHandle(class_loader));
-
- IterateOverPathClassLoader(h_class_loader, dex_elements, GetDexFilesFn);
-
- return true;
-}
-
-static void GetDexFilesFromDexElementsArray(
- ScopedObjectAccessAlreadyRunnable& soa,
- Handle<mirror::ObjectArray<mirror::Object>> dex_elements,
- std::vector<const DexFile*>* dex_files)
- REQUIRES_SHARED(Locks::mutator_lock_) {
- if (dex_elements == nullptr) {
- // Nothing to do.
- return;
- }
-
- ArtField* const cookie_field =
- jni::DecodeArtField(WellKnownClasses::dalvik_system_DexFile_cookie);
- ArtField* const dex_file_field =
- jni::DecodeArtField(WellKnownClasses::dalvik_system_DexPathList__Element_dexFile);
- ObjPtr<mirror::Class> const element_class = soa.Decode<mirror::Class>(
- WellKnownClasses::dalvik_system_DexPathList__Element);
- ObjPtr<mirror::Class> const dexfile_class = soa.Decode<mirror::Class>(
- WellKnownClasses::dalvik_system_DexFile);
-
- // Collect all the dex files.
- auto GetDexFilesFn = [&] (const DexFile* cp_dex_file)
- REQUIRES_SHARED(Locks::mutator_lock_) {
- if (cp_dex_file != nullptr && cp_dex_file->NumClassDefs() > 0) {
- dex_files->push_back(cp_dex_file);
- }
- return true; // Continue looking.
- };
-
- for (int32_t i = 0; i < dex_elements->GetLength(); ++i) {
- mirror::Object* element = dex_elements->GetWithoutChecks(i);
- if (element == nullptr) {
- continue;
- }
-
- // We support this being dalvik.system.DexPathList$Element and dalvik.system.DexFile.
-
- ObjPtr<mirror::Object> dex_file;
- if (element_class == element->GetClass()) {
- dex_file = dex_file_field->GetObject(element);
- } else if (dexfile_class == element->GetClass()) {
- dex_file = element;
- } else {
- LOG(WARNING) << "Unsupported element in dex_elements: "
- << mirror::Class::PrettyClass(element->GetClass());
- continue;
- }
-
- IterateOverJavaDexFile(dex_file, cookie_field, GetDexFilesFn);
- }
-}
-
-static bool AreSharedLibrariesOk(const std::string& context_spec,
- std::vector<const DexFile*>& dex_files,
- std::string* error_msg) {
- std::vector<std::string> classpath;
- std::vector<uint32_t> checksums;
- bool is_special_shared_library;
- if (!ClassLoaderContext::DecodePathClassLoaderContextFromOatFileKey(
- context_spec, &classpath, &checksums, &is_special_shared_library)) {
- *error_msg = "Could not decode the class loader context from the oat file key.";
- return false;
- }
-
- DCHECK_EQ(classpath.size(), checksums.size());
-
- // The classpath size should match the number of dex files.
- if (classpath.size() != dex_files.size()) {
- *error_msg = "The number of loaded dex files does not match the number of files "
- "specified in the context. Expected=" + std::to_string(classpath.size()) +
- ", found=" + std::to_string(dex_files.size());
- return false;
- }
-
- // If we find the special shared library, skip the shared libraries check.
- if (is_special_shared_library) {
- return true;
- }
-
- // Check that the loaded dex files have the same order and checksums as the shared libraries.
- for (size_t i = 0; i < dex_files.size(); ++i) {
- const std::string& dex_location = dex_files[i]->GetLocation();
- uint32_t dex_location_checksum = dex_files[i]->GetLocationChecksum();
- std::string absolute_library_path =
- OatFile::ResolveRelativeEncodedDexLocation(dex_location.c_str(), classpath[i]);
- if (dex_location != absolute_library_path) {
- *error_msg = "SharedLibraryCheck: expected=" + absolute_library_path + ", found=" +
- dex_location;
- return false;
- }
- if (dex_location_checksum != checksums[i]) {
- *error_msg = "SharedLibraryCheck: checksum mismatch for " + dex_location + ". Expected=" +
- std::to_string(checksums[i]) + ", found=" + std::to_string(dex_location_checksum);
- return false;
- }
- }
-
- return true;
-}
-
static bool CollisionCheck(std::vector<const DexFile*>& dex_files_loaded,
std::vector<const DexFile*>& dex_files_unloaded,
std::string* error_msg /*out*/) {
@@ -554,52 +348,38 @@
DCHECK(oat_file != nullptr);
DCHECK(error_msg != nullptr);
- std::vector<const DexFile*> dex_files_loaded;
-
- // Try to get dex files from the given class loader. If the class loader is null, or we do
- // not support one of the class loaders in the chain, we do nothing and assume the collision
- // check has succeeded.
- bool class_loader_ok = false;
- {
- ScopedObjectAccess soa(Thread::Current());
- StackHandleScope<2> hs(Thread::Current());
- Handle<mirror::ClassLoader> h_class_loader =
- hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader));
- Handle<mirror::ObjectArray<mirror::Object>> h_dex_elements =
- hs.NewHandle(soa.Decode<mirror::ObjectArray<mirror::Object>>(dex_elements));
- if (h_class_loader != nullptr &&
- GetDexFilesFromClassLoader(soa, h_class_loader.Get(), &dex_files_loaded)) {
- class_loader_ok = true;
-
- // In this case, also take into account the dex_elements array, if given. We don't need to
- // read it otherwise, as we'll compare against all open oat files anyways.
- GetDexFilesFromDexElementsArray(soa, h_dex_elements, &dex_files_loaded);
- } else if (h_class_loader != nullptr) {
- VLOG(class_linker) << "Something unsupported with "
- << mirror::Class::PrettyClass(h_class_loader->GetClass());
-
- // This is a class loader we don't recognize. Our earlier strategy would
- // be to perform a global duplicate class check (with all loaded oat files)
- // but that seems overly conservative - we have no way of knowing that
- // those files are present in the same loader hierarchy. Among other
- // things, it hurt GMS core and its filtering class loader.
- }
+ // If the class_loader is null there's not much we can do. This happens if a dex files is loaded
+ // directly with DexFile APIs instead of using class loaders.
+ if (class_loader == nullptr) {
+ LOG(WARNING) << "Opening an oat file without a class loader. "
+ << "Are you using the deprecated DexFile APIs?";
+ return false;
}
- // Exit if we find a class loader we don't recognize. Proceed to check shared
- // libraries and do a full class loader check otherwise.
- if (!class_loader_ok) {
- LOG(WARNING) << "Skipping duplicate class check due to unrecognized classloader";
+ std::unique_ptr<ClassLoaderContext> context =
+ ClassLoaderContext::CreateContextForClassLoader(class_loader, dex_elements);
+
+ // The context might be null if there are unrecognized class loaders in the chain or they
+ // don't meet sensible sanity conditions. In this case we assume that the app knows what it's
+ // doing and accept the oat file.
+ // Note that this has correctness implications as we cannot guarantee that the class resolution
+ // used during compilation is OK (b/37777332).
+ if (context == nullptr) {
+ LOG(WARNING) << "Skipping duplicate class check due to unsupported classloader";
return false;
}
- // Exit if shared libraries are ok. Do a full duplicate classes check otherwise.
- const std::string
- shared_libraries(oat_file->GetOatHeader().GetStoreValueByKey(OatHeader::kClassPathKey));
- if (AreSharedLibrariesOk(shared_libraries, dex_files_loaded, error_msg)) {
+ // If the pat file loading context matches the context used during compilation then we accept
+ // the oat file without addition checks
+ if (context->VerifyClassLoaderContextMatch(
+ oat_file->GetOatHeader().GetStoreValueByKey(OatHeader::kClassPathKey))) {
return false;
}
+ // The class loader context does not match. Perform a full duplicate classes check.
+
+ std::vector<const DexFile*> dex_files_loaded = context->FlattenOpenedDexFiles();
+
// Vector that holds the newly opened dex files live, this is done to prevent leaks.
std::vector<std::unique_ptr<const DexFile>> opened_dex_files;