Always allow agent attach on userdebug builds with kArtTiVersion

We added support for the jvmti-alike ArtTi for use by debuggers on
userdebug/eng builds of android. Extend this support to allow any
agent to be loaded on any process of a userdebug device. These agents
will need to make use of kArtTiVersion (0x70010200) envs.

Test: build
Test: ./test.py --host -j50
Test: ensure AS profiler continues to work with userdebug devices
Bug: 78195998
Change-Id: I984d1ea937eb49afb376a48bea3d67085192020e
diff --git a/adbconnection/adbconnection.cc b/adbconnection/adbconnection.cc
index ee89717..3c5f735 100644
--- a/adbconnection/adbconnection.cc
+++ b/adbconnection/adbconnection.cc
@@ -837,8 +837,7 @@
   self->AssertNoPendingException();
   runtime->AttachAgent(/* JNIEnv */ nullptr,
                        MakeAgentArg(),
-                       /* classloader */ nullptr,
-                       /*allow_non_debuggable_tooling*/ true);
+                       /* classloader */ nullptr);
   if (self->IsExceptionPending()) {
     LOG(ERROR) << "Failed to load agent " << agent_name_;
     art::ScopedObjectAccess soa(self);
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index c394fef..8f5295c 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -1619,7 +1619,6 @@
 }
 
 static bool EnsureJvmtiPlugin(Runtime* runtime,
-                              bool allow_non_debuggable_tooling,
                               std::vector<Plugin>* plugins,
                               std::string* error_msg) {
   constexpr const char* plugin_name = kIsDebugBuild ? "libopenjdkjvmtid.so" : "libopenjdkjvmti.so";
@@ -1631,10 +1630,13 @@
     }
   }
 
+  // TODO Rename Dbg::IsJdwpAllowed is IsDebuggingAllowed.
+  DCHECK(Dbg::IsJdwpAllowed() || !runtime->IsJavaDebuggable())
+      << "Being debuggable requires that jdwp (i.e. debugging) is allowed.";
   // Is the process debuggable? Otherwise, do not attempt to load the plugin unless we are
   // specifically allowed.
