Adding Class.getDeclaredFields to unstarted runtime

As part of the update of java.util.concurrent to 11+28, it is
needed to have Class.getDeclaredFields() called from the
unstarted runtime.

Test: m
Bug: 188889082
Change-Id: I0ad4629ba1f55165c6c4a14cad823735c9f8cd02
diff --git a/runtime/hidden_api.cc b/runtime/hidden_api.cc
index 9e2ad92..365bace 100644
--- a/runtime/hidden_api.cc
+++ b/runtime/hidden_api.cc
@@ -21,14 +21,17 @@
 
 #include "art_field-inl.h"
 #include "art_method-inl.h"
+#include "class_root-inl.h"
 #include "compat_framework.h"
 #include "base/dumpable.h"
 #include "base/file_utils.h"
 #include "dex/class_accessor-inl.h"
 #include "dex/dex_file_loader.h"
 #include "mirror/class_ext.h"
+#include "mirror/proxy.h"
 #include "oat_file.h"
 #include "scoped_thread_state_change.h"
+#include "stack.h"
 #include "thread-inl.h"
 #include "well_known_classes.h"
 
@@ -45,6 +48,10 @@
 
 static constexpr uint64_t kMaxLogWarnings = 100;
 
+// Should be the same as dalvik.system.VMRuntime.PREVENT_META_REFLECTION_BLOCKLIST_ACCESS.
+// Corresponds to a bug id.
+static constexpr uint64_t kPreventMetaReflectionBlocklistAccess = 142365358;
+
 // Set to true if we should always print a warning in logcat for all hidden API accesses, not just
 // conditionally and unconditionally blocked. This can be set to true for developer preview / beta
 // builds, but should be false for public release builds.
@@ -160,6 +167,75 @@
   }
 }
 
