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());
   }
 }
 
diff --git a/test/909-attach-agent/expected.txt b/test/909-attach-agent/expected.txt
index eacc595..c0bccd6 100644
--- a/test/909-attach-agent/expected.txt
+++ b/test/909-attach-agent/expected.txt
@@ -1,3 +1,11 @@
 Hello, world!
 Attached Agent for test 909-attach-agent
 Goodbye!
+Hello, world!
+Attached Agent for test 909-attach-agent
+Goodbye!
+Hello, world!
+java.io.IOException: Process is not debuggable.
+	at dalvik.system.VMDebug.attachAgent(Native Method)
+	at Main.main(Main.java:27)
+Goodbye!
diff --git a/test/909-attach-agent/run b/test/909-attach-agent/run
index aed6e83..985341b 100755
--- a/test/909-attach-agent/run
+++ b/test/909-attach-agent/run
@@ -24,4 +24,14 @@
 ./default-run "$@" --experimental agents \
                    --experimental runtime-plugins \
                    --android-runtime-option -Xplugin:${plugin} \
+                   --android-runtime-option -Xfully-deoptable \
+                   --args agent:${agent}=909-attach-agent
+
+./default-run "$@" --experimental agents \
+                   --experimental runtime-plugins \
+                   --android-runtime-option -Xfully-deoptable \
+                   --args agent:${agent}=909-attach-agent
+
+./default-run "$@" --experimental agents \
+                   --experimental runtime-plugins \
                    --args agent:${agent}=909-attach-agent
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index fd3a897..deb0e6f 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -721,6 +721,16 @@
 
 TEST_ART_BROKEN_OPTIMIZING_HEAP_POISONING_RUN_TESTS :=
 
+# Tests that check semantics for a non-debuggable app.
+TEST_ART_BROKEN_DEBUGGABLE_RUN_TESTS := \
+  909-attach-agent \
+
+ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),$(PREBUILD_TYPES), \
+    $(COMPILER_TYPES),$(RELOCATE_TYPES),$(TRACE_TYPES),$(GC_TYPES),$(JNI_TYPES), \
+    $(IMAGE_TYPES),$(PICTEST_TYPES),debuggable,$(TEST_ART_BROKEN_DEBUGGABLE_RUN_TESTS),$(ALL_ADDRESS_SIZES))
+
+TEST_ART_BROKEN_DEBUGGABLE_RUN_TESTS :=
+
 # Tests incompatible with bisection bug search. Sorted by incompatibility reason.
 # 000 through 595 do not compile anything. 089 tests a build failure. 018 through 137
 # run dalvikvm more than once. 115 and 088 assume they are always compiled.