summaryrefslogtreecommitdiff
path: root/runtime/class_linker.cc
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/class_linker.cc')
-rw-r--r--runtime/class_linker.cc351
1 files changed, 251 insertions, 100 deletions
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index bcc05c7bca..0deb37ce4b 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -798,6 +798,8 @@ bool ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b
FindSystemClass(self, "Ljava/lang/StackTraceElement;"));
SetClassRoot(ClassRoot::kJavaLangStackTraceElementArrayClass,
FindSystemClass(self, "[Ljava/lang/StackTraceElement;"));
+ SetClassRoot(ClassRoot::kJavaLangClassLoaderArrayClass,
+ FindSystemClass(self, "[Ljava/lang/ClassLoader;"));
// Create conflict tables that depend on the class linker.
runtime->FixupConflictTables();
@@ -1092,51 +1094,165 @@ static bool GetDexPathListElementName(ObjPtr<mirror::Object> element,
return false;
}
-static bool FlattenPathClassLoader(ObjPtr<mirror::ClassLoader> class_loader,
- std::list<ObjPtr<mirror::String>>* out_dex_file_names,
- std::string* error_msg)
+static bool GetDexFileNames(ScopedObjectAccessUnchecked& soa,
+ ObjPtr<mirror::ClassLoader> class_loader,
+ /*out*/std::list<ObjPtr<mirror::String>>* dex_files,
+ /*out*/std::string* error_msg)
REQUIRES_SHARED(Locks::mutator_lock_) {
- DCHECK(out_dex_file_names != nullptr);
- DCHECK(error_msg != nullptr);
- ScopedObjectAccessUnchecked soa(Thread::Current());
StackHandleScope<1> hs(soa.Self());
Handle<mirror::ClassLoader> handle(hs.NewHandle(class_loader));
- while (!ClassLinker::IsBootClassLoader(soa, class_loader)) {
- if (soa.Decode<mirror::Class>(WellKnownClasses::dalvik_system_PathClassLoader) !=
- class_loader->GetClass()) {
- *error_msg = StringPrintf("Unknown class loader type %s",
- class_loader->PrettyTypeOf().c_str());
- // Unsupported class loader.
+ // Get element names. Sets error to true on failure.
+ auto add_element_names = [&](ObjPtr<mirror::Object> element, bool* error)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ if (element == nullptr) {
+ *error_msg = "Null dex element";
+ *error = true; // Null element is a critical error.
+ return false; // Had an error, stop the visit.
+ }
+ ObjPtr<mirror::String> name;
+ if (!GetDexPathListElementName(element, &name)) {
+ *error_msg = "Invalid dex path list element";
+ *error = true; // Invalid element, make it a critical error.
+ return false; // Stop the visit.
+ }
+ if (name != nullptr) {
+ dex_files->push_front(name);
+ }
+ return true; // Continue with the next Element.
+ };
+ bool error = VisitClassLoaderDexElements(soa,
+ handle,
+ add_element_names,
+ /*defaultReturn=*/ false);
+ return !error;
+}
+
+static bool CompareClassLoaderTypes(ScopedObjectAccessUnchecked& soa,
+ ObjPtr<mirror::ClassLoader> image_class_loader,
+ ObjPtr<mirror::ClassLoader> class_loader,
+ std::string* error_msg)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ if (ClassLinker::IsBootClassLoader(soa, class_loader)) {
+ if (!ClassLinker::IsBootClassLoader(soa, image_class_loader)) {
+ *error_msg = "Hierarchies don't match";
return false;
}
- // Get element names. Sets error to true on failure.
- auto add_element_names = [&](ObjPtr<mirror::Object> element, bool* error)
- REQUIRES_SHARED(Locks::mutator_lock_) {
- if (element == nullptr) {
- *error_msg = "Null dex element";
- *error = true; // Null element is a critical error.
- return false; // Had an error, stop the visit.
- }
- ObjPtr<mirror::String> name;
- if (!GetDexPathListElementName(element, &name)) {
- *error_msg = "Invalid dex path list element";
- *error = false; // Invalid element is not a critical error.
- return false; // Stop the visit.
- }
- if (name != nullptr) {
- out_dex_file_names->push_front(name);
- }
- return true; // Continue with the next Element.
- };
- bool error = VisitClassLoaderDexElements(soa,
- handle,
- add_element_names,
- /* defaultReturn= */ false);
- if (error) {
- // An error occurred during DexPathList Element visiting.
+ } else if (ClassLinker::IsBootClassLoader(soa, image_class_loader)) {
+ *error_msg = "Hierarchies don't match";
+ return false;
+ } else if (class_loader->GetClass() != image_class_loader->GetClass()) {
+ *error_msg = StringPrintf("Class loader types don't match %s and %s",
+ image_class_loader->PrettyTypeOf().c_str(),
+ class_loader->PrettyTypeOf().c_str());
+ return false;
+ } else if (soa.Decode<mirror::Class>(WellKnownClasses::dalvik_system_PathClassLoader) !=
+ class_loader->GetClass()) {
+ *error_msg = StringPrintf("Unknown class loader type %s",
+ class_loader->PrettyTypeOf().c_str());
+ // Unsupported class loader.
+ return false;
+ }
+ return true;
+}
+
+static bool CompareDexFiles(const std::list<ObjPtr<mirror::String>>& image_dex_files,
+ const std::list<ObjPtr<mirror::String>>& loader_dex_files,
+ std::string* error_msg)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ bool equal = (image_dex_files.size() == loader_dex_files.size()) &&
+ std::equal(image_dex_files.begin(),
+ image_dex_files.end(),
+ loader_dex_files.begin(),
+ [](ObjPtr<mirror::String> lhs, ObjPtr<mirror::String> rhs)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ return lhs->Equals(rhs);
+ });
+ if (!equal) {
+ VLOG(image) << "Image dex files " << image_dex_files.size();
+ for (ObjPtr<mirror::String> name : image_dex_files) {
+ VLOG(image) << name->ToModifiedUtf8();
+ }
+ VLOG(image) << "Loader dex files " << loader_dex_files.size();
+ for (ObjPtr<mirror::String> name : loader_dex_files) {
+ VLOG(image) << name->ToModifiedUtf8();
+ }
+ *error_msg = "Mismatch in dex files";
+ }
+ return equal;
+}
+
+static bool CompareClassLoaders(ScopedObjectAccessUnchecked& soa,
+ ObjPtr<mirror::ClassLoader> image_class_loader,
+ ObjPtr<mirror::ClassLoader> class_loader,
+ bool check_dex_file_names,
+ std::string* error_msg)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ if (!CompareClassLoaderTypes(soa, image_class_loader, class_loader, error_msg)) {
+ return false;
+ }
+
+ if (ClassLinker::IsBootClassLoader(soa, class_loader)) {
+ // No need to check further.
+ return true;
+ }
+
+ if (check_dex_file_names) {
+ std::list<ObjPtr<mirror::String>> image_dex_files;
+ if (!GetDexFileNames(soa, image_class_loader, &image_dex_files, error_msg)) {
+ return false;
+ }
+
+ std::list<ObjPtr<mirror::String>> loader_dex_files;
+ if (!GetDexFileNames(soa, class_loader, &loader_dex_files, error_msg)) {
+ return false;
+ }
+
+ if (!CompareDexFiles(image_dex_files, loader_dex_files, error_msg)) {
return false;
}
- class_loader = class_loader->GetParent();
+ }
+
+ ArtField* field =
+ jni::DecodeArtField(WellKnownClasses::dalvik_system_BaseDexClassLoader_sharedLibraryLoaders);
+ ObjPtr<mirror::Object> shared_libraries_image_loader = field->GetObject(image_class_loader.Ptr());
+ ObjPtr<mirror::Object> shared_libraries_loader = field->GetObject(class_loader.Ptr());
+ if (shared_libraries_image_loader == nullptr) {
+ if (shared_libraries_loader != nullptr) {
+ *error_msg = "Mismatch in shared libraries";
+ return false;
+ }
+ } else if (shared_libraries_loader == nullptr) {
+ *error_msg = "Mismatch in shared libraries";
+ return false;
+ } else {
+ ObjPtr<mirror::ObjectArray<mirror::ClassLoader>> array1 =
+ shared_libraries_image_loader->AsObjectArray<mirror::ClassLoader>();
+ ObjPtr<mirror::ObjectArray<mirror::ClassLoader>> array2 =
+ shared_libraries_loader->AsObjectArray<mirror::ClassLoader>();
+ if (array1->GetLength() != array2->GetLength()) {
+ *error_msg = "Mismatch in number of shared libraries";
+ return false;
+ }
+
+ for (int32_t i = 0; i < array1->GetLength(); ++i) {
+ // Do a full comparison of the class loaders, including comparing their dex files.
+ if (!CompareClassLoaders(soa,
+ array1->Get(i),
+ array2->Get(i),
+ /*check_dex_file_names=*/ true,
+ error_msg)) {
+ return false;
+ }
+ }
+ }
+
+ // Do a full comparison of the class loaders, including comparing their dex files.
+ if (!CompareClassLoaders(soa,
+ image_class_loader->GetParent(),
+ class_loader->GetParent(),
+ /*check_dex_file_names=*/ true,
+ error_msg)) {
+ return false;
}
return true;
}
@@ -1905,6 +2021,7 @@ bool ClassLinker::AddImageSpace(
if (app_image) {
ScopedObjectAccessUnchecked soa(Thread::Current());
+ ScopedAssertNoThreadSuspension sants("Checking app image", soa.Self());
// Check that the class loader resolves the same way as the ones in the image.
// Image class loader [A][B][C][image dex files]
// Class loader = [???][dex_elements][image dex files]
@@ -1917,21 +2034,12 @@ bool ClassLinker::AddImageSpace(
*error_msg = "Unexpected BootClassLoader in app image";
return false;
}
- std::list<ObjPtr<mirror::String>> image_dex_file_names;
- std::string temp_error_msg;
- if (!FlattenPathClassLoader(image_class_loader.Get(), &image_dex_file_names, &temp_error_msg)) {
- *error_msg = StringPrintf("Failed to flatten image class loader hierarchy '%s'",
- temp_error_msg.c_str());
- return false;
- }
- std::list<ObjPtr<mirror::String>> loader_dex_file_names;
- if (!FlattenPathClassLoader(class_loader.Get(), &loader_dex_file_names, &temp_error_msg)) {
- *error_msg = StringPrintf("Failed to flatten class loader hierarchy '%s'",
- temp_error_msg.c_str());
- return false;
- }
- // Add the temporary dex path list elements at the end.
+ // The dex files of `class_loader` are not setup yet, so we cannot do a full comparison
+ // of `class_loader` and `image_class_loader` in `CompareClassLoaders`. Therefore, we
+ // special case the comparison of dex files of the two class loaders, but then do full
+ // comparisons for their shared libraries and parent.
auto elements = soa.Decode<mirror::ObjectArray<mirror::Object>>(dex_elements);
+ std::list<ObjPtr<mirror::String>> loader_dex_file_names;
for (size_t i = 0, num_elems = elements->GetLength(); i < num_elems; ++i) {
ObjPtr<mirror::Object> element = elements->GetWithoutChecks(i);
if (element != nullptr) {
@@ -1942,31 +2050,29 @@ bool ClassLinker::AddImageSpace(
}
}
}
- // Ignore the number of image dex files since we are adding those to the class loader anyways.
- CHECK_GE(static_cast<size_t>(image_dex_file_names.size()),
- static_cast<size_t>(dex_caches->GetLength()));
- size_t image_count = image_dex_file_names.size() - dex_caches->GetLength();
- // Check that the dex file names match.
- bool equal = image_count == loader_dex_file_names.size();
- if (equal) {
- auto it1 = image_dex_file_names.begin();
- auto it2 = loader_dex_file_names.begin();
- for (size_t i = 0; equal && i < image_count; ++i, ++it1, ++it2) {
- equal = equal && (*it1)->Equals(*it2);
- }
- }
- if (!equal) {
- VLOG(image) << "Image dex files " << image_dex_file_names.size();
- for (ObjPtr<mirror::String> name : image_dex_file_names) {
- VLOG(image) << name->ToModifiedUtf8();
- }
- VLOG(image) << "Loader dex files " << loader_dex_file_names.size();
- for (ObjPtr<mirror::String> name : loader_dex_file_names) {
- VLOG(image) << name->ToModifiedUtf8();
- }
- *error_msg = "Rejecting application image due to class loader mismatch";
- // Ignore class loader mismatch for now since these would just use possibly incorrect
- // oat code anyways. The structural class check should be done in the parent.
+ std::string temp_error_msg;
+ std::list<ObjPtr<mirror::String>> image_dex_file_names;
+ bool success = GetDexFileNames(
+ soa, image_class_loader.Get(), &image_dex_file_names, &temp_error_msg);
+ if (success) {
+ // Ignore the number of image dex files since we are adding those to the class loader anyways.
+ CHECK_GE(static_cast<size_t>(image_dex_file_names.size()),
+ static_cast<size_t>(dex_caches->GetLength()));
+ size_t image_count = image_dex_file_names.size() - dex_caches->GetLength();
+ image_dex_file_names.resize(image_count);
+ success = success && CompareDexFiles(image_dex_file_names,
+ loader_dex_file_names,
+ &temp_error_msg);
+ success = success && CompareClassLoaders(soa,
+ image_class_loader.Get(),
+ class_loader.Get(),
+ /*check_dex_file_names=*/ false,
+ &temp_error_msg);
+ }
+ if (!success) {
+ *error_msg = StringPrintf("Rejecting application image due to class loader mismatch: '%s'",
+ temp_error_msg.c_str());
+ return false;
}
}
@@ -8074,14 +8180,22 @@ ObjPtr<mirror::Class> ClassLinker::DoLookupResolvedType(dex::TypeIndex type_idx,
return type;
}
-ObjPtr<mirror::Class> ClassLinker::DoResolveType(dex::TypeIndex type_idx,
- ObjPtr<mirror::Class> referrer) {
+template <typename T>
+ObjPtr<mirror::Class> ClassLinker::DoResolveType(dex::TypeIndex type_idx, T referrer) {
StackHandleScope<2> hs(Thread::Current());
Handle<mirror::DexCache> dex_cache(hs.NewHandle(referrer->GetDexCache()));
Handle<mirror::ClassLoader> class_loader(hs.NewHandle(referrer->GetClassLoader()));
return DoResolveType(type_idx, dex_cache, class_loader);
}
+// Instantiate the above.
+template ObjPtr<mirror::Class> ClassLinker::DoResolveType(dex::TypeIndex type_idx,
+ ArtField* referrer);
+template ObjPtr<mirror::Class> ClassLinker::DoResolveType(dex::TypeIndex type_idx,
+ ArtMethod* referrer);
+template ObjPtr<mirror::Class> ClassLinker::DoResolveType(dex::TypeIndex type_idx,
+ ObjPtr<mirror::Class> referrer);
+
ObjPtr<mirror::Class> ClassLinker::DoResolveType(dex::TypeIndex type_idx,
Handle<mirror::DexCache> dex_cache,
Handle<mirror::ClassLoader> class_loader) {
@@ -8994,21 +9108,14 @@ void ClassLinker::AllocAndSetPrimitiveArrayClassRoot(Thread* self,
CheckSystemClass(self, primitive_array_class, descriptor);
}
-jobject ClassLinker::CreateWellKnownClassLoader(Thread* self,
- const std::vector<const DexFile*>& dex_files,
- jclass loader_class,
- jobject parent_loader) {
- CHECK(self->GetJniEnv()->IsSameObject(loader_class,
- WellKnownClasses::dalvik_system_PathClassLoader) ||
- self->GetJniEnv()->IsSameObject(loader_class,
- WellKnownClasses::dalvik_system_DelegateLastClassLoader));
-
- // SOAAlreadyRunnable is protected, and we need something to add a global reference.
- // We could move the jobject to the callers, but all call-sites do this...
- ScopedObjectAccessUnchecked soa(self);
+ObjPtr<mirror::ClassLoader> ClassLinker::CreateWellKnownClassLoader(
+ Thread* self,
+ const std::vector<const DexFile*>& dex_files,
+ Handle<mirror::Class> loader_class,
+ Handle<mirror::ObjectArray<mirror::ClassLoader>> shared_libraries,
+ Handle<mirror::ClassLoader> parent_loader) {
- // For now, create a libcore-level DexFile for each ART DexFile. This "explodes" multidex.
- StackHandleScope<6> hs(self);
+ StackHandleScope<5> hs(self);
ArtField* dex_elements_field =
jni::DecodeArtField(WellKnownClasses::dalvik_system_DexPathList_dexElements);
@@ -9098,8 +9205,8 @@ jobject ClassLinker::CreateWellKnownClassLoader(Thread* self,
}
// Create the class loader..
- Handle<mirror::Class> h_loader_class = hs.NewHandle(soa.Decode<mirror::Class>(loader_class));
- Handle<mirror::Object> h_class_loader = hs.NewHandle(h_loader_class->AllocObject(self));
+ Handle<mirror::ClassLoader> h_class_loader = hs.NewHandle<mirror::ClassLoader>(
+ ObjPtr<mirror::ClassLoader>::DownCast(loader_class->AllocObject(self)));
DCHECK(h_class_loader != nullptr);
// Set DexPathList.
ArtField* path_list_field =
@@ -9115,15 +9222,59 @@ jobject ClassLinker::CreateWellKnownClassLoader(Thread* self,
"parent",
"Ljava/lang/ClassLoader;");
DCHECK(parent_field != nullptr);
+ if (parent_loader.Get() == nullptr) {
+ ScopedObjectAccessUnchecked soa(self);
+ ObjPtr<mirror::Object> boot_loader(soa.Decode<mirror::Class>(
+ WellKnownClasses::java_lang_BootClassLoader)->AllocObject(self));
+ parent_field->SetObject<false>(h_class_loader.Get(), boot_loader);
+ } else {
+ parent_field->SetObject<false>(h_class_loader.Get(), parent_loader.Get());
+ }
+
+ ArtField* shared_libraries_field =
+ jni::DecodeArtField(WellKnownClasses::dalvik_system_BaseDexClassLoader_sharedLibraryLoaders);
+ DCHECK(shared_libraries_field != nullptr);
+ shared_libraries_field->SetObject<false>(h_class_loader.Get(), shared_libraries.Get());
+
+ return h_class_loader.Get();
+}
- ObjPtr<mirror::Object> parent = (parent_loader != nullptr)
- ? soa.Decode<mirror::ClassLoader>(parent_loader)
- : soa.Decode<mirror::Class>(WellKnownClasses::java_lang_BootClassLoader)->AllocObject(self);
- parent_field->SetObject<false>(h_class_loader.Get(), parent);
+jobject ClassLinker::CreateWellKnownClassLoader(Thread* self,
+ const std::vector<const DexFile*>& dex_files,
+ jclass loader_class,
+ jobject parent_loader) {
+ CHECK(self->GetJniEnv()->IsSameObject(loader_class,
+ WellKnownClasses::dalvik_system_PathClassLoader) ||
+ self->GetJniEnv()->IsSameObject(loader_class,
+ WellKnownClasses::dalvik_system_DelegateLastClassLoader));
+
+ // SOAAlreadyRunnable is protected, and we need something to add a global reference.
+ // We could move the jobject to the callers, but all call-sites do this...
+ ScopedObjectAccessUnchecked soa(self);
+
+ // For now, create a libcore-level DexFile for each ART DexFile. This "explodes" multidex.
+ StackHandleScope<3> hs(self);
+
+ Handle<mirror::Class> h_loader_class =
+ hs.NewHandle<mirror::Class>(soa.Decode<mirror::Class>(loader_class));
+ Handle<mirror::ClassLoader> parent =
+ hs.NewHandle<mirror::ClassLoader>(ObjPtr<mirror::ClassLoader>::DownCast(
+ (parent_loader != nullptr)
+ ? soa.Decode<mirror::ClassLoader>(parent_loader)
+ : nullptr));
+ Handle<mirror::ObjectArray<mirror::ClassLoader>> shared_libraries =
+ hs.NewHandle<mirror::ObjectArray<mirror::ClassLoader>>(nullptr);
+
+ ObjPtr<mirror::ClassLoader> loader = CreateWellKnownClassLoader(
+ self,
+ dex_files,
+ h_loader_class,
+ shared_libraries,
+ parent);
// Make it a global ref and return.
ScopedLocalRef<jobject> local_ref(
- soa.Env(), soa.Env()->AddLocalReference<jobject>(h_class_loader.Get()));
+ soa.Env(), soa.Env()->AddLocalReference<jobject>(loader));
return soa.Env()->NewGlobalRef(local_ref.get());
}