+hiddenapi::AccessContext GetReflectionCallerAccessContext(Thread* self)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  // Walk the stack and find the first frame not from java.lang.Class,
+  // java.lang.invoke or java.lang.reflect. This is very expensive.
+  // Save this till the last.
+  struct FirstExternalCallerVisitor : public StackVisitor {
+    explicit FirstExternalCallerVisitor(Thread* thread)
+        : StackVisitor(thread, nullptr, StackVisitor::StackWalkKind::kIncludeInlinedFrames),
+          caller(nullptr) {
+    }
+
+    bool VisitFrame() override REQUIRES_SHARED(Locks::mutator_lock_) {
+      ArtMethod *m = GetMethod();
+      if (m == nullptr) {
+        // Attached native thread. Assume this is *not* boot class path.
+        caller = nullptr;
+        return false;
+      } else if (m->IsRuntimeMethod()) {
+        // Internal runtime method, continue walking the stack.
+        return true;
+      }
+
+      ObjPtr<mirror::Class> declaring_class = m->GetDeclaringClass();
+      if (declaring_class->IsBootStrapClassLoaded()) {
+        if (declaring_class->IsClassClass()) {
+          return true;
+        }
+        // Check classes in the java.lang.invoke package. At the time of writing, the
+        // classes of interest are MethodHandles and MethodHandles.Lookup, but this
+        // is subject to change so conservatively cover the entire package.
+        // NB Static initializers within java.lang.invoke are permitted and do not
+        // need further stack inspection.
+        ObjPtr<mirror::Class> lookup_class = GetClassRoot<mirror::MethodHandlesLookup>();
+        if ((declaring_class == lookup_class || declaring_class->IsInSamePackage(lookup_class))
+            && !m->IsClassInitializer()) {
+          return true;
+        }
+        // Check for classes in the java.lang.reflect package, except for java.lang.reflect.Proxy.
+        // java.lang.reflect.Proxy does its own hidden api checks (https://r.android.com/915496),
+        // and walking over this frame would cause a null pointer dereference
+        // (e.g. in 691-hiddenapi-proxy).
+        ObjPtr<mirror::Class> proxy_class = GetClassRoot<mirror::Proxy>();
+        CompatFramework& compat_framework = Runtime::Current()->GetCompatFramework();
+        if (declaring_class->IsInSamePackage(proxy_class) && declaring_class != proxy_class) {
+          if (compat_framework.IsChangeEnabled(kPreventMetaReflectionBlocklistAccess)) {
+            return true;
+          }
+        }
+      }
+
+      caller = m;
+      return false;
+    }
+
+    ArtMethod* caller;
+  };
+
+  FirstExternalCallerVisitor visitor(self);
+  visitor.WalkStack();
+
+  // Construct AccessContext from the calling class found on the stack.
+  // If the calling class cannot be determined, e.g. unattached threads,
+  // we conservatively assume the caller is trusted.
+  ObjPtr<mirror::Class> caller = (visitor.caller == nullptr)
+      ? nullptr : visitor.caller->GetDeclaringClass();
+  return caller.IsNull() ? AccessContext(/* is_trusted= */ true)
+                         : AccessContext(caller);
+}
+
 namespace detail {
 
 // Do not change the values of items in this enum, as they are written to the
diff --git a/runtime/hidden_api.h b/runtime/hidden_api.h
index 11c058c..66e81c4 100644
--- a/runtime/hidden_api.h
+++ b/runtime/hidden_api.h
@@ -162,6 +162,10 @@
 
 void InitializeCorePlatformApiPrivateFields() REQUIRES(!Locks::mutator_lock_);
 
+// Walks the stack, finds the caller of this reflective call and returns
+// a hiddenapi AccessContext formed from its declaring class.
+AccessContext GetReflectionCallerAccessContext(Thread* self) REQUIRES_SHARED(Locks::mutator_lock_);
+
 // Implementation details. DO NOT ACCESS DIRECTLY.
 namespace detail {
 
diff --git a/runtime/interpreter/unstarted_runtime.cc b/runtime/interpreter/unstarted_runtime.cc
index b8fb5b8..135b6b4 100644
--- a/runtime/interpreter/unstarted_runtime.cc
+++ b/runtime/interpreter/unstarted_runtime.cc
@@ -369,6 +369,19 @@
   result->SetL(field);
 }
 
+void UnstartedRuntime::UnstartedClassGetDeclaredFields(
+    Thread* self, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset) {
+  // Special managed code cut-out to allow field lookup in a un-started runtime that'd fail
+  // going the reflective Dex way.
+  ObjPtr<mirror::Class> klass = shadow_frame->GetVRegReference(arg_offset)->AsClass();
+  auto object_array = klass->GetDeclaredFields(self,
+                                               /*public_only=*/ false,
+                                               /*force_resolve=*/ true);
+  if (object_array != nullptr) {
+    result->SetL(object_array);
+  }
+}
+
 // This is required for Enum(Set) code, as that uses reflection to inspect enum classes.
 void UnstartedRuntime::UnstartedClassGetDeclaredMethod(
     Thread* self, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset) {
diff --git a/runtime/interpreter/unstarted_runtime_list.h b/runtime/interpreter/unstarted_runtime_list.h
index 498aeb6..16d29b8 100644
--- a/runtime/interpreter/unstarted_runtime_list.h
+++ b/runtime/interpreter/unstarted_runtime_list.h
@@ -27,6 +27,7 @@
   V(ClassClassForName, "Ljava/lang/Class;", "classForName", "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;") \
   V(ClassNewInstance, "Ljava/lang/Class;", "newInstance", "()Ljava/lang/Object;") \
   V(ClassGetDeclaredField, "Ljava/lang/Class;", "getDeclaredField", "(Ljava/lang/String;)Ljava/lang/reflect/Field;") \
+  V(ClassGetDeclaredFields, "Ljava/lang/Class;", "getDeclaredFields", "()[Ljava/lang/reflect/Field;") \
   V(ClassGetDeclaredMethod, "Ljava/lang/Class;", "getDeclaredMethodInternal", "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;") \
   V(ClassGetDeclaredConstructor, "Ljava/lang/Class;", "getDeclaredConstructorInternal", "([Ljava/lang/Class;)Ljava/lang/reflect/Constructor;") \
   V(ClassGetDeclaringClass, "Ljava/lang/Class;", "getDeclaringClass", "()Ljava/lang/Class;") \
diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h
index b59dc18..84f117f 100644
--- a/runtime/mirror/class-inl.h
+++ b/runtime/mirror/class-inl.h
@@ -32,10 +32,10 @@
 #include "dex/dex_file-inl.h"
 #include "dex/invoke_type.h"
 #include "dex_cache.h"
+#include "hidden_api.h"
 #include "iftable-inl.h"
 #include "imtable.h"
 #include "object-inl.h"
-#include "object_array.h"
 #include "read_barrier-inl.h"
 #include "runtime.h"
 #include "string.h"
@@ -412,6 +412,18 @@
   return SetField32<false>(OFFSET_OF_OBJECT_MEMBER(Class, object_size_), new_object_size);
 }
 
+template<typename T>
+inline bool Class::IsDiscoverable(bool public_only,
+                                  const hiddenapi::AccessContext& access_context,
+                                  T* member) {
+  if (public_only && ((member->GetAccessFlags() & kAccPublic) == 0)) {
+    return false;
+  }
+
+  return !hiddenapi::ShouldDenyAccessToMember(
+      member, access_context, hiddenapi::AccessMethod::kNone);
+}
+
 // Determine whether "this" is assignable from "src", where both of these
 // are array classes.
 //
diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc
index 4828ca2..40ff7c0 100644
--- a/runtime/mirror/class.cc
+++ b/runtime/mirror/class.cc
@@ -38,6 +38,7 @@
 #include "dex/dex_file_annotations.h"
 #include "dex/signature-inl.h"
 #include "dex_cache-inl.h"
+#include "field.h"
 #include "gc/accounting/card_table-inl.h"
 #include "gc/heap-inl.h"
 #include "handle_scope-inl.h"
@@ -47,6 +48,7 @@
 #include "method.h"
 #include "object-inl.h"
 #include "object-refvisitor-inl.h"
+#include "object_array-alloc-inl.h"
 #include "object_array-inl.h"
 #include "object_lock.h"
 #include "string-inl.h"
@@ -1165,6 +1167,75 @@
   return nullptr;
 }
 