-  if (!allow_non_debuggable_tooling && !runtime->IsJavaDebuggable()) {
-    *error_msg = "Process is not debuggable.";
+  if (!Dbg::IsJdwpAllowed()) {
+    *error_msg = "Process is not allowed to load openjdkjvmti plugin. Process must be debuggable";
     return false;
   }
 
@@ -1654,12 +1656,9 @@
 //   revisit this and make sure we're doing this on the right thread
 //   (and we synchronize access to any shared data structures like "agents_")
 //
-void Runtime::AttachAgent(JNIEnv* env,
-                          const std::string& agent_arg,
-                          jobject class_loader,
-                          bool allow_non_debuggable_tooling) {
+void Runtime::AttachAgent(JNIEnv* env, const std::string& agent_arg, jobject class_loader) {
   std::string error_msg;
-  if (!EnsureJvmtiPlugin(this, allow_non_debuggable_tooling, &plugins_, &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());
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 3d4b596..1b7663c 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -710,10 +710,7 @@
   void AddSystemWeakHolder(gc::AbstractSystemWeakHolder* holder);
   void RemoveSystemWeakHolder(gc::AbstractSystemWeakHolder* holder);
 
-  void AttachAgent(JNIEnv* env,
-                   const std::string& agent_arg,
-                   jobject class_loader,
-                   bool allow_non_debuggable_tooling = false);
+  void AttachAgent(JNIEnv* env, const std::string& agent_arg, jobject class_loader);
 
   const std::list<std::unique_ptr<ti::Agent>>& GetAgents() const {
     return agents_;
diff --git a/test/909-attach-agent/attach.cc b/test/909-attach-agent/attach.cc
index 3a6788a..50ab26a 100644
--- a/test/909-attach-agent/attach.cc
+++ b/test/909-attach-agent/attach.cc
@@ -32,6 +32,8 @@
   fflush(stdout);
 }
 
+static constexpr jint kArtTiVersion = JVMTI_VERSION_1_2 | 0x40000000;
+
 jint OnAttach(JavaVM* vm,
             char* options ATTRIBUTE_UNUSED,
             void* reserved ATTRIBUTE_UNUSED) {
@@ -47,7 +49,18 @@
     } \
   } while (false)
 
-  CHECK_CALL_SUCCESS(vm->GetEnv(reinterpret_cast<void**>(&env), JVMTI_VERSION_1_0));
+  if (vm->GetEnv(reinterpret_cast<void**>(&env), kArtTiVersion) == JNI_OK) {
+    Println("Created env for kArtTiVersion");
+    CHECK_CALL_SUCCESS(env->DisposeEnvironment());
+    env = nullptr;
+  } else {
+    Println("Failed to create env for kArtTiVersion");
+    return -1;
+  }
+  if (vm->GetEnv(reinterpret_cast<void**>(&env), JVMTI_VERSION_1_0) != JNI_OK) {
+    Println("Unable to create env for JVMTI_VERSION_1_0");
+    return 0;
+  }
   CHECK_CALL_SUCCESS(vm->GetEnv(reinterpret_cast<void**>(&env2), JVMTI_VERSION_1_0));
   if (env == env2) {
     Println("GetEnv returned same environment twice!");
diff --git a/test/909-attach-agent/disallow_debugging.cc b/test/909-attach-agent/disallow_debugging.cc
new file mode 100644
index 0000000..4c70f62
--- /dev/null
+++ b/test/909-attach-agent/disallow_debugging.cc
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "debugger.h"
+
+namespace art {
+namespace Test909AttachAgent {
+
+extern "C" JNIEXPORT void JNICALL Java_Main_setDebuggingAllowed(JNIEnv*, jclass, jboolean val) {
+  Dbg::SetJdwpAllowed(val);
+}
+
+}  // namespace Test909AttachAgent
+}  // namespace art
diff --git a/test/909-attach-agent/expected.txt b/test/909-attach-agent/expected.txt
index 4d687f5..eec767d 100644
--- a/test/909-attach-agent/expected.txt
+++ b/test/909-attach-agent/expected.txt
@@ -1,12 +1,28 @@
+JNI_OnLoad called
 Hello, world!
 Attached Agent for test 909-attach-agent
+Created env for kArtTiVersion
 Attached Agent for test 909-attach-agent
+Created env for kArtTiVersion
 Goodbye!
+JNI_OnLoad called
 Hello, world!
 Attached Agent for test 909-attach-agent
+Created env for kArtTiVersion
 Attached Agent for test 909-attach-agent
+Created env for kArtTiVersion
 Goodbye!
+JNI_OnLoad called
 Hello, world!
-Process is not debuggable.
-Process is not debuggable.
+Attached Agent for test 909-attach-agent
+Created env for kArtTiVersion
+version 0x30010000 is not valid!Unable to create env for JVMTI_VERSION_1_0
+Attached Agent for test 909-attach-agent
+Created env for kArtTiVersion
+version 0x30010000 is not valid!Unable to create env for JVMTI_VERSION_1_0
+Goodbye!
+JNI_OnLoad called
+Hello, world!
+Can't attach agent, process is not debuggable.
+Can't attach agent, process is not debuggable.
 Goodbye!
diff --git a/test/909-attach-agent/interpreter-expected.patch b/test/909-attach-agent/interpreter-expected.patch
new file mode 100644
index 0000000..5035c6a
--- /dev/null
+++ b/test/909-attach-agent/interpreter-expected.patch
@@ -0,0 +1,4 @@
+19d18
+< version 0x30010000 is not valid!Unable to create env for JVMTI_VERSION_1_0
+22d20
+< version 0x30010000 is not valid!Unable to create env for JVMTI_VERSION_1_0
diff --git a/test/909-attach-agent/run b/test/909-attach-agent/run
index a556bba..fd45abd 100755
--- a/test/909-attach-agent/run
+++ b/test/909-attach-agent/run
@@ -21,6 +21,14 @@
   plugin=libopenjdkjvmti.so
 fi
 
+if [[ "$@" == *"--interpreter"* ]]; then
+  # On interpreter we are fully capable of providing the full jvmti api so we
+  # have a slightly different expected output.
+  # TODO We should really be changing this in the 'check' script.
+  patch -s expected.txt <interpreter-expected.patch
+fi
+
+export ANDROID_LOG_TAGS='*:f'
 ./default-run "$@" --android-runtime-option -Xplugin:${plugin} \
                    --android-runtime-option -Xcompiler-option \
                    --android-runtime-option --debuggable \
@@ -32,8 +40,16 @@
                    --args agent:${agent}=909-attach-agent
 return_status2=$?
 
-./default-run "$@" --args agent:${agent}=909-attach-agent
+./default-run "$@" --args agent:${agent}=909-attach-agent --external-log-tags
 return_status3=$?
 
+./default-run "$@" --args agent:${agent}=909-attach-agent \
+                   --args disallow-debugging \
+                   --external-log-tags
+return_status4=$?
+
 # Make sure we don't silently ignore an early failure.
-(exit $return_status1) && (exit $return_status2) && (exit $return_status3)
+(exit $return_status1) && \
+  (exit $return_status2) && \
+  (exit $return_status3) && \
+  (exit $return_status4)
diff --git a/test/909-attach-agent/src-art/Main.java b/test/909-attach-agent/src-art/Main.java
index 705e61e..6359f7e6 100644
--- a/test/909-attach-agent/src-art/Main.java
+++ b/test/909-attach-agent/src-art/Main.java
@@ -24,23 +24,36 @@
 import java.io.IOException;
 
 public class Main {
-  public static void main(String[] args) {
+  public static void main(String[] args) throws Exception {
+    System.loadLibrary(args[0]);
     System.out.println("Hello, world!");
+    String agent = null;
+    // By default allow debugging
+    boolean debugging_allowed = true;
     for(String a : args) {
       if(a.startsWith("agent:")) {
-        String agent = a.substring(6);
-        try {
-          VMDebug.attachAgent(agent);
-        } catch(IOException e) {
-          System.out.println(e.getMessage());
-        }
+        agent = a.substring(6);
+      } else if (a.equals("disallow-debugging")) {
+        debugging_allowed = false;
       }
     }
+    if (agent == null) {
+      throw new Error("Could not find agent: argument!");
+    }
+    setDebuggingAllowed(debugging_allowed);
+    // Setup is finished. Try to attach agent in 2 ways.
+    try {
+      VMDebug.attachAgent(agent);
+    } catch(SecurityException e) {
+      System.out.println(e.getMessage());
+    }
     attachWithClassLoader(args);
     System.out.println("Goodbye!");
   }
 
-  private static void attachWithClassLoader(String[] args) {
+  private static native void setDebuggingAllowed(boolean val);
+
+  private static void attachWithClassLoader(String[] args) throws Exception {
     for(String a : args) {
       if(a.startsWith("agent:")) {
         String agentName = a.substring(6, a.indexOf('='));
@@ -56,7 +69,7 @@
               Main.class.getClassLoader());
           try {
             VMDebug.attachAgent(agent, cl);
-          } catch(IOException e) {
+          } catch(SecurityException e) {
             System.out.println(e.getMessage());
           }
         } catch (Exception e) {
diff --git a/test/Android.bp b/test/Android.bp
index bd13de2..b9312c8 100644
--- a/test/Android.bp
+++ b/test/Android.bp
@@ -440,6 +440,7 @@
         "667-jit-jni-stub/jit_jni_stub_test.cc",
         "674-hiddenapi/hiddenapi.cc",
         "708-jit-cache-churn/jit.cc",
+        "909-attach-agent/disallow_debugging.cc",
         "1947-breakpoint-redefine-deopt/check_deopt.cc",
         "common/runtime_state.cc",
         "common/stack_inspect.cc",