ART: Add JNI API

Add support for GetJNIFunctionTable and SetJNIFunctionTable. Add
tests.

Bug: 34343708
Test: m test-art-host-run-test-928-jni-table
Change-Id: Ib9fafbac2781c570aa6eacf5242afbbf6c3ee7a9
diff --git a/test/928-jni-table/build b/test/928-jni-table/build
new file mode 100755
index 0000000..898e2e5
--- /dev/null
+++ b/test/928-jni-table/build
@@ -0,0 +1,17 @@
+#!/bin/bash
+#
+# Copyright 2016 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.
+
+./default-build "$@" --experimental agents
diff --git a/test/928-jni-table/expected.txt b/test/928-jni-table/expected.txt
new file mode 100644
index 0000000..a965a70
--- /dev/null
+++ b/test/928-jni-table/expected.txt
@@ -0,0 +1 @@
+Done
diff --git a/test/928-jni-table/info.txt b/test/928-jni-table/info.txt
new file mode 100644
index 0000000..875a5f6
--- /dev/null
+++ b/test/928-jni-table/info.txt
@@ -0,0 +1 @@
+Tests basic functions in the jvmti plugin.
diff --git a/test/928-jni-table/jni_table.cc b/test/928-jni-table/jni_table.cc
new file mode 100644
index 0000000..5123d3a
--- /dev/null
+++ b/test/928-jni-table/jni_table.cc
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2013 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 <stdio.h>
+
+#include "jni.h"
+#include "openjdkjvmti/jvmti.h"
+
+#include "base/logging.h"
+#include "base/macros.h"
+
+#include "ti-agent/common_helper.h"
+#include "ti-agent/common_load.h"
+
+namespace art {
+namespace Test927JNITable {
+
+// This test is equivalent to the jni_internal_test JNIEnvExtTableOverride.
+
+static size_t gGlobalRefCount = 0;
+static JNINativeInterface* gOriginalEnv = nullptr;
+
+static jobject CountNewGlobalRef(JNIEnv* env, jobject o) {
+  ++gGlobalRefCount;
+  return gOriginalEnv->NewGlobalRef(env, o);
+}
+
+extern "C" JNIEXPORT void JNICALL Java_Main_doJNITableTest(
+    JNIEnv* env, jclass klass) {
+  // Get the current table, as the delegate.
+  jvmtiError getorig_result = jvmti_env->GetJNIFunctionTable(&gOriginalEnv);
+  if (JvmtiErrorToException(env, getorig_result)) {
+    return;
+  }
+
+  // Get the current table, as the override we'll install.
+  JNINativeInterface* env_override;
+  jvmtiError getoverride_result = jvmti_env->GetJNIFunctionTable(&env_override);
+  if (JvmtiErrorToException(env, getoverride_result)) {
+    return;
+  }
+
+  env_override->NewGlobalRef = CountNewGlobalRef;
+  gGlobalRefCount = 0;
+
+  // Install the override.
+  jvmtiError setoverride_result = jvmti_env->SetJNIFunctionTable(env_override);
+  if (JvmtiErrorToException(env, setoverride_result)) {
+    return;
+  }
+
+  jobject global = env->NewGlobalRef(klass);
+  CHECK_EQ(1u, gGlobalRefCount);
+  env->DeleteGlobalRef(global);
+
+  // Install the "original." There is no real reset.
+  jvmtiError setoverride2_result = jvmti_env->SetJNIFunctionTable(gOriginalEnv);
+  if (JvmtiErrorToException(env, setoverride2_result)) {
+    return;
+  }
+
+  jobject global2 = env->NewGlobalRef(klass);
+  CHECK_EQ(1u, gGlobalRefCount);
+  env->DeleteGlobalRef(global2);
+
+  // Try to install null. Should return NULL_POINTER error.
+  jvmtiError setoverride3_result = jvmti_env->SetJNIFunctionTable(nullptr);
+  if (setoverride3_result != JVMTI_ERROR_NULL_POINTER) {
+    LOG(FATAL) << "Didn't receive NULL_POINTER";
+  }
+
+  jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(env_override));
+}
+
+}  // namespace Test927JNITable
+}  // namespace art
diff --git a/test/928-jni-table/run b/test/928-jni-table/run
new file mode 100755
index 0000000..4379349
--- /dev/null
+++ b/test/928-jni-table/run
@@ -0,0 +1,19 @@
+#!/bin/bash
+#
+# Copyright 2016 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.
+
+./default-run "$@" --experimental agents \
+                   --experimental runtime-plugins \
+                   --jvmti
diff --git a/test/928-jni-table/src/Main.java b/test/928-jni-table/src/Main.java
new file mode 100644
index 0000000..b0baea1
--- /dev/null
+++ b/test/928-jni-table/src/Main.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+public class Main {
+  public static void main(String[] args) throws Exception {
+    System.loadLibrary(args[1]);
+
+    doJNITableTest();
+
+    System.out.println("Done");
+  }
+
+  public static native void doJNITableTest();
+}
diff --git a/test/Android.bp b/test/Android.bp
index a1b283d..965d07a 100644
--- a/test/Android.bp
+++ b/test/Android.bp
@@ -267,6 +267,7 @@
         "924-threads/threads.cc",
         "925-threadgroups/threadgroups.cc",
         "927-timers/timers.cc",
+        "928-jni-table/jni_table.cc",
         "929-search/search.cc",
     ],
     shared_libs: [
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index 668d669..b1a0c91 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -306,6 +306,7 @@
   925-threadgroups \
   926-multi-obsolescence \
   927-timers \
+  928-jni-table \
   929-search \
 
 ifneq (,$(filter target,$(TARGET_TYPES)))