+ObjPtr<mirror::ObjectArray<mirror::Field>> Class::GetDeclaredFields(
+    Thread* self,
+    bool public_only,
+    bool force_resolve) REQUIRES_SHARED(Locks::mutator_lock_) {
+  if (UNLIKELY(IsObsoleteObject())) {
+    ThrowRuntimeException("Obsolete Object!");
+    return nullptr;
+  }
+  StackHandleScope<1> hs(self);
+  IterationRange<StrideIterator<ArtField>> ifields = GetIFields();
+  IterationRange<StrideIterator<ArtField>> sfields = GetSFields();
+  size_t array_size = NumInstanceFields() + NumStaticFields();
+  auto hiddenapi_context = hiddenapi::GetReflectionCallerAccessContext(self);
+  // Lets go subtract all the non discoverable fields.
+  for (ArtField& field : ifields) {
+    if (!IsDiscoverable(public_only, hiddenapi_context, &field)) {
+      --array_size;
+    }
+  }
+  for (ArtField& field : sfields) {
+    if (!IsDiscoverable(public_only, hiddenapi_context, &field)) {
+      --array_size;
+    }
+  }
+  size_t array_idx = 0;
+  auto object_array = hs.NewHandle(mirror::ObjectArray<mirror::Field>::Alloc(
+      self, GetClassRoot<mirror::ObjectArray<mirror::Field>>(), array_size));
+  if (object_array == nullptr) {
+    return nullptr;
+  }
+  for (ArtField& field : ifields) {
+    if (IsDiscoverable(public_only, hiddenapi_context, &field)) {
+      ObjPtr<mirror::Field> reflect_field =
+          mirror::Field::CreateFromArtField(self, &field, force_resolve);
+      if (reflect_field == nullptr) {
+        if (kIsDebugBuild) {
+          self->AssertPendingException();
+        }
+        // Maybe null due to OOME or type resolving exception.
+        return nullptr;
+      }
+      // We're initializing a newly allocated object, so we do not need to record that under
+      // a transaction. If the transaction is aborted, the whole object shall be unreachable.
+      object_array->SetWithoutChecks</*kTransactionActive=*/ false,
+                                     /*kCheckTransaction=*/ false>(
+                                         array_idx++, reflect_field);
+    }
+  }
+  for (ArtField& field : sfields) {
+    if (IsDiscoverable(public_only, hiddenapi_context, &field)) {
+      ObjPtr<mirror::Field> reflect_field =
+          mirror::Field::CreateFromArtField(self, &field, force_resolve);
+      if (reflect_field == nullptr) {
+        if (kIsDebugBuild) {
+          self->AssertPendingException();
+        }
+        return nullptr;
+      }
+      // We're initializing a newly allocated object, so we do not need to record that under
+      // a transaction. If the transaction is aborted, the whole object shall be unreachable.
+      object_array->SetWithoutChecks</*kTransactionActive=*/ false,
+                                     /*kCheckTransaction=*/ false>(
+                                         array_idx++, reflect_field);
+    }
+  }
+  DCHECK_EQ(array_idx, array_size);
+  return object_array.Get();
+}
+
 ArtField* Class::FindStaticField(std::string_view name, std::string_view type) {
   ScopedAssertNoThreadSuspension ants(__FUNCTION__);
   // Is the field in this class (or its interfaces), or any of its
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index 9a97fcf..6c839ca 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -71,6 +71,7 @@
 class ClassLoader;
 class Constructor;
 class DexCache;
+class Field;
 class IfTable;
 class Method;
 template <typename T> struct PACKED(8) DexCachePair;
@@ -589,6 +590,16 @@
 
   static bool IsInSamePackage(std::string_view descriptor1, std::string_view descriptor2);
 
+  // Returns true if a class member should be discoverable with reflection given
+  // the criteria. Some reflection calls only return public members
+  // (public_only == true), some members should be hidden from non-boot class path
+  // callers (hiddenapi_context).
+  template<typename T>
+  ALWAYS_INLINE static bool IsDiscoverable(bool public_only,
+                                           const hiddenapi::AccessContext& access_context,
+                                           T* member)
+      REQUIRES_SHARED(Locks::mutator_lock_);
+
   // Returns true if this class can access that class.
   bool CanAccess(ObjPtr<Class> that) REQUIRES_SHARED(Locks::mutator_lock_);
 
@@ -1109,6 +1120,12 @@
   ArtField* FindDeclaredStaticField(ObjPtr<DexCache> dex_cache, uint32_t dex_field_idx)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
+  ObjPtr<mirror::ObjectArray<mirror::Field>> GetDeclaredFields(Thread* self,
+                                                               bool public_only,
+                                                               bool force_resolve)
+      REQUIRES_SHARED(Locks::mutator_lock_);
+
+
   pid_t GetClinitThreadId() REQUIRES_SHARED(Locks::mutator_lock_) {
     DCHECK(IsIdxLoaded() || IsErroneous()) << PrettyClass();
     return GetField32(OFFSET_OF_OBJECT_MEMBER(Class, clinit_thread_id_));
diff --git a/runtime/native/java_lang_Class.cc b/runtime/native/java_lang_Class.cc
index 776b14f..da42e61 100644
--- a/runtime/native/java_lang_Class.cc
+++ b/runtime/native/java_lang_Class.cc
@@ -57,83 +57,10 @@
 
 namespace art {
 
-// Should be the same as dalvik.system.VMRuntime.PREVENT_META_REFLECTION_BLOCKLIST_ACCESS.
-// Corresponds to a bug id.
-static constexpr uint64_t kPreventMetaReflectionBlocklistAccess = 142365358;
-
-// Walks the stack, finds the caller of this reflective call and returns
-// a hiddenapi AccessContext formed from its declaring class.
-static hiddenapi::AccessContext GetReflectionCaller(Thread* self)
-    REQUIRES_SHARED(Locks::mutator_lock_) {
-  // Walk the stack and find the first frame not from java.lang.Class,
-  // java.lang.invoke or java.lang.reflect. This is very expensive.
-  // Save this till the last.
-  struct FirstExternalCallerVisitor : public StackVisitor {
-    explicit FirstExternalCallerVisitor(Thread* thread)
-        : StackVisitor(thread, nullptr, StackVisitor::StackWalkKind::kIncludeInlinedFrames),
-          caller(nullptr) {
-    }
-
-    bool VisitFrame() override REQUIRES_SHARED(Locks::mutator_lock_) {
-      ArtMethod *m = GetMethod();
-      if (m == nullptr) {
-        // Attached native thread. Assume this is *not* boot class path.
-        caller = nullptr;
-        return false;
-      } else if (m->IsRuntimeMethod()) {
-        // Internal runtime method, continue walking the stack.
-        return true;
-      }
-
-      ObjPtr<mirror::Class> declaring_class = m->GetDeclaringClass();
-      if (declaring_class->IsBootStrapClassLoaded()) {
-        if (declaring_class->IsClassClass()) {
-          return true;
-        }
-        // Check classes in the java.lang.invoke package. At the time of writing, the
-        // classes of interest are MethodHandles and MethodHandles.Lookup, but this
-        // is subject to change so conservatively cover the entire package.
-        // NB Static initializers within java.lang.invoke are permitted and do not
-        // need further stack inspection.
-        ObjPtr<mirror::Class> lookup_class = GetClassRoot<mirror::MethodHandlesLookup>();
-        if ((declaring_class == lookup_class || declaring_class->IsInSamePackage(lookup_class))
-            && !m->IsClassInitializer()) {
-          return true;
-        }
-        // Check for classes in the java.lang.reflect package, except for java.lang.reflect.Proxy.
-        // java.lang.reflect.Proxy does its own hidden api checks (https://r.android.com/915496),
-        // and walking over this frame would cause a null pointer dereference
-        // (e.g. in 691-hiddenapi-proxy).
-        ObjPtr<mirror::Class> proxy_class = GetClassRoot<mirror::Proxy>();
-        CompatFramework& compat_framework = Runtime::Current()->GetCompatFramework();
-        if (declaring_class->IsInSamePackage(proxy_class) && declaring_class != proxy_class) {
-          if (compat_framework.IsChangeEnabled(kPreventMetaReflectionBlocklistAccess)) {
-            return true;
-          }
-        }
-      }
-
-      caller = m;
-      return false;
-    }
-
-    ArtMethod* caller;
-  };
-
-  FirstExternalCallerVisitor visitor(self);
-  visitor.WalkStack();
-
-  // Construct AccessContext from the calling class found on the stack.
-  // If the calling class cannot be determined, e.g. unattached threads,
-  // we conservatively assume the caller is trusted.
-  ObjPtr<mirror::Class> caller = (visitor.caller == nullptr)
-      ? nullptr : visitor.caller->GetDeclaringClass();
-  return caller.IsNull() ? hiddenapi::AccessContext(/* is_trusted= */ true)
-                         : hiddenapi::AccessContext(caller);
-}
-
 static std::function<hiddenapi::AccessContext()> GetHiddenapiAccessContextFunction(Thread* self) {
-  return [=]() REQUIRES_SHARED(Locks::mutator_lock_) { return GetReflectionCaller(self); };
+  return [=]() REQUIRES_SHARED(Locks::mutator_lock_) {
+    return hiddenapi::GetReflectionCallerAccessContext(self);
+  };
 }
 
 // Returns true if the first non-ClassClass caller up the stack should not be
@@ -146,23 +73,6 @@
                                              hiddenapi::AccessMethod::kReflection);
 }
 
-// Returns true if a class member should be discoverable with reflection given
-// the criteria. Some reflection calls only return public members
-// (public_only == true), some members should be hidden from non-boot class path
-// callers (hiddenapi_context).
-template<typename T>
-ALWAYS_INLINE static bool IsDiscoverable(bool public_only,
-                                         const hiddenapi::AccessContext& access_context,
-                                         T* member)
-    REQUIRES_SHARED(Locks::mutator_lock_) {
-  if (public_only && ((member->GetAccessFlags() & kAccPublic) == 0)) {
-    return false;
-  }
-
-  return !hiddenapi::ShouldDenyAccessToMember(
-      member, access_context, hiddenapi::AccessMethod::kNone);
-}
-
 ALWAYS_INLINE static inline ObjPtr<mirror::Class> DecodeClass(
     const ScopedFastNativeObjectAccess& soa, jobject java_class)
     REQUIRES_SHARED(Locks::mutator_lock_) {
@@ -280,85 +190,32 @@
   return soa.AddLocalReference<jobjectArray>(ifaces);
 }
 
-static ObjPtr<mirror::ObjectArray<mirror::Field>> GetDeclaredFields(
-    Thread* self,
-    ObjPtr<mirror::Class> klass,
-    bool public_only,
-    bool force_resolve) REQUIRES_SHARED(Locks::mutator_lock_) {
-  if (UNLIKELY(klass->IsObsoleteObject())) {
-    ThrowRuntimeException("Obsolete Object!");
-    return nullptr;
-  }
-  StackHandleScope<1> hs(self);
-  IterationRange<StrideIterator<ArtField>> ifields = klass->GetIFields();
-  IterationRange<StrideIterator<ArtField>> sfields = klass->GetSFields();
-  size_t array_size = klass->NumInstanceFields() + klass->NumStaticFields();
-  hiddenapi::AccessContext hiddenapi_context = GetReflectionCaller(self);
-  // Lets go subtract all the non discoverable fields.
-  for (ArtField& field : ifields) {
-    if (!IsDiscoverable(public_only, hiddenapi_context, &field)) {
-      --array_size;
-    }
-  }
-  for (ArtField& field : sfields) {
-    if (!IsDiscoverable(public_only, hiddenapi_context, &field)) {
-      --array_size;
-    }
-  }
-  size_t array_idx = 0;
-  auto object_array = hs.NewHandle(mirror::ObjectArray<mirror::Field>::Alloc(
-      self, GetClassRoot<mirror::ObjectArray<mirror::Field>>(), array_size));
-  if (object_array == nullptr) {
-    return nullptr;
-  }
-  for (ArtField& field : ifields) {
-    if (IsDiscoverable(public_only, hiddenapi_context, &field)) {
-      ObjPtr<mirror::Field> reflect_field =
-          mirror::Field::CreateFromArtField(self, &field, force_resolve);
-      if (reflect_field == nullptr) {
-        if (kIsDebugBuild) {
-          self->AssertPendingException();
-        }
-        // Maybe null due to OOME or type resolving exception.
-        return nullptr;
-      }
-      object_array->SetWithoutChecks<false>(array_idx++, reflect_field);
-    }
-  }
-  for (ArtField& field : sfields) {
-    if (IsDiscoverable(public_only, hiddenapi_context, &field)) {
-      ObjPtr<mirror::Field> reflect_field =
-          mirror::Field::CreateFromArtField(self, &field, force_resolve);
-      if (reflect_field == nullptr) {
-        if (kIsDebugBuild) {
-          self->AssertPendingException();
-        }
-        return nullptr;
-      }
-      object_array->SetWithoutChecks<false>(array_idx++, reflect_field);
-    }
-  }
-  DCHECK_EQ(array_idx, array_size);
-  return object_array.Get();
-}
-
 static jobjectArray Class_getDeclaredFieldsUnchecked(JNIEnv* env, jobject javaThis,
                                                      jboolean publicOnly) {
   ScopedFastNativeObjectAccess soa(env);
+  ObjPtr<mirror::Class> klass = DecodeClass(soa, javaThis);
   return soa.AddLocalReference<jobjectArray>(
-      GetDeclaredFields(soa.Self(), DecodeClass(soa, javaThis), publicOnly != JNI_FALSE, false));
+      klass->GetDeclaredFields(soa.Self(),
+                               publicOnly != JNI_FALSE,
+                               /*force_resolve=*/ false));
 }
 
 static jobjectArray Class_getDeclaredFields(JNIEnv* env, jobject javaThis) {
   ScopedFastNativeObjectAccess soa(env);
+  ObjPtr<mirror::Class> klass = DecodeClass(soa, javaThis);
   return soa.AddLocalReference<jobjectArray>(
-      GetDeclaredFields(soa.Self(), DecodeClass(soa, javaThis), false, true));
+      klass->GetDeclaredFields(soa.Self(),
+                               /*public_only=*/ false,
+                               /*force_resolve=*/ true));
 }
 
 static jobjectArray Class_getPublicDeclaredFields(JNIEnv* env, jobject javaThis) {
   ScopedFastNativeObjectAccess soa(env);
+  ObjPtr<mirror::Class> klass = DecodeClass(soa, javaThis);
   return soa.AddLocalReference<jobjectArray>(
-      GetDeclaredFields(soa.Self(), DecodeClass(soa, javaThis), true, true));
+      klass->GetDeclaredFields(soa.Self(),
+                               /*public_only=*/ true,
+                               /*force_resolve=*/ true));
 }
 
 // Performs a binary search through an array of fields, TODO: Is this fast enough if we don't use
