Revert "Revert "ART: Ensure plugin is loaded on AttachAgent""

Agents require the JVMTI plugin. Ensure that it is loaded when
trying to satisfy an AttachAgent request. Amend test 909.

This reverts commit 98cf7cf8766770dba2718a6131345cc7f57c5bc7.
Blacklist debuggable test configurations for negative test.

Bug: 31682382
Test: m test-art-host-run-test-909-attach-agent
Change-Id: I7720a18689bd6ddee38292dd42faf190fc06d14d
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 2086d70..df5fc5c 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -1364,6 +1364,39 @@
   return true;
 }
 
+static bool EnsureJvmtiPlugin(Runtime* runtime,
+                              std::vector<Plugin>* plugins,
+                              std::string* error_msg) {
+  constexpr const char* plugin_name = kIsDebugBuild ? "libopenjdkjvmtid.so" : "libopenjdkjvmti.so";
+
+  // Is the plugin already loaded?
+  for (Plugin p : *plugins) {
+    if (p.GetLibrary() == plugin_name) {
+      return true;
+    }
+  }
+
+  // Is the process debuggable? Otherwise, do not attempt to load the plugin.
+  if (!runtime->IsDebuggable()) {
+    *error_msg = "Process is not debuggable.";
+    return false;
+  }
+
+  Plugin new_plugin = Plugin::Create(plugin_name);
+
+  // Suspend all threads to protect ourself somewhat.
+  Thread* self = Thread::Current();
+  ScopedObjectAccess soa(self);      // Now we know we have the shared lock.
+  ScopedThreadSuspension sts(self, art::kWaitingForDebuggerToAttach);
+  ScopedSuspendAll ssa("EnsureJvmtiPlugin");
+  if (!new_plugin.Load(error_msg)) {
+    return false;
+  }
+
+  plugins->push_back(std::move(new_plugin));
+  return true;
+}
+
 // Attach a new agent and add it to the list of runtime agents
 //
 // TODO: once we decide on the threading model for agents,
@@ -1371,18 +1404,25 @@
 //   (and we synchronize access to any shared data structures like "agents_")
 //
 void Runtime::AttachAgent(const std::string& agent_arg) {
+  std::string error_msg;
+  if (!EnsureJvmtiPlugin(this, &plugins_, &error_msg)) {
+    LOG(WARNING) << "Could not load plugin: " << error_msg;
+    ScopedObjectAccess soa(Thread::Current());
+    ThrowIOException("%s", error_msg.c_str());
+    return;
+  }
+
   ti::Agent agent(agent_arg);
 
   int res = 0;
-  std::string err;
-  ti::Agent::LoadError result = agent.Attach(&res, &err);
+  ti::Agent::LoadError result = agent.Attach(&res, &error_msg);
 
   if (result == ti::Agent::kNoError) {
     agents_.push_back(std::move(agent));
   } else {
-    LOG(ERROR) << "Agent attach failed (result=" << result << ") : " << err;
+    LOG(WARNING) << "Agent attach failed (result=" << result << ") : " << error_msg;
     ScopedObjectAccess soa(Thread::Current());
-    ThrowWrappedIOException("%s", err.c_str());
+    ThrowIOException("%s", error_msg.c_str());
   }
 }