ART: Add event callback support

Add basic event callback support infrastructure. Actual users will
follow.

Bug: 31684920
Test: m test-art-host
Change-Id: Ic496933ef3a94f9d27a2779b7f4fdc5b096eab22
diff --git a/runtime/openjdkjvmti/OpenjdkJvmTi.cc b/runtime/openjdkjvmti/OpenjdkJvmTi.cc
index bea40c8..6812a92 100644
--- a/runtime/openjdkjvmti/OpenjdkJvmTi.cc
+++ b/runtime/openjdkjvmti/OpenjdkJvmTi.cc
@@ -37,12 +37,15 @@
 #include "openjdkjvmti/jvmti.h"
 
 #include "art_jvmti.h"
+#include "base/mutex.h"
+#include "events-inl.h"
 #include "jni_env_ext-inl.h"
 #include "object_tagging.h"
 #include "obj_ptr-inl.h"
 #include "runtime.h"
 #include "scoped_thread_state_change-inl.h"
 #include "thread_list.h"
+#include "thread-inl.h"
 #include "transform.h"
 
 // TODO Remove this at some point by annotating all the methods. It was put in to make the skeleton
@@ -52,6 +55,7 @@
 namespace openjdkjvmti {
 
 ObjectTagTable gObjectTagTable;
+EventHandler gEventHandler;
 
 class JvmtiFunctions {
  private:
@@ -731,10 +735,33 @@
     return ERR(NOT_IMPLEMENTED);
   }
 
+  // TODO: This will require locking, so that an agent can't remove callbacks when we're dispatching
+  //       an event.
   static jvmtiError SetEventCallbacks(jvmtiEnv* env,
                                       const jvmtiEventCallbacks* callbacks,
                                       jint size_of_callbacks) {
-    return ERR(NOT_IMPLEMENTED);
+    if (env == nullptr) {
+      return ERR(NULL_POINTER);
+    }
+    if (size_of_callbacks < 0) {
+      return ERR(ILLEGAL_ARGUMENT);
+    }
+
+    if (callbacks == nullptr) {
+      ArtJvmTiEnv::AsArtJvmTiEnv(env)->event_callbacks.reset();
+      return ERR(NONE);
+    }
+
+    std::unique_ptr<jvmtiEventCallbacks> tmp(new jvmtiEventCallbacks());
+    memset(tmp.get(), 0, sizeof(jvmtiEventCallbacks));
+    size_t copy_size = std::min(sizeof(jvmtiEventCallbacks),
+                                static_cast<size_t>(size_of_callbacks));
+    copy_size = art::RoundDown(copy_size, sizeof(void*));
+    memcpy(tmp.get(), callbacks, copy_size);
+
+    ArtJvmTiEnv::AsArtJvmTiEnv(env)->event_callbacks = std::move(tmp);
+
+    return ERR(NONE);
   }
 
   static jvmtiError SetEventNotificationMode(jvmtiEnv* env,
@@ -742,7 +769,21 @@
                                              jvmtiEvent event_type,
                                              jthread event_thread,
                                              ...) {
-    return ERR(NOT_IMPLEMENTED);
+    art::Thread* art_thread = nullptr;
+    if (event_thread != nullptr) {
+      // TODO: Need non-aborting call here, to return JVMTI_ERROR_INVALID_THREAD.
+      art::ScopedObjectAccess soa(art::Thread::Current());
+      art::MutexLock mu(soa.Self(), *art::Locks::thread_list_lock_);
+      art_thread = art::Thread::FromManagedThread(soa, event_thread);
+
+      if (art_thread == nullptr ||  // The thread hasn't been started or is already dead.
+          art_thread->IsStillStarting()) {
+        // TODO: We may want to let the EventHandler know, so it could clean up masks, potentially.
+        return ERR(THREAD_NOT_ALIVE);
+      }
+    }
+
+    return gEventHandler.SetEvent(ArtJvmTiEnv::AsArtJvmTiEnv(env), art_thread, event_type, mode);
   }
 
   static jvmtiError GenerateEvents(jvmtiEnv* env, jvmtiEvent event_type) {
@@ -1018,6 +1059,8 @@
 static void CreateArtJvmTiEnv(art::JavaVMExt* vm, /*out*/void** new_jvmtiEnv) {
   struct ArtJvmTiEnv* env = new ArtJvmTiEnv(vm);
   *new_jvmtiEnv = env;
+
+  gEventHandler.RegisterArtJvmTiEnv(env);
 }
 
 // A hook that the runtime uses to allow plugins to handle GetEnv calls. It returns true and