Implement can_generate_native_method_bind capability

This capability lets one observe and even replace the implementations
of native methods when they are bound.

Test: ./test.py --host -j40

Bug: 37432636
Change-Id: I2432a8e4da1a677e8011ce495296f4ab9f42eb3e
diff --git a/runtime/openjdkjvmti/OpenjdkJvmTi.cc b/runtime/openjdkjvmti/OpenjdkJvmTi.cc
index 39e603e..c3a94b9 100644
--- a/runtime/openjdkjvmti/OpenjdkJvmTi.cc
+++ b/runtime/openjdkjvmti/OpenjdkJvmTi.cc
@@ -1556,6 +1556,7 @@
   ThreadUtil::Register(&gEventHandler);
   ClassUtil::Register(&gEventHandler);
   DumpUtil::Register(&gEventHandler);
+  MethodUtil::Register(&gEventHandler);
   SearchUtil::Register();
   HeapUtil::Register();
 
@@ -1569,6 +1570,7 @@
   ThreadUtil::Unregister();
   ClassUtil::Unregister();
   DumpUtil::Unregister();
+  MethodUtil::Unregister();
   SearchUtil::Unregister();
   HeapUtil::Unregister();
 
diff --git a/runtime/openjdkjvmti/art_jvmti.h b/runtime/openjdkjvmti/art_jvmti.h
index 2ff3a47..2a2aa4c 100644
--- a/runtime/openjdkjvmti/art_jvmti.h
+++ b/runtime/openjdkjvmti/art_jvmti.h
@@ -223,7 +223,7 @@
     .can_generate_compiled_method_load_events        = 0,
     .can_generate_monitor_events                     = 0,
     .can_generate_vm_object_alloc_events             = 1,
-    .can_generate_native_method_bind_events          = 0,
+    .can_generate_native_method_bind_events          = 1,
     .can_generate_garbage_collection_events          = 1,
     .can_generate_object_free_events                 = 1,
     .can_force_early_return                          = 0,
diff --git a/runtime/openjdkjvmti/events-inl.h b/runtime/openjdkjvmti/events-inl.h
index 233b45c..57abf31 100644
--- a/runtime/openjdkjvmti/events-inl.h
+++ b/runtime/openjdkjvmti/events-inl.h
@@ -191,6 +191,27 @@
   }
 }
 
+// Need to give a custom specialization for NativeMethodBind since it has to deal with an out
+// variable.
+template <>
+inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kNativeMethodBind>(art::Thread* thread,
+                                                                          JNIEnv* jnienv,
+                                                                          jthread jni_thread,
+                                                                          jmethodID method,
+                                                                          void* cur_method,
+                                                                          void** new_method) const {
+  *new_method = cur_method;
+  for (ArtJvmTiEnv* env : envs) {
+    if (env != nullptr && ShouldDispatch<ArtJvmtiEvent::kNativeMethodBind>(env, thread)) {
+      auto callback = impl::GetCallback<ArtJvmtiEvent::kNativeMethodBind>(env);
+      (*callback)(env, jnienv, jni_thread, method, cur_method, new_method);
+      if (*new_method != nullptr) {
+        cur_method = *new_method;
+      }
+    }
+  }
+}
+
 // C++ does not allow partial template function specialization. The dispatch for our separated
 // ClassFileLoadHook event types is the same, and in the DispatchClassFileLoadHookEvent helper.
 // The following two DispatchEvent specializations dispatch to it.
diff --git a/runtime/openjdkjvmti/ti_method.cc b/runtime/openjdkjvmti/ti_method.cc
index 01bf21d..2adabba 100644
--- a/runtime/openjdkjvmti/ti_method.cc
+++ b/runtime/openjdkjvmti/ti_method.cc
@@ -35,14 +35,59 @@
 #include "art_method-inl.h"
 #include "base/enums.h"
 #include "dex_file_annotations.h"
+#include "events-inl.h"
 #include "jni_internal.h"
 #include "mirror/object_array-inl.h"
 #include "modifiers.h"
+#include "runtime_callbacks.h"
 #include "scoped_thread_state_change-inl.h"
+#include "ScopedLocalRef.h"
 #include "thread-inl.h"
+#include "thread_list.h"
 
 namespace openjdkjvmti {
 
+struct TiMethodCallback : public art::MethodCallback {
+  void RegisterNativeMethod(art::ArtMethod* method,
+                            const void* cur_method,
+                            /*out*/void** new_method)
+      OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) {
+    if (event_handler->IsEventEnabledAnywhere(ArtJvmtiEvent::kNativeMethodBind)) {
+      art::Thread* thread = art::Thread::Current();
+      ScopedLocalRef<jthread> thread_jni(
+          thread->GetJniEnv(), thread->GetJniEnv()->AddLocalReference<jthread>(thread->GetPeer()));
+      art::ScopedThreadSuspension sts(thread, art::ThreadState::kNative);
+      event_handler->DispatchEvent<ArtJvmtiEvent::kNativeMethodBind>(
+          thread,
+          static_cast<JNIEnv*>(thread->GetJniEnv()),
+          thread_jni.get(),
+          art::jni::EncodeArtMethod(method),
+          const_cast<void*>(cur_method),
+          new_method);
+    }
+  }
+
+  EventHandler* event_handler = nullptr;
+};
+
+TiMethodCallback gMethodCallback;
+
+void MethodUtil::Register(EventHandler* handler) {
+  gMethodCallback.event_handler = handler;
+  art::ScopedThreadStateChange stsc(art::Thread::Current(),
+                                    art::ThreadState::kWaitingForDebuggerToAttach);
+  art::ScopedSuspendAll ssa("Add method callback");
+  art::Runtime::Current()->GetRuntimeCallbacks()->AddMethodCallback(&gMethodCallback);
+}
+
+void MethodUtil::Unregister() {
+  art::ScopedThreadStateChange stsc(art::Thread::Current(),
+                                    art::ThreadState::kWaitingForDebuggerToAttach);
+  art::ScopedSuspendAll ssa("Remove method callback");
+  art::Runtime* runtime = art::Runtime::Current();
+  runtime->GetRuntimeCallbacks()->RemoveMethodCallback(&gMethodCallback);
+}
+
 jvmtiError MethodUtil::GetArgumentsSize(jvmtiEnv* env ATTRIBUTE_UNUSED,
                                         jmethodID method,
                                         jint* size_ptr) {
diff --git a/runtime/openjdkjvmti/ti_method.h b/runtime/openjdkjvmti/ti_method.h
index e5c1705..cc161c8 100644
--- a/runtime/openjdkjvmti/ti_method.h
+++ b/runtime/openjdkjvmti/ti_method.h
@@ -37,8 +37,13 @@
 
 namespace openjdkjvmti {
 
+class EventHandler;
+
 class MethodUtil {
  public:
+  static void Register(EventHandler* event_handler);
+  static void Unregister();
+
   static jvmtiError GetArgumentsSize(jvmtiEnv* env, jmethodID method, jint* size_ptr);
 
   static jvmtiError GetMaxLocals(jvmtiEnv* env, jmethodID method, jint* max_ptr);