Add support for Executable.getParameters() metadata

java.lang.reflect.Executable native code to create Parameter
objects and supporting code for obtaining the system annotations
that hold the parameter metadata.

Bug: 30391692
Test: test-art-host and CtsLibcoreTestCases
Change-Id: I23d7e36014716967ce189fba5955cc5e064fe8d0
diff --git a/runtime/dex_file_annotations.cc b/runtime/dex_file_annotations.cc
index c6c87fd..e0d5337 100644
--- a/runtime/dex_file_annotations.cc
+++ b/runtime/dex_file_annotations.cc
@@ -1027,6 +1027,66 @@
                                               annotation_class);
 }
 
+bool GetParametersMetadataForMethod(ArtMethod* method,
+                                    MutableHandle<mirror::ObjectArray<mirror::String>>* names,
+                                    MutableHandle<mirror::IntArray>* access_flags) {
+  const DexFile::AnnotationSetItem::AnnotationSetItem* annotation_set =
+      FindAnnotationSetForMethod(method);
+  if (annotation_set == nullptr) {
+    return false;
+  }
+
+  const DexFile* dex_file = method->GetDexFile();
+  const DexFile::AnnotationItem* annotation_item =
+      SearchAnnotationSet(*dex_file,
+                          annotation_set,
+                          "Ldalvik/annotation/MethodParameters;",
+                          DexFile::kDexVisibilitySystem);
+  if (annotation_item == nullptr) {
+    return false;
+  }
+
+  StackHandleScope<5> hs(Thread::Current());
+
+  // Extract the parameters' names String[].
+  mirror::Class* string_class = mirror::String::GetJavaLangString();
+  Handle<mirror::Class> string_array_class(hs.NewHandle(
+      Runtime::Current()->GetClassLinker()->FindArrayClass(Thread::Current(), &string_class)));
+  if (UNLIKELY(string_array_class.Get() == nullptr)) {
+    return false;
+  }
+
+  Handle<mirror::Class> klass = hs.NewHandle(method->GetDeclaringClass());
+  Handle<mirror::Object> names_obj =
+      hs.NewHandle(GetAnnotationValue(klass,
+                                      annotation_item,
+                                      "names",
+                                      string_array_class,
+                                      DexFile::kDexAnnotationArray));
+  if (names_obj.Get() == nullptr) {
+    return false;
+  }
+
+  // Extract the parameters' access flags int[].
+  Handle<mirror::Class> int_array_class(hs.NewHandle(mirror::IntArray::GetArrayClass()));
+  if (UNLIKELY(int_array_class.Get() == nullptr)) {
+    return false;
+  }
+  Handle<mirror::Object> access_flags_obj =
+      hs.NewHandle(GetAnnotationValue(klass,
+                                      annotation_item,
+                                      "accessFlags",
+                                      int_array_class,
+                                      DexFile::kDexAnnotationArray));
+  if (access_flags_obj.Get() == nullptr) {
+    return false;
+  }
+
+  names->Assign(names_obj.Get()->AsObjectArray<mirror::String>());
+  access_flags->Assign(access_flags_obj.Get()->AsIntArray());
+  return true;
+}
+
 mirror::ObjectArray<mirror::String>* GetSignatureAnnotationForMethod(ArtMethod* method) {
   const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForMethod(method);
   if (annotation_set == nullptr) {
diff --git a/runtime/dex_file_annotations.h b/runtime/dex_file_annotations.h
index 7b4e856..c66c5bd 100644
--- a/runtime/dex_file_annotations.h
+++ b/runtime/dex_file_annotations.h
@@ -30,6 +30,7 @@
 class ArtField;
 class ArtMethod;
 class ClassLinker;
+template<class T> class MutableHandle;
 
 namespace annotations {
 
@@ -58,6 +59,10 @@
                                                 uint32_t parameter_idx,
                                                 Handle<mirror::Class> annotation_class)
     REQUIRES_SHARED(Locks::mutator_lock_);
+bool GetParametersMetadataForMethod(ArtMethod* method,
+                                    MutableHandle<mirror::ObjectArray<mirror::String>>* names,
+                                    MutableHandle<mirror::IntArray>* access_flags)
+    REQUIRES_SHARED(Locks::mutator_lock_);
 mirror::ObjectArray<mirror::String>* GetSignatureAnnotationForMethod(ArtMethod* method)
     REQUIRES_SHARED(Locks::mutator_lock_);
 bool IsMethodAnnotationPresent(ArtMethod* method, Handle<mirror::Class> annotation_class,
diff --git a/runtime/native/java_lang_reflect_Executable.cc b/runtime/native/java_lang_reflect_Executable.cc
index 8fcf6ac..f345c09 100644
--- a/runtime/native/java_lang_reflect_Executable.cc
+++ b/runtime/native/java_lang_reflect_Executable.cc
@@ -18,8 +18,10 @@
 
 #include "art_method-inl.h"
 #include "dex_file_annotations.h"
+#include "handle.h"
 #include "jni_internal.h"
 #include "mirror/class-inl.h"
+#include "mirror/method.h"
 #include "mirror/object-inl.h"
 #include "mirror/object_array-inl.h"
 #include "reflection.h"
@@ -43,8 +45,8 @@
 }
 
 static jobject Executable_getAnnotationNative(JNIEnv* env,
-                                                  jobject javaMethod,
-                                                  jclass annotationType) {
+                                              jobject javaMethod,
+                                              jclass annotationType) {
   ScopedFastNativeObjectAccess soa(env);
   StackHandleScope<1> hs(soa.Self());
   ArtMethod* method = ArtMethod::FromReflectedMethod(soa, javaMethod);
@@ -77,9 +79,107 @@
   }
 }
 
+static jobjectArray Executable_getParameters0(JNIEnv* env, jobject javaMethod) {
+  ScopedFastNativeObjectAccess soa(env);
+  Thread* self = soa.Self();
+  StackHandleScope<8> hs(self);
+
+  Handle<mirror::Method> executable = hs.NewHandle(soa.Decode<mirror::Method*>(javaMethod));
+  ArtMethod* art_method = executable.Get()->GetArtMethod();
+  if (art_method->GetDeclaringClass()->IsProxyClass()) {
+    return nullptr;
+  }
+
+  // Find the MethodParameters system annotation.
+  MutableHandle<mirror::ObjectArray<mirror::String>> names =
+      hs.NewHandle<mirror::ObjectArray<mirror::String>>(nullptr);
+  MutableHandle<mirror::IntArray> access_flags = hs.NewHandle<mirror::IntArray>(nullptr);
+  if (!annotations::GetParametersMetadataForMethod(art_method, &names, &access_flags)) {
+    return nullptr;
+  }
+
+  // Validate the MethodParameters system annotation data.
+  if (UNLIKELY(names.Get() == nullptr || access_flags.Get() == nullptr)) {
+    ThrowIllegalArgumentException(
+        StringPrintf("Missing parameter metadata for names or access flags for %s",
+                     PrettyMethod(art_method).c_str()).c_str());
+    return nullptr;
+  }
+
+  // Check array sizes match each other
+  int32_t names_count = names.Get()->GetLength();
+  int32_t access_flags_count = access_flags.Get()->GetLength();
+  if (names_count != access_flags_count) {
+    ThrowIllegalArgumentException(
+        StringPrintf(
+            "Inconsistent parameter metadata for %s. names length: %d, access flags length: %d",
+            PrettyMethod(art_method).c_str(),
+            names_count,
+            access_flags_count).c_str());
+    return nullptr;
+  }
+
+  // Instantiate a Parameter[] to hold the result.
+  Handle<mirror::Class> parameter_array_class =
+      hs.NewHandle(
+          soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_reflect_Parameter__array));
+  Handle<mirror::ObjectArray<mirror::Object>> parameter_array =
+      hs.NewHandle(
+          mirror::ObjectArray<mirror::Object>::Alloc(self,
+                                                     parameter_array_class.Get(),
+                                                     names_count));
+  if (UNLIKELY(parameter_array.Get() == nullptr)) {
+    self->AssertPendingException();
+    return nullptr;
+  }
+
+  Handle<mirror::Class> parameter_class =
+      hs.NewHandle(soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_reflect_Parameter));
+  ArtMethod* parameter_init =
+      soa.DecodeMethod(WellKnownClasses::java_lang_reflect_Parameter_init);
+
+  // Mutable handles used in the loop below to ensure cleanup without scaling the number of
+  // handles by the number of parameters.
+  MutableHandle<mirror::String> name = hs.NewHandle<mirror::String>(nullptr);
+  MutableHandle<mirror::Object> parameter = hs.NewHandle<mirror::Object>(nullptr);
+
+  // Populate the Parameter[] to return.
+  for (int32_t parameter_index = 0; parameter_index < names_count; parameter_index++) {
+    name.Assign(names.Get()->Get(parameter_index));
+    int32_t modifiers = access_flags.Get()->Get(parameter_index);
+
+    // Allocate / initialize the Parameter to add to parameter_array.
+    parameter.Assign(parameter_class->AllocObject(self));
+    if (UNLIKELY(parameter.Get() == nullptr)) {
+      self->AssertPendingOOMException();
+      return nullptr;
+    }
+
+    uint32_t args[5] = { PointerToLowMemUInt32(parameter.Get()),
+                         PointerToLowMemUInt32(name.Get()),
+                         static_cast<uint32_t>(modifiers),
+                         PointerToLowMemUInt32(executable.Get()),
+                         static_cast<uint32_t>(parameter_index)
+    };
+    JValue result;
+    static const char* method_signature = "VLILI";  // return + parameter types
+    parameter_init->Invoke(self, args, sizeof(args), &result, method_signature);
+    if (UNLIKELY(self->IsExceptionPending())) {
+      return nullptr;
+    }
+
+    // Store the Parameter in the Parameter[].
+    parameter_array.Get()->Set(parameter_index, parameter.Get());
+    if (UNLIKELY(self->IsExceptionPending())) {
+      return nullptr;
+    }
+  }
+  return soa.AddLocalReference<jobjectArray>(parameter_array.Get());
+}
+
 static jboolean Executable_isAnnotationPresentNative(JNIEnv* env,
-                                                         jobject javaMethod,
-                                                         jclass annotationType) {
+                                                     jobject javaMethod,
+                                                     jclass annotationType) {
   ScopedFastNativeObjectAccess soa(env);
   ArtMethod* method = ArtMethod::FromReflectedMethod(soa, javaMethod);
   if (method->GetDeclaringClass()->IsProxyClass()) {
@@ -96,6 +196,7 @@
   NATIVE_METHOD(Executable, getDeclaredAnnotationsNative, "!()[Ljava/lang/annotation/Annotation;"),
   NATIVE_METHOD(Executable, getParameterAnnotationsNative,
                 "!()[[Ljava/lang/annotation/Annotation;"),
+  NATIVE_METHOD(Executable, getParameters0, "!()[Ljava/lang/reflect/Parameter;"),
   NATIVE_METHOD(Executable, getSignatureAnnotation, "!()[Ljava/lang/String;"),
   NATIVE_METHOD(Executable, isAnnotationPresentNative, "!(Ljava/lang/Class;)Z"),
 };
diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc
index 6b569f4..e5216fb 100644
--- a/runtime/well_known_classes.cc
+++ b/runtime/well_known_classes.cc
@@ -53,6 +53,8 @@
 jclass WellKnownClasses::java_lang_reflect_Executable;
 jclass WellKnownClasses::java_lang_reflect_Field;
 jclass WellKnownClasses::java_lang_reflect_Method;
+jclass WellKnownClasses::java_lang_reflect_Parameter;
+jclass WellKnownClasses::java_lang_reflect_Parameter__array;
 jclass WellKnownClasses::java_lang_reflect_Proxy;
 jclass WellKnownClasses::java_lang_RuntimeException;
 jclass WellKnownClasses::java_lang_StackOverflowError;
@@ -87,6 +89,7 @@
 jmethodID WellKnownClasses::java_lang_Long_valueOf;
 jmethodID WellKnownClasses::java_lang_ref_FinalizerReference_add;
 jmethodID WellKnownClasses::java_lang_ref_ReferenceQueue_add;
+jmethodID WellKnownClasses::java_lang_reflect_Parameter_init;
 jmethodID WellKnownClasses::java_lang_reflect_Proxy_invoke;
 jmethodID WellKnownClasses::java_lang_Runtime_nativeLoad;
 jmethodID WellKnownClasses::java_lang_Short_valueOf;
@@ -280,6 +283,8 @@
   java_lang_reflect_Executable = CacheClass(env, "java/lang/reflect/Executable");
   java_lang_reflect_Field = CacheClass(env, "java/lang/reflect/Field");
   java_lang_reflect_Method = CacheClass(env, "java/lang/reflect/Method");
+  java_lang_reflect_Parameter = CacheClass(env, "java/lang/reflect/Parameter");
+  java_lang_reflect_Parameter__array = CacheClass(env, "[Ljava/lang/reflect/Parameter;");
   java_lang_reflect_Proxy = CacheClass(env, "java/lang/reflect/Proxy");
   java_lang_RuntimeException = CacheClass(env, "java/lang/RuntimeException");
   java_lang_StackOverflowError = CacheClass(env, "java/lang/StackOverflowError");
@@ -312,6 +317,7 @@
   ScopedLocalRef<jclass> java_lang_ref_ReferenceQueue(env, env->FindClass("java/lang/ref/ReferenceQueue"));
   java_lang_ref_ReferenceQueue_add = CacheMethod(env, java_lang_ref_ReferenceQueue.get(), true, "add", "(Ljava/lang/ref/Reference;)V");
 
+  java_lang_reflect_Parameter_init = CacheMethod(env, java_lang_reflect_Parameter, false, "<init>", "(Ljava/lang/String;ILjava/lang/reflect/Executable;I)V");
   java_lang_reflect_Proxy_invoke = CacheMethod(env, java_lang_reflect_Proxy, true, "invoke", "(Ljava/lang/reflect/Proxy;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;");
   java_lang_Thread_dispatchUncaughtException = CacheMethod(env, java_lang_Thread, false, "dispatchUncaughtException", "(Ljava/lang/Throwable;)V");
   java_lang_Thread_init = CacheMethod(env, java_lang_Thread, false, "<init>", "(Ljava/lang/ThreadGroup;Ljava/lang/String;IZ)V");
diff --git a/runtime/well_known_classes.h b/runtime/well_known_classes.h
index c9110e6..ddfc5b8 100644
--- a/runtime/well_known_classes.h
+++ b/runtime/well_known_classes.h
@@ -67,6 +67,8 @@
   static jclass java_lang_reflect_Executable;
   static jclass java_lang_reflect_Field;
   static jclass java_lang_reflect_Method;
+  static jclass java_lang_reflect_Parameter;
+  static jclass java_lang_reflect_Parameter__array;
   static jclass java_lang_reflect_Proxy;
   static jclass java_lang_RuntimeException;
   static jclass java_lang_StackOverflowError;
@@ -101,6 +103,7 @@
   static jmethodID java_lang_Long_valueOf;
   static jmethodID java_lang_ref_FinalizerReference_add;
   static jmethodID java_lang_ref_ReferenceQueue_add;
+  static jmethodID java_lang_reflect_Parameter_init;
   static jmethodID java_lang_reflect_Proxy_invoke;
   static jmethodID java_lang_Runtime_nativeLoad;
   static jmethodID java_lang_Short_valueOf;