Use j.l.ThreadGroup class directly for GetThreadGroupInfo

We were using the class of the input to GetThreadGroupInfo in some
situations. This could lead to us reading the wrong field or not
finding expected fields. Change to always directly use the
j.l.ThreadGroup class from WellKnownClasses. Also use some handles in
this function.

Test: ./test.py --host
Bug: 140521090
Change-Id: I3560662718311ccc0fa9b906f178407350ce9960
diff --git a/openjdkjvmti/ti_threadgroup.cc b/openjdkjvmti/ti_threadgroup.cc
index e17e61f..f2e5c90 100644
--- a/openjdkjvmti/ti_threadgroup.cc
+++ b/openjdkjvmti/ti_threadgroup.cc
@@ -99,7 +99,10 @@
     return ERR(INVALID_THREAD_GROUP);
   }
 
-  art::ObjPtr<art::mirror::Object> obj = soa.Decode<art::mirror::Object>(group);
+  art::StackHandleScope<2> hs(soa.Self());
+  art::Handle<art::mirror::Class> tg_class(
+      hs.NewHandle(soa.Decode<art::mirror::Class>(art::WellKnownClasses::java_lang_ThreadGroup)));
+  art::Handle<art::mirror::Object> obj(hs.NewHandle(soa.Decode<art::mirror::Object>(group)));
 
   // Do the name first. It's the only thing that can fail.
   {
@@ -107,7 +110,7 @@
         art::jni::DecodeArtField(art::WellKnownClasses::java_lang_ThreadGroup_name);
     CHECK(name_field != nullptr);
     art::ObjPtr<art::mirror::String> name_obj =
-        art::ObjPtr<art::mirror::String>::DownCast(name_field->GetObject(obj));
+        art::ObjPtr<art::mirror::String>::DownCast(name_field->GetObject(obj.Get()));
     std::string tmp_str;
     const char* tmp_cstr;
     if (name_obj == nullptr) {
@@ -129,7 +132,7 @@
     art::ArtField* parent_field =
         art::jni::DecodeArtField(art::WellKnownClasses::java_lang_ThreadGroup_parent);
     CHECK(parent_field != nullptr);
-    art::ObjPtr<art::mirror::Object> parent_group = parent_field->GetObject(obj);
+    art::ObjPtr<art::mirror::Object> parent_group = parent_field->GetObject(obj.Get());
     info_ptr->parent = parent_group == nullptr
                            ? nullptr
                            : soa.AddLocalReference<jthreadGroup>(parent_group);
@@ -137,16 +140,16 @@
 
   // Max priority.
   {
-    art::ArtField* prio_field = obj->GetClass()->FindDeclaredInstanceField("maxPriority", "I");
+    art::ArtField* prio_field = tg_class->FindDeclaredInstanceField("maxPriority", "I");
     CHECK(prio_field != nullptr);
-    info_ptr->max_priority = static_cast<jint>(prio_field->GetInt(obj));
+    info_ptr->max_priority = static_cast<jint>(prio_field->GetInt(obj.Get()));
   }
 
   // Daemon.
   {
-    art::ArtField* daemon_field = obj->GetClass()->FindDeclaredInstanceField("daemon", "Z");
+    art::ArtField* daemon_field = tg_class->FindDeclaredInstanceField("daemon", "Z");
     CHECK(daemon_field != nullptr);
-    info_ptr->is_daemon = daemon_field->GetBoolean(obj) == 0 ? JNI_FALSE : JNI_TRUE;
+    info_ptr->is_daemon = daemon_field->GetBoolean(obj.Get()) == 0 ? JNI_FALSE : JNI_TRUE;
   }
 
   return ERR(NONE);
diff --git a/test/925-threadgroups/expected.txt b/test/925-threadgroups/expected.txt
index 7d1a259..9dfa37d 100644
--- a/test/925-threadgroups/expected.txt
+++ b/test/925-threadgroups/expected.txt
@@ -14,3 +14,8 @@
 system:
   [Thread[FinalizerDaemon,5,system], Thread[FinalizerWatchdogDaemon,5,system], Thread[HeapTaskDaemon,5,system], Thread[ReferenceQueueDaemon,5,system], Thread[Signal Catcher,5,system]]
   [java.lang.ThreadGroup[name=main,maxpri=10]]
+art.Test925$CustomThreadGroup[name=TEST GROUP,maxpri=10]
+  java.lang.ThreadGroup[name=main,maxpri=10]
+  TEST GROUP
+  10
+  false
diff --git a/test/925-threadgroups/src/art/Test925.java b/test/925-threadgroups/src/art/Test925.java
index 8d1e665..0779f63 100644
--- a/test/925-threadgroups/src/art/Test925.java
+++ b/test/925-threadgroups/src/art/Test925.java
@@ -22,6 +22,7 @@
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
+import java.util.concurrent.CountDownLatch;
 
 public class Test925 {
   public static void run() throws Exception {
@@ -49,6 +50,30 @@
     waitGroupChildren(rootGroup, 5 /* # daemons */, 30 /* timeout in seconds */);
 
     checkChildren(curGroup);
+
+    // Test custom groups
+    ThreadGroup testGroup = new CustomThreadGroup(curGroup, "TEST GROUP");
+    final CountDownLatch cdl = new CountDownLatch(1);
+    final CountDownLatch startup = new CountDownLatch(1);
+    Thread t2 = new Thread(testGroup, "Test Thread") {
+      public void run() {
+        startup.countDown();
+        try {
+          cdl.await();
+        } catch (Exception e) {}
+      }
+    };
+    t2.start();
+    startup.await();
+    printThreadGroupInfo(testGroup);
+    cdl.countDown();
+    t2.join();
+  }
+
+  private static final class CustomThreadGroup extends ThreadGroup {
+    public CustomThreadGroup(ThreadGroup parent, String name) {
+      super(parent, name);
+    }
   }
 
   private static void printThreadGroupInfo(ThreadGroup tg) {