Add get_class_loader_class_descriptors JVMTI extension method

This adds a new JVMTI extension:
com.android.art.class.get_class_loader_class_descriptors. This will
enumerate all of the classes known to be loadable with a given
class-loader as the defining class loader. The function gets this by
looking at all dex-files associated with the given class-loader.

Bug: 73504235
Test: ./test.py --host -j50
Change-Id: Ie54223cd40109056396ba609f92b6c02d81dd4ab
diff --git a/openjdkjvmti/ti_class_loader.cc b/openjdkjvmti/ti_class_loader.cc
index d594d6e..3df5de9 100644
--- a/openjdkjvmti/ti_class_loader.cc
+++ b/openjdkjvmti/ti_class_loader.cc
@@ -29,7 +29,7 @@
  * questions.
  */
 
-#include "ti_class_loader.h"
+#include "ti_class_loader-inl.h"
 
 #include <limits>
 
@@ -134,45 +134,28 @@
   return new_cookie.Get();
 }
 
-// TODO This should return the actual source java.lang.DexFile object for the klass being loaded.
-art::ObjPtr<art::mirror::Object> ClassLoaderHelper::FindSourceDexFileObject(
-    art::Thread* self, art::Handle<art::mirror::ClassLoader> loader) {
-  const char* dex_path_list_element_array_name = "[Ldalvik/system/DexPathList$Element;";
-  const char* dex_path_list_element_name = "Ldalvik/system/DexPathList$Element;";
-  const char* dex_file_name = "Ldalvik/system/DexFile;";
-  const char* dex_path_list_name = "Ldalvik/system/DexPathList;";
-  const char* dex_class_loader_name = "Ldalvik/system/BaseDexClassLoader;";
+art::ObjPtr<art::mirror::ObjectArray<art::mirror::Object>> ClassLoaderHelper::GetDexElementList(
+    art::Thread* self,
+    art::Handle<art::mirror::ClassLoader> loader) {
+  art::StackHandleScope<4> hs(self);
 
-  CHECK(!self->IsExceptionPending());
-  art::StackHandleScope<5> hs(self);
-  art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
-
-  art::Handle<art::mirror::ClassLoader> null_loader(hs.NewHandle<art::mirror::ClassLoader>(
-      nullptr));
-  art::Handle<art::mirror::Class> base_dex_loader_class(hs.NewHandle(class_linker->FindClass(
-      self, dex_class_loader_name, null_loader)));
+  art::Handle<art::mirror::Class>
+      base_dex_loader_class(hs.NewHandle(self->DecodeJObject(
+          art::WellKnownClasses::dalvik_system_BaseDexClassLoader)->AsClass()));
 
   // Get all the ArtFields so we can look in the BaseDexClassLoader
-  art::ArtField* path_list_field = base_dex_loader_class->FindDeclaredInstanceField(
-      "pathList", dex_path_list_name);
-  CHECK(path_list_field != nullptr);
-
+  art::ArtField* path_list_field = art::jni::DecodeArtField(
+      art::WellKnownClasses::dalvik_system_BaseDexClassLoader_pathList);
   art::ArtField* dex_path_list_element_field =
-      class_linker->FindClass(self, dex_path_list_name, null_loader)
-        ->FindDeclaredInstanceField("dexElements", dex_path_list_element_array_name);
-  CHECK(dex_path_list_element_field != nullptr);
-
-  art::ArtField* element_dex_file_field =
-      class_linker->FindClass(self, dex_path_list_element_name, null_loader)
-        ->FindDeclaredInstanceField("dexFile", dex_file_name);
-  CHECK(element_dex_file_field != nullptr);
+      art::jni::DecodeArtField(art::WellKnownClasses::dalvik_system_DexPathList_dexElements);
 
   // Check if loader is a BaseDexClassLoader
   art::Handle<art::mirror::Class> loader_class(hs.NewHandle(loader->GetClass()));
   // Currently only base_dex_loader is allowed to actually define classes but if this changes in the
   // future we should make sure to support all class loader types.
   if (!loader_class->IsSubClass(base_dex_loader_class.Get())) {
-    LOG(ERROR) << "The classloader is not a BaseDexClassLoader which is currently the only "
+    LOG(ERROR) << "The classloader " << loader_class->PrettyClass() << " is not a "
+               << base_dex_loader_class->PrettyClass() << " which is currently the only "
                << "supported class loader type!";
     return nullptr;
   }
@@ -180,28 +163,28 @@
   art::Handle<art::mirror::Object> path_list(
       hs.NewHandle(path_list_field->GetObject(loader.Get())));
   CHECK(path_list != nullptr);
-  CHECK(!self->IsExceptionPending());
-  art::Handle<art::mirror::ObjectArray<art::mirror::Object>> dex_elements_list(hs.NewHandle(
-      dex_path_list_element_field->GetObject(path_list.Get())->
-      AsObjectArray<art::mirror::Object>()));
-  CHECK(!self->IsExceptionPending());
-  CHECK(dex_elements_list != nullptr);
-  size_t num_elements = dex_elements_list->GetLength();
-  // Iterate over the DexPathList$Element to find the right one
-  for (size_t i = 0; i < num_elements; i++) {
-    art::ObjPtr<art::mirror::Object> current_element = dex_elements_list->Get(i);
-    CHECK(!current_element.IsNull());
-    // TODO It would be cleaner to put the art::DexFile into the dalvik.system.DexFile the class
-    // comes from but it is more annoying because we would need to find this class. It is not
-    // necessary for proper function since we just need to be in front of the classes old dex file
-    // in the path.
-    art::ObjPtr<art::mirror::Object> first_dex_file(
-        element_dex_file_field->GetObject(current_element));
-    if (!first_dex_file.IsNull()) {
-      return first_dex_file;
-    }
-  }
-  return nullptr;
+  art::ObjPtr<art::mirror::ObjectArray<art::mirror::Object>> dex_elements_list =
+      dex_path_list_element_field->GetObject(path_list.Get())->AsObjectArray<art::mirror::Object>();
+  return dex_elements_list;
+}
+
+// TODO This should return the actual source java.lang.DexFile object for the klass being loaded.
+art::ObjPtr<art::mirror::Object> ClassLoaderHelper::FindSourceDexFileObject(
+    art::Thread* self, art::Handle<art::mirror::ClassLoader> loader) {
+  art::ObjPtr<art::mirror::Object> res = nullptr;
+  VisitDexFileObjects(self,
+                      loader,
+                      [&] (art::ObjPtr<art::mirror::Object> dex_file) {
+                        res = dex_file;
+                        // Just stop at the first one.
+                        // TODO It would be cleaner to put the art::DexFile into the
+                        // dalvik.system.DexFile the class comes from but it is more annoying
+                        // because we would need to find this class. It is not necessary for proper
+                        // function since we just need to be in front of the classes old dex file in
+                        // the path.
+                        return false;
+                      });
+  return res;
 }
 
 }  // namespace openjdkjvmti