ART: Add phase events

Add VMStart, VMInit and VMDeath event support. Add removal of
jvmtiEnv from the event handler. Add and extend tests.

Bug: 31684920
Test: m test-art-host-901-hello-ti-agent
Change-Id: I914dfac98c2fb7b59efdfde69597a7fcd20fd486
diff --git a/runtime/openjdkjvmti/OpenjdkJvmTi.cc b/runtime/openjdkjvmti/OpenjdkJvmTi.cc
index 53f8747..7882ece 100644
--- a/runtime/openjdkjvmti/OpenjdkJvmTi.cc
+++ b/runtime/openjdkjvmti/OpenjdkJvmTi.cc
@@ -1105,6 +1105,7 @@
 
   static jvmtiError DisposeEnvironment(jvmtiEnv* env) {
     ENSURE_VALID_ENV(env);
+    gEventHandler.RemoveArtJvmTiEnv(ArtJvmTiEnv::AsArtJvmTiEnv(env));
     delete env;
     return OK;
   }
@@ -1307,7 +1308,7 @@
   } else {
     PhaseUtil::SetToOnLoad();
   }
-  PhaseUtil::Register();
+  PhaseUtil::Register(&gEventHandler);
 
   runtime->GetJavaVM()->AddEnvironmentHook(GetEnvHandler);
   runtime->AddSystemWeakHolder(&gObjectTagTable);
diff --git a/runtime/openjdkjvmti/events.cc b/runtime/openjdkjvmti/events.cc
index f38aa86..7182055 100644
--- a/runtime/openjdkjvmti/events.cc
+++ b/runtime/openjdkjvmti/events.cc
@@ -144,6 +144,18 @@
   envs.push_back(env);
 }
 
+void EventHandler::RemoveArtJvmTiEnv(ArtJvmTiEnv* env) {
+  auto it = std::find(envs.begin(), envs.end(), env);
+  if (it != envs.end()) {
+    envs.erase(it);
+    for (size_t i = static_cast<size_t>(ArtJvmtiEvent::kMinEventTypeVal);
+         i <= static_cast<size_t>(ArtJvmtiEvent::kMaxEventTypeVal);
+         ++i) {
+      RecalculateGlobalEventMask(static_cast<ArtJvmtiEvent>(i));
+    }
+  }
+}
+
 static bool IsThreadControllable(ArtJvmtiEvent event) {
   switch (event) {
     case ArtJvmtiEvent::kVmInit:
diff --git a/runtime/openjdkjvmti/events.h b/runtime/openjdkjvmti/events.h
index 08a8765..8e246de 100644
--- a/runtime/openjdkjvmti/events.h
+++ b/runtime/openjdkjvmti/events.h
@@ -141,6 +141,9 @@
   // enabled, yet.
   void RegisterArtJvmTiEnv(ArtJvmTiEnv* env);
 
+  // Remove an env.
+  void RemoveArtJvmTiEnv(ArtJvmTiEnv* env);
+
   bool IsEventEnabledAnywhere(ArtJvmtiEvent event) const {
     if (!EventMask::EventIsInRange(event)) {
       return false;
diff --git a/runtime/openjdkjvmti/ti_phase.cc b/runtime/openjdkjvmti/ti_phase.cc
index e36b947..85d6b72 100644
--- a/runtime/openjdkjvmti/ti_phase.cc
+++ b/runtime/openjdkjvmti/ti_phase.cc
@@ -33,8 +33,10 @@
 
 #include "art_jvmti.h"
 #include "base/macros.h"
+#include "events-inl.h"
 #include "runtime.h"
 #include "runtime_callbacks.h"
+#include "ScopedLocalRef.h"
 #include "scoped_thread_state_change-inl.h"
 #include "thread-inl.h"
 #include "thread_list.h"
@@ -44,6 +46,15 @@
 jvmtiPhase PhaseUtil::current_phase_ = static_cast<jvmtiPhase>(0);
 
 struct PhaseUtil::PhaseCallback : public art::RuntimePhaseCallback {
+  inline static JNIEnv* GetJniEnv() {
+    return reinterpret_cast<JNIEnv*>(art::Thread::Current()->GetJniEnv());
+  }
+
+  inline static jthread GetCurrentJThread() {
+    art::ScopedObjectAccess soa(art::Thread::Current());
+    return soa.AddLocalReference<jthread>(soa.Self()->GetPeer());
+  }
+
   void NextRuntimePhase(RuntimePhase phase) OVERRIDE {
     // TODO: Events.
     switch (phase) {
@@ -51,16 +62,28 @@
         PhaseUtil::current_phase_ = JVMTI_PHASE_PRIMORDIAL;
         break;
       case RuntimePhase::kStart:
+        event_handler->DispatchEvent(nullptr, ArtJvmtiEvent::kVmStart, GetJniEnv());
         PhaseUtil::current_phase_ = JVMTI_PHASE_START;
         break;
       case RuntimePhase::kInit:
-        PhaseUtil::current_phase_ = JVMTI_PHASE_LIVE;
+        {
+          ScopedLocalRef<jthread> thread(GetJniEnv(), GetCurrentJThread());
+          event_handler->DispatchEvent(nullptr,
+                                       ArtJvmtiEvent::kVmInit,
+                                       GetJniEnv(),
+                                       thread.get());
+          PhaseUtil::current_phase_ = JVMTI_PHASE_LIVE;
+        }
         break;
       case RuntimePhase::kDeath:
+        event_handler->DispatchEvent(nullptr, ArtJvmtiEvent::kVmDeath, GetJniEnv());
         PhaseUtil::current_phase_ = JVMTI_PHASE_DEAD;
+        // TODO: Block events now.
         break;
     }
   }
+
+  EventHandler* event_handler = nullptr;
 };
 
 PhaseUtil::PhaseCallback gPhaseCallback;
@@ -94,7 +117,8 @@
   PhaseUtil::current_phase_ = JVMTI_PHASE_LIVE;
 }
 
-void PhaseUtil::Register() {
+void PhaseUtil::Register(EventHandler* handler) {
+  gPhaseCallback.event_handler = handler;
   art::ScopedThreadStateChange stsc(art::Thread::Current(),
                                     art::ThreadState::kWaitingForDebuggerToAttach);
   art::ScopedSuspendAll ssa("Add phase callback");
diff --git a/runtime/openjdkjvmti/ti_phase.h b/runtime/openjdkjvmti/ti_phase.h
index 3cbda5f..054652a 100644
--- a/runtime/openjdkjvmti/ti_phase.h
+++ b/runtime/openjdkjvmti/ti_phase.h
@@ -37,11 +37,13 @@
 
 namespace openjdkjvmti {
 
+class EventHandler;
+
 class PhaseUtil {
  public:
   static jvmtiError GetPhase(jvmtiEnv* env, jvmtiPhase* phase_ptr);
 
-  static void Register();
+  static void Register(EventHandler* event_handler);
 
   // Move the phase from unitialized to LOAD.
   static void SetToOnLoad();