@@ -559,7 +416,7 @@
   DCHECK(m != nullptr);
   return m->IsConstructor() &&
          !m->IsStatic() &&
-         IsDiscoverable(public_only, hiddenapi_context, m);
+         mirror::Class::IsDiscoverable(public_only, hiddenapi_context, m);
 }
 
 static jobjectArray Class_getDeclaredConstructorsInternal(
@@ -567,7 +424,7 @@
   ScopedFastNativeObjectAccess soa(env);
   StackHandleScope<2> hs(soa.Self());
   bool public_only = (publicOnly != JNI_FALSE);
-  hiddenapi::AccessContext hiddenapi_context = GetReflectionCaller(soa.Self());
+  auto hiddenapi_context = hiddenapi::GetReflectionCallerAccessContext(soa.Self());
   Handle<mirror::Class> h_klass = hs.NewHandle(DecodeClass(soa, javaThis));
   if (UNLIKELY(h_klass->IsObsoleteObject())) {
     ThrowRuntimeException("Obsolete Object!");
@@ -630,7 +487,7 @@
   ScopedFastNativeObjectAccess soa(env);
   StackHandleScope<2> hs(soa.Self());
 
-  hiddenapi::AccessContext hiddenapi_context = GetReflectionCaller(soa.Self());
+  auto hiddenapi_context = hiddenapi::GetReflectionCallerAccessContext(soa.Self());
   bool public_only = (publicOnly != JNI_FALSE);
 
   Handle<mirror::Class> klass = hs.NewHandle(DecodeClass(soa, javaThis));
@@ -643,7 +500,7 @@
     uint32_t modifiers = m.GetAccessFlags();
     // Add non-constructor declared methods.
     if ((modifiers & kAccConstructor) == 0 &&
-        IsDiscoverable(public_only, hiddenapi_context, &m)) {
+        mirror::Class::IsDiscoverable(public_only, hiddenapi_context, &m)) {
       ++num_methods;
     }
   }
@@ -657,7 +514,7 @@
   for (ArtMethod& m : klass->GetDeclaredMethods(kRuntimePointerSize)) {
     uint32_t modifiers = m.GetAccessFlags();
     if ((modifiers & kAccConstructor) == 0 &&
-        IsDiscoverable(public_only, hiddenapi_context, &m)) {
+        mirror::Class::IsDiscoverable(public_only, hiddenapi_context, &m)) {
       DCHECK_EQ(Runtime::Current()->GetClassLinker()->GetImagePointerSize(), kRuntimePointerSize);
       DCHECK(!Runtime::Current()->IsActiveTransaction());
       ObjPtr<mirror::Method> method =