Start enforcing hidden API blacklist

Insert checks into reflection, JNI and Class::CanAccessMember to
make blacklisted hidden APIs undiscoverable.

The change was tested with internal microbenchmarks of reflection
and those showed no measurable performance impact.

Test: art/test.py -b -r -t 674-hiddenapi
Bug: 64382372
Change-Id: I9e39804b837ae9ffeba926f2a5b1e8e9986c472b
diff --git a/runtime/native/java_lang_Class.cc b/runtime/native/java_lang_Class.cc
index 7b999c0..4d36e80 100644
--- a/runtime/native/java_lang_Class.cc
+++ b/runtime/native/java_lang_Class.cc
@@ -25,6 +25,7 @@
 #include "common_throws.h"
 #include "dex/dex_file-inl.h"
 #include "dex/dex_file_annotations.h"
+#include "hidden_api.h"
 #include "jni_internal.h"
 #include "mirror/class-inl.h"
 #include "mirror/class_loader.h"
@@ -47,6 +48,75 @@
 
 namespace art {
 
+ALWAYS_INLINE static bool ShouldEnforceHiddenApi(Thread* self)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  if (!Runtime::Current()->AreHiddenApiChecksEnabled()) {
+    return false;
+  }
+
+  // Walk the stack and find the first frame not from java.lang.Class.
+  // This is very expensive. Save this till the last.
+  struct FirstNonClassClassCallerVisitor : public StackVisitor {
+    explicit FirstNonClassClassCallerVisitor(Thread* thread)
+        : StackVisitor(thread, nullptr, StackVisitor::StackWalkKind::kIncludeInlinedFrames),
+          caller(nullptr) {
+    }
+
+    bool VisitFrame() 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;
+      } else if (m->GetDeclaringClass()->IsClassClass()) {
+        return true;
+      } else {
+        caller = m;
+        return false;
+      }
+    }
+
+    ArtMethod* caller;
+  };
+
+  FirstNonClassClassCallerVisitor visitor(self);
+  visitor.WalkStack();
+  return visitor.caller == nullptr ||
+         !visitor.caller->GetDeclaringClass()->IsBootStrapClassLoaded();
+}
+
+// Returns true if the first non-ClassClass caller up the stack should not be
+// allowed access to `member`.
+template<typename T>
+ALWAYS_INLINE static bool ShouldBlockAccessToMember(T* member, Thread* self)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  DCHECK(member != nullptr);
+  return hiddenapi::IsMemberHidden(member->GetAccessFlags()) &&
+         ShouldEnforceHiddenApi(self);
+}
+
+// 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 (enforce_hidden_api == true).
+ALWAYS_INLINE static bool IsDiscoverable(bool public_only,
+                                         bool enforce_hidden_api,
+                                         uint32_t access_flags) {
+  if (public_only && ((access_flags & kAccPublic) == 0)) {
+    return false;
+  }
+
+  if (enforce_hidden_api && hiddenapi::IsMemberHidden(access_flags)) {
+    return false;
+  }
+
+  return true;
+}
+
+
 ALWAYS_INLINE static inline ObjPtr<mirror::Class> DecodeClass(
     const ScopedFastNativeObjectAccess& soa, jobject java_class)
     REQUIRES_SHARED(Locks::mutator_lock_) {
@@ -164,17 +234,16 @@
   IterationRange<StrideIterator<ArtField>> ifields = klass->GetIFields();
   IterationRange<StrideIterator<ArtField>> sfields = klass->GetSFields();
   size_t array_size = klass->NumInstanceFields() + klass->NumStaticFields();
-  if (public_only) {
-    // Lets go subtract all the non public fields.
-    for (ArtField& field : ifields) {
-      if (!field.IsPublic()) {
-        --array_size;
-      }
+  bool enforce_hidden_api = ShouldEnforceHiddenApi(self);
+  // Lets go subtract all the non discoverable fields.
+  for (ArtField& field : ifields) {
+    if (!IsDiscoverable(public_only, enforce_hidden_api, field.GetAccessFlags())) {
+      --array_size;
     }
-    for (ArtField& field : sfields) {
-      if (!field.IsPublic()) {
-        --array_size;
-      }
+  }
+  for (ArtField& field : sfields) {
+    if (!IsDiscoverable(public_only, enforce_hidden_api, field.GetAccessFlags())) {
+      --array_size;
     }
   }
   size_t array_idx = 0;
@@ -184,7 +253,7 @@
     return nullptr;
   }
   for (ArtField& field : ifields) {
-    if (!public_only || field.IsPublic()) {
+    if (IsDiscoverable(public_only, enforce_hidden_api, field.GetAccessFlags())) {
       auto* reflect_field = mirror::Field::CreateFromArtField<kRuntimePointerSize>(self,
                                                                                    &field,
                                                                                    force_resolve);
@@ -199,7 +268,7 @@
     }
   }
   for (ArtField& field : sfields) {
-    if (!public_only || field.IsPublic()) {
+    if (IsDiscoverable(public_only, enforce_hidden_api, field.GetAccessFlags())) {
       auto* reflect_field = mirror::Field::CreateFromArtField<kRuntimePointerSize>(self,
                                                                                    &field,
                                                                                    force_resolve);
@@ -354,8 +423,13 @@
     ThrowNullPointerException("name == null");
     return nullptr;
   }
-  return soa.AddLocalReference<jobject>(
-      GetPublicFieldRecursive(soa.Self(), DecodeClass(soa, javaThis), name_string));
+
+  mirror::Field* field = GetPublicFieldRecursive(
+      soa.Self(), DecodeClass(soa, javaThis), name_string);
+  if (field == nullptr || ShouldBlockAccessToMember(field->GetArtField(), soa.Self())) {
+    return nullptr;
+  }
+  return soa.AddLocalReference<jobject>(field);
 }
 
 static jobject Class_getDeclaredField(JNIEnv* env, jobject javaThis, jstring name) {
@@ -369,7 +443,7 @@
   Handle<mirror::Class> h_klass = hs.NewHandle(DecodeClass(soa, javaThis));
   Handle<mirror::Field> result =
       hs.NewHandle(GetDeclaredField(soa.Self(), h_klass.Get(), h_string.Get()));
-  if (result == nullptr) {
+  if (result == nullptr || ShouldBlockAccessToMember(result->GetArtField(), soa.Self())) {
     std::string name_str = h_string->ToModifiedUtf8();
     if (name_str == "value" && h_klass->IsStringClass()) {
       // We log the error for this specific case, as the user might just swallow the exception.
@@ -399,24 +473,32 @@
       soa.Self(),
       DecodeClass(soa, javaThis),
       soa.Decode<mirror::ObjectArray<mirror::Class>>(args));
+  if (result == nullptr || ShouldBlockAccessToMember(result->GetArtMethod(), soa.Self())) {
+    return nullptr;
+  }
   return soa.AddLocalReference<jobject>(result);
 }
 
-static ALWAYS_INLINE inline bool MethodMatchesConstructor(ArtMethod* m, bool public_only)
+static ALWAYS_INLINE inline bool MethodMatchesConstructor(
+    ArtMethod* m, bool public_only, bool enforce_hidden_api)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   DCHECK(m != nullptr);
-  return (!public_only || m->IsPublic()) && !m->IsStatic() && m->IsConstructor();
+  return m->IsConstructor() &&
+         !m->IsStatic() &&
+         IsDiscoverable(public_only, enforce_hidden_api, m->GetAccessFlags());
 }
 
 static jobjectArray Class_getDeclaredConstructorsInternal(
     JNIEnv* env, jobject javaThis, jboolean publicOnly) {
   ScopedFastNativeObjectAccess soa(env);
   StackHandleScope<2> hs(soa.Self());
+  bool public_only = (publicOnly != JNI_FALSE);
+  bool enforce_hidden_api = ShouldEnforceHiddenApi(soa.Self());
   Handle<mirror::Class> h_klass = hs.NewHandle(DecodeClass(soa, javaThis));
   size_t constructor_count = 0;
   // Two pass approach for speed.
   for (auto& m : h_klass->GetDirectMethods(kRuntimePointerSize)) {
-    constructor_count += MethodMatchesConstructor(&m, publicOnly != JNI_FALSE) ? 1u : 0u;
+    constructor_count += MethodMatchesConstructor(&m, public_only, enforce_hidden_api) ? 1u : 0u;
   }
   auto h_constructors = hs.NewHandle(mirror::ObjectArray<mirror::Constructor>::Alloc(
       soa.Self(), mirror::Constructor::ArrayClass(), constructor_count));
@@ -426,7 +508,7 @@
   }
   constructor_count = 0;
   for (auto& m : h_klass->GetDirectMethods(kRuntimePointerSize)) {
-    if (MethodMatchesConstructor(&m, publicOnly != JNI_FALSE)) {
+    if (MethodMatchesConstructor(&m, public_only, enforce_hidden_api)) {
       DCHECK_EQ(Runtime::Current()->GetClassLinker()->GetImagePointerSize(), kRuntimePointerSize);
       DCHECK(!Runtime::Current()->IsActiveTransaction());
       auto* constructor = mirror::Constructor::CreateFromArtMethod<kRuntimePointerSize, false>(
@@ -452,6 +534,9 @@
           DecodeClass(soa, javaThis),
           soa.Decode<mirror::String>(name),
           soa.Decode<mirror::ObjectArray<mirror::Class>>(args));
+  if (result == nullptr || ShouldBlockAccessToMember(result->GetArtMethod(), soa.Self())) {
+    return nullptr;
+  }
   return soa.AddLocalReference<jobject>(result);
 }
 
@@ -459,13 +544,17 @@
                                                       jboolean publicOnly) {
   ScopedFastNativeObjectAccess soa(env);
   StackHandleScope<2> hs(soa.Self());
+
+  bool enforce_hidden_api = ShouldEnforceHiddenApi(soa.Self());
+  bool public_only = (publicOnly != JNI_FALSE);
+
   Handle<mirror::Class> klass = hs.NewHandle(DecodeClass(soa, javaThis));
   size_t num_methods = 0;
-  for (auto& m : klass->GetDeclaredMethods(kRuntimePointerSize)) {
-    auto modifiers = m.GetAccessFlags();
+  for (ArtMethod& m : klass->GetDeclaredMethods(kRuntimePointerSize)) {
+    uint32_t modifiers = m.GetAccessFlags();
     // Add non-constructor declared methods.
-    if ((publicOnly == JNI_FALSE || (modifiers & kAccPublic) != 0) &&
-        (modifiers & kAccConstructor) == 0) {
+    if ((modifiers & kAccConstructor) == 0 &&
+        IsDiscoverable(public_only, enforce_hidden_api, modifiers)) {
       ++num_methods;
     }
   }
@@ -476,10 +565,10 @@
     return nullptr;
   }
   num_methods = 0;
-  for (auto& m : klass->GetDeclaredMethods(kRuntimePointerSize)) {
-    auto modifiers = m.GetAccessFlags();
-    if ((publicOnly == JNI_FALSE || (modifiers & kAccPublic) != 0) &&
-        (modifiers & kAccConstructor) == 0) {
+  for (ArtMethod& m : klass->GetDeclaredMethods(kRuntimePointerSize)) {
+    uint32_t modifiers = m.GetAccessFlags();
+    if ((modifiers & kAccConstructor) == 0 &&
+        IsDiscoverable(public_only, enforce_hidden_api, modifiers)) {
       DCHECK_EQ(Runtime::Current()->GetClassLinker()->GetImagePointerSize(), kRuntimePointerSize);
       DCHECK(!Runtime::Current()->IsActiveTransaction());
       auto* method =
@@ -693,11 +782,11 @@
       return nullptr;
     }
   }
-  auto* constructor = klass->GetDeclaredConstructor(
+  ArtMethod* constructor = klass->GetDeclaredConstructor(
       soa.Self(),
       ScopedNullHandle<mirror::ObjectArray<mirror::Class>>(),
       kRuntimePointerSize);
-  if (UNLIKELY(constructor == nullptr)) {
+  if (UNLIKELY(constructor == nullptr) || ShouldBlockAccessToMember(constructor, soa.Self())) {
     soa.Self()->ThrowNewExceptionF("Ljava/lang/InstantiationException;",
                                    "%s has no zero argument constructor",
                                    klass->PrettyClass().c_str());