CTS: Use ART's libctstiagent
Use helper functions from ART's test code.
Bug: 32072923
Test: m cts
Test: cts-tradefed run cts-dev --module CtsJvmtiTrackingHostTestCases
Test: cts-tradefed run cts-dev --module CtsJvmtiTaggingHostTestCases
Test: cts-tradefed run cts-dev --module CtsJvmtiRedefineClassesHostTestCases
Change-Id: I961242ebd27a45506aa6eb1db937ea21a06dc113
diff --git a/hostsidetests/jvmti/allocation-tracking/app/src/android/jvmti/cts/JvmtiTrackingTest.java b/hostsidetests/jvmti/allocation-tracking/app/src/android/jvmti/cts/JvmtiTrackingTest.java
index 70434d1..7a13e79 100644
--- a/hostsidetests/jvmti/allocation-tracking/app/src/android/jvmti/cts/JvmtiTrackingTest.java
+++ b/hostsidetests/jvmti/allocation-tracking/app/src/android/jvmti/cts/JvmtiTrackingTest.java
@@ -19,6 +19,8 @@
import org.junit.Before;
import org.junit.Test;
+import art.Main;
+
/**
* Check tagging-related functionality.
*/
@@ -27,7 +29,7 @@
@Before
public void setUp() throws Exception {
// Bind our native methods.
- JniBindings.bindAgentJNI("android/jvmti/cts/JvmtiTrackingTest",
+ Main.bindAgentJNI("android/jvmti/cts/JvmtiTrackingTest",
getClass().getClassLoader());
prefetchClassNames();
diff --git a/hostsidetests/jvmti/allocation-tracking/app/src/art/Main.java b/hostsidetests/jvmti/allocation-tracking/app/src/art/Main.java
new file mode 100644
index 0000000..6f569d1
--- /dev/null
+++ b/hostsidetests/jvmti/allocation-tracking/app/src/art/Main.java
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+package art;
+
+/**
+ * This is a definition of generically exposed implementations by the CTS JVMTI agent.
+ */
+public class Main {
+ // Load the given class with the given classloader, and bind all native methods to corresponding
+ // C methods in the agent. Will abort if any of the steps fail.
+ public static native void bindAgentJNI(String className, ClassLoader classLoader);
+ // Same as above, giving the class directly.
+ public static native void bindAgentJNIForClass(Class<?> klass);
+
+ // General functionality shared between tests.
+ public static native void setTag(Object o, long tag);
+
+ public static native long getTag(Object o);
+}
diff --git a/hostsidetests/jvmti/base/app/src/android/jvmti/cts/JvmtiTestBase.java b/hostsidetests/jvmti/base/app/src/android/jvmti/cts/JvmtiTestBase.java
index b0c02cf..0b54a93 100644
--- a/hostsidetests/jvmti/base/app/src/android/jvmti/cts/JvmtiTestBase.java
+++ b/hostsidetests/jvmti/base/app/src/android/jvmti/cts/JvmtiTestBase.java
@@ -15,14 +15,17 @@
*/
package android.jvmti.cts;
-import android.jvmti.JvmtiActivity;
import android.support.test.filters.SmallTest;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
+
import org.junit.Before;
import org.junit.Rule;
import org.junit.runner.RunWith;
+import android.jvmti.JvmtiActivity;
+import art.CtsMain;
+
/**
* Base class for JVMTI tests. Ensures that the agent is connected for the tests. If you
* do not subclass this test, make sure that JniBindings.waitFor is appropriately called.
@@ -45,6 +48,6 @@
mActivity = mActivityRule.getActivity();
// Make sure that the agent is ready.
- JniBindings.waitFor();
+ CtsMain.waitFor();
}
}
diff --git a/hostsidetests/jvmti/base/app/src/android/jvmti/cts/JniBindings.java b/hostsidetests/jvmti/base/app/src/art/CtsMain.java
similarity index 70%
rename from hostsidetests/jvmti/base/app/src/android/jvmti/cts/JniBindings.java
rename to hostsidetests/jvmti/base/app/src/art/CtsMain.java
index cc473d2..4970c07 100644
--- a/hostsidetests/jvmti/base/app/src/android/jvmti/cts/JniBindings.java
+++ b/hostsidetests/jvmti/base/app/src/art/CtsMain.java
@@ -12,15 +12,15 @@
* the License.
*/
-package android.jvmti.cts;
+package art;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
/**
- * A class that contains all bindings to JNI implementations provided by the CTS JVMTI agent.
+ * An entrypoint for the CTS JVMTI agent to signal to the Java side that it has attached.
*/
-public class JniBindings {
+public class CtsMain {
private static CountDownLatch sStartWaiter = new CountDownLatch(1);
@@ -42,13 +42,4 @@
throw new RuntimeException("Got interrupted waiting for agent.");
}
}
-
- // Load the given class with the given classloader, and bind all native methods to corresponding
- // C methods in the agent. Will abort if any of the steps fail.
- public static native void bindAgentJNI(String className, ClassLoader classLoader);
-
- // General functionality shared between tests.
- public static native void setTag(Object o, long tag);
-
- public static native long getTag(Object o);
}
diff --git a/hostsidetests/jvmti/base/jni/Android.mk b/hostsidetests/jvmti/base/jni/Android.mk
index ff65af6..28b7ea3 100644
--- a/hostsidetests/jvmti/base/jni/Android.mk
+++ b/hostsidetests/jvmti/base/jni/Android.mk
@@ -21,9 +21,7 @@
# Don't include this package in any configuration by default.
LOCAL_MODULE_TAGS := optional
-LOCAL_SRC_FILES := cts_agent.cpp \
- jni_binder.cpp \
- jvmti_helper.cpp \
+LOCAL_SRC_FILES := cts_agent.cpp
# Tagging.
LOCAL_SRC_FILES += tagging.cpp
@@ -40,8 +38,12 @@
LOCAL_SHARED_LIBRARIES := liblog \
libdl
+# The test implementation. We get this provided by ART.
+# Note: Needs to be "whole" as this exposes JNI functions.
+LOCAL_WHOLE_STATIC_LIBRARIES := libctstiagent
+
# Platform libraries that are not available to apps. Link in statically.
-LOCAL_STATIC_LIBRARIES := libbase
+LOCAL_STATIC_LIBRARIES += libbase
LOCAL_STRIP_MODULE := keep_symbols
diff --git a/hostsidetests/jvmti/base/jni/common.h b/hostsidetests/jvmti/base/jni/common.h
deleted file mode 100644
index ded4fc5..0000000
--- a/hostsidetests/jvmti/base/jni/common.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef COMMON_H_
-#define COMMON_H_
-
-#include "jni.h"
-#include "jvmti.h"
-
-namespace cts {
-namespace jvmti {
-
-jvmtiEnv* GetJvmtiEnv();
-
-int JniThrowNullPointerException(JNIEnv* env, const char* msg);
-
-} // namespace jvmti
-} // namespace cts
-
-
-#endif // COMMON_H_
diff --git a/hostsidetests/jvmti/base/jni/cts_agent.cpp b/hostsidetests/jvmti/base/jni/cts_agent.cpp
index 817842c3..6afae53 100644
--- a/hostsidetests/jvmti/base/jni/cts_agent.cpp
+++ b/hostsidetests/jvmti/base/jni/cts_agent.cpp
@@ -17,41 +17,40 @@
#include <jni.h>
#include <jvmti.h>
+#include "agent_startup.h"
#include "android-base/logging.h"
-#include "common.h"
#include "jni_binder.h"
#include "jvmti_helper.h"
+#include "scoped_local_ref.h"
+#include "test_env.h"
-namespace cts {
-namespace jvmti {
+namespace art {
-static jvmtiEnv* jvmti_env;
+static void InformMainAttach(jvmtiEnv* jenv,
+ JNIEnv* env,
+ const char* class_name,
+ const char* method_name) {
+ // Use JNI to load the class.
+ ScopedLocalRef<jclass> klass(env, FindClass(jenv, env, class_name, nullptr));
+ CHECK(klass.get() != nullptr) << class_name;
-jvmtiEnv* GetJvmtiEnv() {
- return jvmti_env;
+ jmethodID method = env->GetStaticMethodID(klass.get(), method_name, "()V");
+ CHECK(method != nullptr);
+
+ env->CallStaticVoidMethod(klass.get(), method);
}
-int JniThrowNullPointerException(JNIEnv* env, const char* msg) {
- if (env->ExceptionCheck()) {
- env->ExceptionClear();
- }
+static constexpr const char* kMainClass = "art/CtsMain";
+static constexpr const char* kMainClassStartup = "startup";
- jclass exc_class = env->FindClass("java/lang/NullPointerException");
- if (exc_class == nullptr) {
- return -1;
- }
-
- bool ok = env->ThrowNew(exc_class, msg) == JNI_OK;
-
- env->DeleteLocalRef(exc_class);
-
- return ok ? 0 : -1;
+static void CtsStartCallback(jvmtiEnv* jenv, JNIEnv* env) {
+ InformMainAttach(jenv, env, kMainClass, kMainClassStartup);
}
extern "C" JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM* vm,
char* options ATTRIBUTE_UNUSED,
void* reserved ATTRIBUTE_UNUSED) {
- BindOnLoad(vm);
+ BindOnLoad(vm, nullptr);
if (vm->GetEnv(reinterpret_cast<void**>(&jvmti_env), JVMTI_VERSION_1_0) != 0) {
LOG(FATAL) << "Could not get shared jvmtiEnv";
@@ -64,7 +63,7 @@
extern "C" JNIEXPORT jint JNICALL Agent_OnAttach(JavaVM* vm,
char* options ATTRIBUTE_UNUSED,
void* reserved ATTRIBUTE_UNUSED) {
- BindOnAttach(vm);
+ BindOnAttach(vm, CtsStartCallback);
if (vm->GetEnv(reinterpret_cast<void**>(&jvmti_env), JVMTI_VERSION_1_0) != 0) {
LOG(FATAL) << "Could not get shared jvmtiEnv";
@@ -74,5 +73,4 @@
return 0;
}
-}
-}
+} // namespace art
diff --git a/hostsidetests/jvmti/base/jni/jni_binder.cpp b/hostsidetests/jvmti/base/jni/jni_binder.cpp
deleted file mode 100644
index 14658a1..0000000
--- a/hostsidetests/jvmti/base/jni/jni_binder.cpp
+++ /dev/null
@@ -1,431 +0,0 @@
-/*
- * 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.
- */
-
-#include "jni_binder.h"
-
-#include <dlfcn.h>
-#include <inttypes.h>
-#include <stdio.h>
-
-#include "android-base/logging.h"
-#include "android-base/stringprintf.h"
-#include "common.h"
-#include "jvmti_helper.h"
-#include "scoped_local_ref.h"
-#include "scoped_utf_chars.h"
-
-namespace cts {
-namespace jvmti {
-
-static constexpr const char* kMainClass = "android/jvmti/cts/JniBindings";
-static constexpr const char* kMainClassStartup = "startup";
-
-size_t CountModifiedUtf8Chars(const char* utf8, size_t byte_count) {
- DCHECK_LE(byte_count, strlen(utf8));
- size_t len = 0;
- const char* end = utf8 + byte_count;
- for (; utf8 < end; ++utf8) {
- int ic = *utf8;
- len++;
- if (LIKELY((ic & 0x80) == 0)) {
- // One-byte encoding.
- continue;
- }
- // Two- or three-byte encoding.
- utf8++;
- if ((ic & 0x20) == 0) {
- // Two-byte encoding.
- continue;
- }
- utf8++;
- if ((ic & 0x10) == 0) {
- // Three-byte encoding.
- continue;
- }
-
- // Four-byte encoding: needs to be converted into a surrogate
- // pair.
- utf8++;
- len++;
- }
- return len;
-}
-
-static uint16_t GetTrailingUtf16Char(uint32_t maybe_pair) {
- return static_cast<uint16_t>(maybe_pair >> 16);
-}
-
-static uint16_t GetLeadingUtf16Char(uint32_t maybe_pair) {
- return static_cast<uint16_t>(maybe_pair & 0x0000FFFF);
-}
-
-static uint32_t GetUtf16FromUtf8(const char** utf8_data_in) {
- const uint8_t one = *(*utf8_data_in)++;
- if ((one & 0x80) == 0) {
- // one-byte encoding
- return one;
- }
-
- const uint8_t two = *(*utf8_data_in)++;
- if ((one & 0x20) == 0) {
- // two-byte encoding
- return ((one & 0x1f) << 6) | (two & 0x3f);
- }
-
- const uint8_t three = *(*utf8_data_in)++;
- if ((one & 0x10) == 0) {
- return ((one & 0x0f) << 12) | ((two & 0x3f) << 6) | (three & 0x3f);
- }
-
- // Four byte encodings need special handling. We'll have
- // to convert them into a surrogate pair.
- const uint8_t four = *(*utf8_data_in)++;
-
- // Since this is a 4 byte UTF-8 sequence, it will lie between
- // U+10000 and U+1FFFFF.
- //
- // TODO: What do we do about values in (U+10FFFF, U+1FFFFF) ? The
- // spec says they're invalid but nobody appears to check for them.
- const uint32_t code_point = ((one & 0x0f) << 18) | ((two & 0x3f) << 12)
- | ((three & 0x3f) << 6) | (four & 0x3f);
-
- uint32_t surrogate_pair = 0;
- // Step two: Write out the high (leading) surrogate to the bottom 16 bits
- // of the of the 32 bit type.
- surrogate_pair |= ((code_point >> 10) + 0xd7c0) & 0xffff;
- // Step three : Write out the low (trailing) surrogate to the top 16 bits.
- surrogate_pair |= ((code_point & 0x03ff) + 0xdc00) << 16;
-
- return surrogate_pair;
-}
-
-static std::string MangleForJni(const std::string& s) {
- std::string result;
- size_t char_count = CountModifiedUtf8Chars(s.c_str(), s.length());
- const char* cp = &s[0];
- for (size_t i = 0; i < char_count; ++i) {
- uint32_t ch = GetUtf16FromUtf8(&cp);
- if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9')) {
- result.push_back(ch);
- } else if (ch == '.' || ch == '/') {
- result += "_";
- } else if (ch == '_') {
- result += "_1";
- } else if (ch == ';') {
- result += "_2";
- } else if (ch == '[') {
- result += "_3";
- } else {
- const uint16_t leading = GetLeadingUtf16Char(ch);
- const uint32_t trailing = GetTrailingUtf16Char(ch);
-
- android::base::StringAppendF(&result, "_0%04x", leading);
- if (trailing != 0) {
- android::base::StringAppendF(&result, "_0%04x", trailing);
- }
- }
- }
- return result;
-}
-
-static std::string GetJniShortName(const std::string& class_descriptor, const std::string& method) {
- // Remove the leading 'L' and trailing ';'...
- std::string class_name(class_descriptor);
- CHECK_EQ(class_name[0], 'L') << class_name;
- CHECK_EQ(class_name[class_name.size() - 1], ';') << class_name;
- class_name.erase(0, 1);
- class_name.erase(class_name.size() - 1, 1);
-
- std::string short_name;
- short_name += "Java_";
- short_name += MangleForJni(class_name);
- short_name += "_";
- short_name += MangleForJni(method);
- return short_name;
-}
-
-static void BindMethod(jvmtiEnv* jvmti_env,
- JNIEnv* env,
- jclass klass,
- jmethodID method) {
- std::string name;
- std::string signature;
- std::string mangled_names[2];
- {
- char* name_cstr;
- char* sig_cstr;
- jvmtiError name_result = jvmti_env->GetMethodName(method, &name_cstr, &sig_cstr, nullptr);
- CheckJvmtiError(jvmti_env, name_result);
- CHECK(name_cstr != nullptr);
- CHECK(sig_cstr != nullptr);
- name = name_cstr;
- signature = sig_cstr;
-
- char* klass_name;
- jvmtiError klass_result = jvmti_env->GetClassSignature(klass, &klass_name, nullptr);
- CheckJvmtiError(jvmti_env, klass_result);
-
- mangled_names[0] = GetJniShortName(klass_name, name);
- // TODO: Long JNI name.
-
- CheckJvmtiError(jvmti_env, Deallocate(jvmti_env, name_cstr));
- CheckJvmtiError(jvmti_env, Deallocate(jvmti_env, sig_cstr));
- CheckJvmtiError(jvmti_env, Deallocate(jvmti_env, klass_name));
- }
-
- for (const std::string& mangled_name : mangled_names) {
- if (mangled_name.empty()) {
- continue;
- }
- void* sym = dlsym(RTLD_DEFAULT, mangled_name.c_str());
- if (sym == nullptr) {
- continue;
- }
-
- JNINativeMethod native_method;
- native_method.fnPtr = sym;
- native_method.name = name.c_str();
- native_method.signature = signature.c_str();
-
- env->RegisterNatives(klass, &native_method, 1);
-
- return;
- }
-
- LOG(FATAL) << "Could not find " << mangled_names[0];
-}
-
-static std::string DescriptorToDot(const char* descriptor) {
- size_t length = strlen(descriptor);
- if (length > 1) {
- if (descriptor[0] == 'L' && descriptor[length - 1] == ';') {
- // Descriptors have the leading 'L' and trailing ';' stripped.
- std::string result(descriptor + 1, length - 2);
- std::replace(result.begin(), result.end(), '/', '.');
- return result;
- } else {
- // For arrays the 'L' and ';' remain intact.
- std::string result(descriptor);
- std::replace(result.begin(), result.end(), '/', '.');
- return result;
- }
- }
- // Do nothing for non-class/array descriptors.
- return descriptor;
-}
-
-static jobject GetSystemClassLoader(JNIEnv* env) {
- ScopedLocalRef<jclass> cl_klass(env, env->FindClass("java/lang/ClassLoader"));
- CHECK(cl_klass.get() != nullptr);
- jmethodID getsystemclassloader_method = env->GetStaticMethodID(cl_klass.get(),
- "getSystemClassLoader",
- "()Ljava/lang/ClassLoader;");
- CHECK(getsystemclassloader_method != nullptr);
- return env->CallStaticObjectMethod(cl_klass.get(), getsystemclassloader_method);
-}
-
-static jclass FindClassWithClassLoader(JNIEnv* env, const char* class_name, jobject class_loader) {
- // Create a String of the name.
- std::string descriptor = android::base::StringPrintf("L%s;", class_name);
- std::string dot_name = DescriptorToDot(descriptor.c_str());
- ScopedLocalRef<jstring> name_str(env, env->NewStringUTF(dot_name.c_str()));
-
- // Call Class.forName with it.
- ScopedLocalRef<jclass> c_klass(env, env->FindClass("java/lang/Class"));
- CHECK(c_klass.get() != nullptr);
- jmethodID forname_method = env->GetStaticMethodID(
- c_klass.get(),
- "forName",
- "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;");
- CHECK(forname_method != nullptr);
-
- return static_cast<jclass>(env->CallStaticObjectMethod(c_klass.get(),
- forname_method,
- name_str.get(),
- JNI_FALSE,
- class_loader));
-}
-
-// Find the given classname. First try the implied classloader, then the system classloader,
-// then use JVMTI to find all classloaders.
-static jclass FindClass(jvmtiEnv* jvmti_env,
- JNIEnv* env,
- const char* class_name,
- jobject class_loader) {
- if (class_loader != nullptr) {
- return FindClassWithClassLoader(env, class_name, class_loader);
- }
-
- jclass from_implied = env->FindClass(class_name);
- if (from_implied != nullptr) {
- return from_implied;
- }
- env->ExceptionClear();
-
- ScopedLocalRef<jobject> system_class_loader(env, GetSystemClassLoader(env));
- CHECK(system_class_loader.get() != nullptr);
- jclass from_system = FindClassWithClassLoader(env, class_name, system_class_loader.get());
- if (from_system != nullptr) {
- return from_system;
- }
- env->ExceptionClear();
-
- // Look at the context classloaders of all threads.
- jint thread_count;
- jthread* threads;
- CheckJvmtiError(jvmti_env, jvmti_env->GetAllThreads(&thread_count, &threads));
- JvmtiUniquePtr threads_uptr = MakeJvmtiUniquePtr(jvmti_env, threads);
-
- jclass result = nullptr;
- for (jint t = 0; t != thread_count; ++t) {
- // Always loop over all elements, as we need to free the local references.
- if (result == nullptr) {
- jvmtiThreadInfo info;
- CheckJvmtiError(jvmti_env, jvmti_env->GetThreadInfo(threads[t], &info));
- CheckJvmtiError(jvmti_env, Deallocate(jvmti_env, info.name));
- if (info.thread_group != nullptr) {
- env->DeleteLocalRef(info.thread_group);
- }
- if (info.context_class_loader != nullptr) {
- result = FindClassWithClassLoader(env, class_name, info.context_class_loader);
- env->ExceptionClear();
- env->DeleteLocalRef(info.context_class_loader);
- }
- }
- env->DeleteLocalRef(threads[t]);
- }
-
- if (result != nullptr) {
- return result;
- }
-
- // TODO: Implement scanning *all* classloaders.
- LOG(FATAL) << "Unimplemented";
-
- return nullptr;
-}
-
-void BindFunctions(jvmtiEnv* jvmti_env, JNIEnv* env, const char* class_name, jobject class_loader) {
- // Use JNI to load the class.
- ScopedLocalRef<jclass> klass(env, FindClass(jvmti_env, env, class_name, class_loader));
- CHECK(klass.get() != nullptr) << class_name;
-
- // Use JVMTI to get the methods.
- jint method_count;
- jmethodID* methods;
- jvmtiError methods_result = jvmti_env->GetClassMethods(klass.get(), &method_count, &methods);
- CheckJvmtiError(jvmti_env, methods_result);
-
- // Check each method.
- for (jint i = 0; i < method_count; ++i) {
- jint modifiers;
- jvmtiError mod_result = jvmti_env->GetMethodModifiers(methods[i], &modifiers);
- CheckJvmtiError(jvmti_env, mod_result);
- constexpr jint kNative = static_cast<jint>(0x0100);
- if ((modifiers & kNative) != 0) {
- BindMethod(jvmti_env, env, klass.get(), methods[i]);
- }
- }
-
- CheckJvmtiError(jvmti_env, Deallocate(jvmti_env, methods));
-}
-
-// Inform the main instrumentation class of our successful attach.
-static void InformMainAttach(jvmtiEnv* jvmti_env,
- JNIEnv* jni_env,
- const char* class_name,
- const char* method_name) {
- // Use JNI to load the class.
- ScopedLocalRef<jclass> klass(jni_env, FindClass(jvmti_env, jni_env, class_name, nullptr));
- CHECK(klass.get() != nullptr) << class_name;
-
- jmethodID method = jni_env->GetStaticMethodID(klass.get(), method_name, "()V");
- CHECK(method != nullptr);
-
- jni_env->CallStaticVoidMethod(klass.get(), method);
-}
-
-// TODO: Check this. This may not work on device. The classloader containing the app's classes
-// may not have been created at this point (i.e., if it's not the system classloader).
-static void JNICALL VMInitCallback(jvmtiEnv* jvmti_env,
- JNIEnv* jni_env,
- jthread thread ATTRIBUTE_UNUSED) {
- // Bind kMainClass native methods.
- BindFunctions(jvmti_env, jni_env, kMainClass);
-
- // And let the test know that we have started up.
- InformMainAttach(jvmti_env, jni_env, kMainClass, kMainClassStartup);
-
- // And delete the jvmtiEnv.
- jvmti_env->DisposeEnvironment();
-}
-
-// Install a phase callback that will bind JNI functions on VMInit.
-void BindOnLoad(JavaVM* vm) {
- // Use a new jvmtiEnv. Otherwise we might collide with table changes.
- jvmtiEnv* install_env;
- if (vm->GetEnv(reinterpret_cast<void**>(&install_env), JVMTI_VERSION_1_0) != 0) {
- LOG(FATAL) << "Could not get jvmtiEnv";
- }
- SetAllCapabilities(install_env);
-
- {
- jvmtiEventCallbacks callbacks;
- memset(&callbacks, 0, sizeof(jvmtiEventCallbacks));
- callbacks.VMInit = VMInitCallback;
-
- CheckJvmtiError(install_env, install_env->SetEventCallbacks(&callbacks, sizeof(callbacks)));
- }
-
- {
- CheckJvmtiError(install_env, install_env->SetEventNotificationMode(JVMTI_ENABLE,
- JVMTI_EVENT_VM_INIT,
- nullptr));
- }
-}
-
-// Ensure binding of the Main class when the agent is started through OnAttach.
-void BindOnAttach(JavaVM* vm) {
- // Get a JNIEnv. As the thread is attached, we must not destroy it.
- JNIEnv* env;
- if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != 0) {
- LOG(FATAL) << "Could not get JNIEnv";
- }
-
- jvmtiEnv* jvmti_env;
- if (vm->GetEnv(reinterpret_cast<void**>(&jvmti_env), JVMTI_VERSION_1_0) != 0) {
- LOG(FATAL) << "Could not get jvmtiEnv";
- }
- SetAllCapabilities(jvmti_env);
-
- BindFunctions(jvmti_env, env, kMainClass);
-
- // And let the test know that we have started up.
- InformMainAttach(jvmti_env, env, kMainClass, kMainClassStartup);
-
- if (jvmti_env->DisposeEnvironment() != JVMTI_ERROR_NONE) {
- LOG(FATAL) << "Could not dispose temporary jvmtiEnv";
- }
-}
-
-extern "C" JNIEXPORT void JNICALL Java_android_jvmti_cts_JniBindings_bindAgentJNI(
- JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jstring className, jobject classLoader) {
- ScopedUtfChars name(env, className);
- BindFunctions(GetJvmtiEnv(), env, name.c_str(), classLoader);
-}
-
-} // namespace jvmti
-} // namespace cts
diff --git a/hostsidetests/jvmti/base/jni/jni_binder.h b/hostsidetests/jvmti/base/jni/jni_binder.h
deleted file mode 100644
index fb311ee..0000000
--- a/hostsidetests/jvmti/base/jni/jni_binder.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef JNI_BINDER_H_
-#define JNI_BINDER_H_
-
-#include "jni.h"
-#include "jvmti.h"
-
-namespace cts {
-namespace jvmti {
-
-// Load the class through JNI. Inspect it, find all native methods. Construct the corresponding
-// mangled name, run dlsym and bind the method.
-//
-// This will abort on failure.
-void BindFunctions(jvmtiEnv* jvmti_env,
- JNIEnv* env,
- const char* class_name,
- jobject class_loader = nullptr);
-
-// Ensure binding of the Main class when the agent is started through OnLoad.
-void BindOnLoad(JavaVM* vm);
-
-// Ensure binding of the Main class when the agent is started through OnAttach.
-void BindOnAttach(JavaVM* vm);
-
-} // namespace jvmti
-} // namespace cts
-
-#endif // JNI_BINDER_H_
diff --git a/hostsidetests/jvmti/base/jni/jni_helper.h b/hostsidetests/jvmti/base/jni/jni_helper.h
deleted file mode 100644
index 14aba8b..0000000
--- a/hostsidetests/jvmti/base/jni/jni_helper.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef JNI_HELPER_H_
-#define JNI_HELPER_H_
-
-#include "jni.h"
-#include "scoped_local_ref.h"
-
-namespace cts {
-namespace jvmti {
-
-// Create an object array using a lambda that returns a local ref for each element.
-template <typename T>
-static jobjectArray CreateObjectArray(JNIEnv* env,
- jint length,
- const char* component_type_descriptor,
- T src) {
- if (length < 0) {
- return nullptr;
- }
-
- ScopedLocalRef<jclass> obj_class(env, env->FindClass(component_type_descriptor));
- if (obj_class.get() == nullptr) {
- return nullptr;
- }
-
- ScopedLocalRef<jobjectArray> ret(env, env->NewObjectArray(length, obj_class.get(), nullptr));
- if (ret.get() == nullptr) {
- return nullptr;
- }
-
- for (jint i = 0; i < length; ++i) {
- jobject element = src(i);
- env->SetObjectArrayElement(ret.get(), static_cast<jint>(i), element);
- env->DeleteLocalRef(element);
- if (env->ExceptionCheck()) {
- return nullptr;
- }
- }
-
- return ret.release();
-}
-
-} // namespace jvmti
-} // namespace cts
-
-#endif // JNI_HELPER_H_
diff --git a/hostsidetests/jvmti/base/jni/jvmti_helper.cpp b/hostsidetests/jvmti/base/jni/jvmti_helper.cpp
deleted file mode 100644
index a8a1aec..0000000
--- a/hostsidetests/jvmti/base/jni/jvmti_helper.cpp
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * 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.
- */
-
-#include "jvmti_helper.h"
-
-#include <algorithm>
-#include <dlfcn.h>
-#include <stdio.h>
-#include <sstream>
-#include <string.h>
-
-#include "android-base/logging.h"
-#include "scoped_local_ref.h"
-
-namespace cts {
-namespace jvmti {
-
-void CheckJvmtiError(jvmtiEnv* env, jvmtiError error) {
- if (error != JVMTI_ERROR_NONE) {
- char* error_name;
- jvmtiError name_error = env->GetErrorName(error, &error_name);
- if (name_error != JVMTI_ERROR_NONE) {
- LOG(FATAL) << "Unable to get error name for " << error;
- }
- LOG(FATAL) << "Unexpected error: " << error_name;
- }
-}
-
-void SetAllCapabilities(jvmtiEnv* env) {
- jvmtiCapabilities caps;
- jvmtiError error1 = env->GetPotentialCapabilities(&caps);
- CheckJvmtiError(env, error1);
- jvmtiError error2 = env->AddCapabilities(&caps);
- CheckJvmtiError(env, error2);
-}
-
-bool JvmtiErrorToException(JNIEnv* env, jvmtiEnv* jvmti_env, jvmtiError error) {
- if (error == JVMTI_ERROR_NONE) {
- return false;
- }
-
- ScopedLocalRef<jclass> rt_exception(env, env->FindClass("java/lang/RuntimeException"));
- if (rt_exception.get() == nullptr) {
- // CNFE should be pending.
- return true;
- }
-
- char* err;
- CheckJvmtiError(jvmti_env, jvmti_env->GetErrorName(error, &err));
-
- env->ThrowNew(rt_exception.get(), err);
-
- Deallocate(jvmti_env, err);
- return true;
-}
-
-std::ostream& operator<<(std::ostream& os, const jvmtiError& rhs) {
- switch (rhs) {
- case JVMTI_ERROR_NONE:
- return os << "NONE";
- case JVMTI_ERROR_INVALID_THREAD:
- return os << "INVALID_THREAD";
- case JVMTI_ERROR_INVALID_THREAD_GROUP:
- return os << "INVALID_THREAD_GROUP";
- case JVMTI_ERROR_INVALID_PRIORITY:
- return os << "INVALID_PRIORITY";
- case JVMTI_ERROR_THREAD_NOT_SUSPENDED:
- return os << "THREAD_NOT_SUSPENDED";
- case JVMTI_ERROR_THREAD_SUSPENDED:
- return os << "THREAD_SUSPENDED";
- case JVMTI_ERROR_THREAD_NOT_ALIVE:
- return os << "THREAD_NOT_ALIVE";
- case JVMTI_ERROR_INVALID_OBJECT:
- return os << "INVALID_OBJECT";
- case JVMTI_ERROR_INVALID_CLASS:
- return os << "INVALID_CLASS";
- case JVMTI_ERROR_CLASS_NOT_PREPARED:
- return os << "CLASS_NOT_PREPARED";
- case JVMTI_ERROR_INVALID_METHODID:
- return os << "INVALID_METHODID";
- case JVMTI_ERROR_INVALID_LOCATION:
- return os << "INVALID_LOCATION";
- case JVMTI_ERROR_INVALID_FIELDID:
- return os << "INVALID_FIELDID";
- case JVMTI_ERROR_NO_MORE_FRAMES:
- return os << "NO_MORE_FRAMES";
- case JVMTI_ERROR_OPAQUE_FRAME:
- return os << "OPAQUE_FRAME";
- case JVMTI_ERROR_TYPE_MISMATCH:
- return os << "TYPE_MISMATCH";
- case JVMTI_ERROR_INVALID_SLOT:
- return os << "INVALID_SLOT";
- case JVMTI_ERROR_DUPLICATE:
- return os << "DUPLICATE";
- case JVMTI_ERROR_NOT_FOUND:
- return os << "NOT_FOUND";
- case JVMTI_ERROR_INVALID_MONITOR:
- return os << "INVALID_MONITOR";
- case JVMTI_ERROR_NOT_MONITOR_OWNER:
- return os << "NOT_MONITOR_OWNER";
- case JVMTI_ERROR_INTERRUPT:
- return os << "INTERRUPT";
- case JVMTI_ERROR_INVALID_CLASS_FORMAT:
- return os << "INVALID_CLASS_FORMAT";
- case JVMTI_ERROR_CIRCULAR_CLASS_DEFINITION:
- return os << "CIRCULAR_CLASS_DEFINITION";
- case JVMTI_ERROR_FAILS_VERIFICATION:
- return os << "FAILS_VERIFICATION";
- case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_ADDED:
- return os << "UNSUPPORTED_REDEFINITION_METHOD_ADDED";
- case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_SCHEMA_CHANGED:
- return os << "UNSUPPORTED_REDEFINITION_SCHEMA_CHANGED";
- case JVMTI_ERROR_INVALID_TYPESTATE:
- return os << "INVALID_TYPESTATE";
- case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_HIERARCHY_CHANGED:
- return os << "UNSUPPORTED_REDEFINITION_HIERARCHY_CHANGED";
- case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_DELETED:
- return os << "UNSUPPORTED_REDEFINITION_METHOD_DELETED";
- case JVMTI_ERROR_UNSUPPORTED_VERSION:
- return os << "UNSUPPORTED_VERSION";
- case JVMTI_ERROR_NAMES_DONT_MATCH:
- return os << "NAMES_DONT_MATCH";
- case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_MODIFIERS_CHANGED:
- return os << "UNSUPPORTED_REDEFINITION_CLASS_MODIFIERS_CHANGED";
- case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_MODIFIERS_CHANGED:
- return os << "UNSUPPORTED_REDEFINITION_METHOD_MODIFIERS_CHANGED";
- case JVMTI_ERROR_UNMODIFIABLE_CLASS:
- return os << "JVMTI_ERROR_UNMODIFIABLE_CLASS";
- case JVMTI_ERROR_NOT_AVAILABLE:
- return os << "NOT_AVAILABLE";
- case JVMTI_ERROR_MUST_POSSESS_CAPABILITY:
- return os << "MUST_POSSESS_CAPABILITY";
- case JVMTI_ERROR_NULL_POINTER:
- return os << "NULL_POINTER";
- case JVMTI_ERROR_ABSENT_INFORMATION:
- return os << "ABSENT_INFORMATION";
- case JVMTI_ERROR_INVALID_EVENT_TYPE:
- return os << "INVALID_EVENT_TYPE";
- case JVMTI_ERROR_ILLEGAL_ARGUMENT:
- return os << "ILLEGAL_ARGUMENT";
- case JVMTI_ERROR_NATIVE_METHOD:
- return os << "NATIVE_METHOD";
- case JVMTI_ERROR_CLASS_LOADER_UNSUPPORTED:
- return os << "CLASS_LOADER_UNSUPPORTED";
- case JVMTI_ERROR_OUT_OF_MEMORY:
- return os << "OUT_OF_MEMORY";
- case JVMTI_ERROR_ACCESS_DENIED:
- return os << "ACCESS_DENIED";
- case JVMTI_ERROR_WRONG_PHASE:
- return os << "WRONG_PHASE";
- case JVMTI_ERROR_INTERNAL:
- return os << "INTERNAL";
- case JVMTI_ERROR_UNATTACHED_THREAD:
- return os << "UNATTACHED_THREAD";
- case JVMTI_ERROR_INVALID_ENVIRONMENT:
- return os << "INVALID_ENVIRONMENT";
- }
- LOG(FATAL) << "Unexpected error type " << static_cast<int>(rhs);
- __builtin_unreachable();
-}
-
-} // namespace jvmti
-} // namespace cts
diff --git a/hostsidetests/jvmti/base/jni/jvmti_helper.h b/hostsidetests/jvmti/base/jni/jvmti_helper.h
deleted file mode 100644
index 898fa96..0000000
--- a/hostsidetests/jvmti/base/jni/jvmti_helper.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef JVMTI_HELPER_H_
-#define JVMTI_HELPER_H_
-
-#include "jni.h"
-#include "jvmti.h"
-#include <memory>
-#include <ostream>
-
-#include "android-base/logging.h"
-
-namespace cts {
-namespace jvmti {
-
-// Add all capabilities to the given env.
-void SetAllCapabilities(jvmtiEnv* env);
-
-// Check whether the given error is NONE. If not, print out the corresponding error message
-// and abort.
-void CheckJvmtiError(jvmtiEnv* env, jvmtiError error);
-
-// Convert the given error to a RuntimeException with a message derived from the error. Returns
-// true on error, false if error is JVMTI_ERROR_NONE.
-bool JvmtiErrorToException(JNIEnv* env, jvmtiEnv* jvmti_env, jvmtiError error);
-
-class JvmtiDeleter {
- public:
- JvmtiDeleter() : env_(nullptr) {}
- explicit JvmtiDeleter(jvmtiEnv* env) : env_(env) {}
-
- JvmtiDeleter(JvmtiDeleter&) = default;
- JvmtiDeleter(JvmtiDeleter&&) = default;
- JvmtiDeleter& operator=(const JvmtiDeleter&) = default;
-
- void operator()(unsigned char* ptr) const {
- CHECK(env_ != nullptr);
- jvmtiError ret = env_->Deallocate(ptr);
- CheckJvmtiError(env_, ret);
- }
-
- private:
- mutable jvmtiEnv* env_;
-};
-
-using JvmtiUniquePtr = std::unique_ptr<unsigned char, JvmtiDeleter>;
-
-template <typename T>
-static inline JvmtiUniquePtr MakeJvmtiUniquePtr(jvmtiEnv* env, T* mem) {
- return JvmtiUniquePtr(reinterpret_cast<unsigned char*>(mem), JvmtiDeleter(env));
-}
-
-template <typename T>
-static inline jvmtiError Deallocate(jvmtiEnv* env, T* mem) {
- return env->Deallocate(reinterpret_cast<unsigned char*>(mem));
-}
-
-// To print jvmtiError. Does not rely on GetErrorName, so is an approximation.
-std::ostream& operator<<(std::ostream& os, const jvmtiError& rhs);
-
-} // namespace jvmti
-} // namespace cts
-
-#endif // JVMTI_HELPER_H_
diff --git a/hostsidetests/jvmti/base/jni/redefine.cpp b/hostsidetests/jvmti/base/jni/redefine.cpp
index d948b2c..c6e8726 100644
--- a/hostsidetests/jvmti/base/jni/redefine.cpp
+++ b/hostsidetests/jvmti/base/jni/redefine.cpp
@@ -23,15 +23,13 @@
#include "android-base/logging.h"
#include "android-base/macros.h"
-#include "common.h"
#include "jni_helper.h"
#include "jvmti_helper.h"
#include "jvmti.h"
#include "scoped_primitive_array.h"
+#include "test_env.h"
-namespace cts {
-namespace jvmti {
-namespace redefine {
+namespace art {
extern "C" JNIEXPORT jint JNICALL Java_android_jvmti_cts_JvmtiRedefineClassesTest_redefineClass(
JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jclass target, jbyteArray dex_bytes) {
@@ -39,21 +37,21 @@
def.klass = target;
def.class_byte_count = static_cast<jint>(env->GetArrayLength(dex_bytes));
signed char* redef_bytes = env->GetByteArrayElements(dex_bytes, nullptr);
- jvmtiError res = GetJvmtiEnv()->Allocate(def.class_byte_count,
- const_cast<unsigned char**>(&def.class_bytes));
+ jvmtiError res =jvmti_env->Allocate(def.class_byte_count,
+ const_cast<unsigned char**>(&def.class_bytes));
if (res != JVMTI_ERROR_NONE) {
return static_cast<jint>(res);
}
memcpy(const_cast<unsigned char*>(def.class_bytes), redef_bytes, def.class_byte_count);
env->ReleaseByteArrayElements(dex_bytes, redef_bytes, 0);
// Do the redefinition.
- res = GetJvmtiEnv()->RedefineClasses(1, &def);
+ res = jvmti_env->RedefineClasses(1, &def);
return static_cast<jint>(res);
}
extern "C" JNIEXPORT jint JNICALL Java_android_jvmti_cts_JvmtiRedefineClassesTest_retransformClass(
JNIEnv* env ATTRIBUTE_UNUSED, jclass klass ATTRIBUTE_UNUSED, jclass target) {
- return GetJvmtiEnv()->RetransformClasses(1, &target);
+ return jvmti_env->RetransformClasses(1, &target);
}
class TransformationData {
@@ -105,7 +103,7 @@
static TransformationData data;
// The hook we are using.
-void JNICALL CommonClassFileLoadHookRetransformable(jvmtiEnv* jvmti_env,
+void JNICALL CommonClassFileLoadHookRetransformable(jvmtiEnv* local_jvmti_env,
JNIEnv* jni_env ATTRIBUTE_UNUSED,
jclass class_being_redefined ATTRIBUTE_UNUSED,
jobject loader ATTRIBUTE_UNUSED,
@@ -119,7 +117,7 @@
std::vector<unsigned char> dex_data;
if (data.RetrieveRedefinition(name_str, &dex_data)) {
unsigned char* jvmti_dex_data;
- if (JVMTI_ERROR_NONE != jvmti_env->Allocate(dex_data.size(), &jvmti_dex_data)) {
+ if (JVMTI_ERROR_NONE != local_jvmti_env->Allocate(dex_data.size(), &jvmti_dex_data)) {
LOG(FATAL) << "Unable to allocate output buffer for " << name;
return;
}
@@ -136,12 +134,12 @@
jvmtiEventCallbacks cb;
memset(&cb, 0, sizeof(cb));
cb.ClassFileLoadHook = CommonClassFileLoadHookRetransformable;
- if (JvmtiErrorToException(env, GetJvmtiEnv(),
- GetJvmtiEnv()->SetEventCallbacks(&cb, sizeof(cb)))) {
+ if (JvmtiErrorToException(env, jvmti_env, jvmti_env->SetEventCallbacks(&cb, sizeof(cb)))) {
return;
}
- JvmtiErrorToException(env, GetJvmtiEnv(),
- GetJvmtiEnv()->SetEventNotificationMode(
+ JvmtiErrorToException(env,
+ jvmti_env,
+ jvmti_env->SetEventNotificationMode(
enable == JNI_TRUE ? JVMTI_ENABLE : JVMTI_DISABLE,
JVMTI_EVENT_CLASS_FILE_LOAD_HOOK,
nullptr));
@@ -174,7 +172,5 @@
env->ReleaseByteArrayElements(dex_bytes, redef_bytes, 0);
}
-} // namespace redefine
-} // namespace jvmti
-} // namespace cts
+} // namespace art
diff --git a/hostsidetests/jvmti/base/jni/scoped_local_ref.h b/hostsidetests/jvmti/base/jni/scoped_local_ref.h
deleted file mode 100644
index 4622480..0000000
--- a/hostsidetests/jvmti/base/jni/scoped_local_ref.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- */
-
-#ifndef SCOPED_LOCAL_REF_H_
-#define SCOPED_LOCAL_REF_H_
-
-#include "jni.h"
-
-#include <stddef.h>
-
-#include "android-base/macros.h"
-
-namespace cts {
-namespace jvmti {
-
-template<typename T>
-class ScopedLocalRef {
-public:
- ScopedLocalRef(JNIEnv* env, T localRef) : mEnv(env), mLocalRef(localRef) {
- }
-
- ~ScopedLocalRef() {
- reset();
- }
-
- void reset(T ptr = NULL) {
- if (ptr != mLocalRef) {
- if (mLocalRef != NULL) {
- mEnv->DeleteLocalRef(mLocalRef);
- }
- mLocalRef = ptr;
- }
- }
-
- T release() __attribute__((warn_unused_result)) {
- T localRef = mLocalRef;
- mLocalRef = NULL;
- return localRef;
- }
-
- T get() const {
- return mLocalRef;
- }
-
-private:
- JNIEnv* const mEnv;
- T mLocalRef;
-
- DISALLOW_COPY_AND_ASSIGN(ScopedLocalRef);
-};
-
-}
-}
-
-#endif // SCOPED_LOCAL_REF_H_
diff --git a/hostsidetests/jvmti/base/jni/scoped_primitive_array.h b/hostsidetests/jvmti/base/jni/scoped_primitive_array.h
deleted file mode 100644
index c030b7d..0000000
--- a/hostsidetests/jvmti/base/jni/scoped_primitive_array.h
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- */
-
-#ifndef SCOPED_PRIMITIVE_ARRAY_H_
-#define SCOPED_PRIMITIVE_ARRAY_H_
-
-#include "jni.h"
-
-#include "android-base/macros.h"
-#include "common.h"
-
-namespace cts {
-namespace jvmti {
-
-#ifdef POINTER_TYPE
-#error POINTER_TYPE is defined.
-#else
-#define POINTER_TYPE(T) T* /* NOLINT */
-#endif
-
-#ifdef REFERENCE_TYPE
-#error REFERENCE_TYPE is defined.
-#else
-#define REFERENCE_TYPE(T) T& /* NOLINT */
-#endif
-
-// ScopedBooleanArrayRO, ScopedByteArrayRO, ScopedCharArrayRO, ScopedDoubleArrayRO,
-// ScopedFloatArrayRO, ScopedIntArrayRO, ScopedLongArrayRO, and ScopedShortArrayRO provide
-// convenient read-only access to Java arrays from JNI code. This is cheaper than read-write
-// access and should be used by default.
-#define INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RO(PRIMITIVE_TYPE, NAME) \
- class Scoped ## NAME ## ArrayRO { \
- public: \
- explicit Scoped ## NAME ## ArrayRO(JNIEnv* env) \
- : mEnv(env), mJavaArray(nullptr), mRawArray(nullptr), mSize(0) {} \
- Scoped ## NAME ## ArrayRO(JNIEnv* env, PRIMITIVE_TYPE ## Array javaArray) \
- : mEnv(env) { \
- if (javaArray == nullptr) { \
- mJavaArray = nullptr; \
- mSize = 0; \
- mRawArray = nullptr; \
- JniThrowNullPointerException(env, nullptr); \
- } else { \
- reset(javaArray); \
- } \
- } \
- ~Scoped ## NAME ## ArrayRO() { \
- if (mRawArray != nullptr && mRawArray != mBuffer) { \
- mEnv->Release ## NAME ## ArrayElements(mJavaArray, mRawArray, JNI_ABORT); \
- } \
- } \
- void reset(PRIMITIVE_TYPE ## Array javaArray) { \
- mJavaArray = javaArray; \
- mSize = mEnv->GetArrayLength(mJavaArray); \
- if (mSize <= buffer_size) { \
- mEnv->Get ## NAME ## ArrayRegion(mJavaArray, 0, mSize, mBuffer); \
- mRawArray = mBuffer; \
- } else { \
- mRawArray = mEnv->Get ## NAME ## ArrayElements(mJavaArray, nullptr); \
- } \
- } \
- const PRIMITIVE_TYPE* get() const { return mRawArray; } \
- PRIMITIVE_TYPE ## Array getJavaArray() const { return mJavaArray; } \
- const PRIMITIVE_TYPE& operator[](size_t n) const { return mRawArray[n]; } \
- size_t size() const { return mSize; } \
- private: \
- static const jsize buffer_size = 1024; \
- JNIEnv* const mEnv; \
- PRIMITIVE_TYPE ## Array mJavaArray; \
- POINTER_TYPE(PRIMITIVE_TYPE) mRawArray; \
- jsize mSize; \
- PRIMITIVE_TYPE mBuffer[buffer_size]; \
- DISALLOW_COPY_AND_ASSIGN(Scoped ## NAME ## ArrayRO); \
- }
-
-INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RO(jboolean, Boolean);
-INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RO(jbyte, Byte);
-INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RO(jchar, Char);
-INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RO(jdouble, Double);
-INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RO(jfloat, Float);
-INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RO(jint, Int);
-INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RO(jlong, Long);
-INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RO(jshort, Short);
-
-#undef INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RO
-
-// ScopedBooleanArrayRW, ScopedByteArrayRW, ScopedCharArrayRW, ScopedDoubleArrayRW,
-// ScopedFloatArrayRW, ScopedIntArrayRW, ScopedLongArrayRW, and ScopedShortArrayRW provide
-// convenient read-write access to Java arrays from JNI code. These are more expensive,
-// since they entail a copy back onto the Java heap, and should only be used when necessary.
-#define INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RW(PRIMITIVE_TYPE, NAME) \
- class Scoped ## NAME ## ArrayRW { \
- public: \
- explicit Scoped ## NAME ## ArrayRW(JNIEnv* env) \
- : mEnv(env), mJavaArray(nullptr), mRawArray(nullptr) {} \
- Scoped ## NAME ## ArrayRW(JNIEnv* env, PRIMITIVE_TYPE ## Array javaArray) \
- : mEnv(env), mJavaArray(javaArray), mRawArray(nullptr) { \
- if (mJavaArray == nullptr) { \
- JniThrowNullPointerException(env, nullptr); \
- } else { \
- mRawArray = mEnv->Get ## NAME ## ArrayElements(mJavaArray, nullptr); \
- } \
- } \
- ~Scoped ## NAME ## ArrayRW() { \
- if (mRawArray) { \
- mEnv->Release ## NAME ## ArrayElements(mJavaArray, mRawArray, 0); \
- } \
- } \
- void reset(PRIMITIVE_TYPE ## Array javaArray) { \
- mJavaArray = javaArray; \
- mRawArray = mEnv->Get ## NAME ## ArrayElements(mJavaArray, nullptr); \
- } \
- const PRIMITIVE_TYPE* get() const { return mRawArray; } \
- PRIMITIVE_TYPE ## Array getJavaArray() const { return mJavaArray; } \
- const PRIMITIVE_TYPE& operator[](size_t n) const { return mRawArray[n]; } \
- POINTER_TYPE(PRIMITIVE_TYPE) get() { return mRawArray; } \
- REFERENCE_TYPE(PRIMITIVE_TYPE) operator[](size_t n) { return mRawArray[n]; } \
- size_t size() const { return mEnv->GetArrayLength(mJavaArray); } \
- private: \
- JNIEnv* const mEnv; \
- PRIMITIVE_TYPE ## Array mJavaArray; \
- POINTER_TYPE(PRIMITIVE_TYPE) mRawArray; \
- DISALLOW_COPY_AND_ASSIGN(Scoped ## NAME ## ArrayRW); \
- }
-
-INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RW(jboolean, Boolean);
-INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RW(jbyte, Byte);
-INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RW(jchar, Char);
-INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RW(jdouble, Double);
-INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RW(jfloat, Float);
-INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RW(jint, Int);
-INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RW(jlong, Long);
-INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RW(jshort, Short);
-
-#undef INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RW
-#undef POINTER_TYPE
-#undef REFERENCE_TYPE
-
-}
-}
-
-#endif // SCOPED_PRIMITIVE_ARRAY_H_
diff --git a/hostsidetests/jvmti/base/jni/scoped_utf_chars.h b/hostsidetests/jvmti/base/jni/scoped_utf_chars.h
deleted file mode 100644
index 8d28a7a..0000000
--- a/hostsidetests/jvmti/base/jni/scoped_utf_chars.h
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- */
-
-#ifndef SCOPED_UTF_CHARS_H_
-#define SCOPED_UTF_CHARS_H_
-
-#include "jni.h"
-
-#include <string.h>
-
-#include "android-base/macros.h"
-#include "common.h"
-
-namespace cts {
-namespace jvmti {
-
-class ScopedUtfChars {
- public:
- ScopedUtfChars(JNIEnv* env, jstring s) : env_(env), string_(s) {
- if (s == nullptr) {
- utf_chars_ = nullptr;
- JniThrowNullPointerException(env, nullptr);
- } else {
- utf_chars_ = env->GetStringUTFChars(s, nullptr);
- }
- }
-
- ScopedUtfChars(ScopedUtfChars&& rhs) :
- env_(rhs.env_), string_(rhs.string_), utf_chars_(rhs.utf_chars_) {
- rhs.env_ = nullptr;
- rhs.string_ = nullptr;
- rhs.utf_chars_ = nullptr;
- }
-
- ~ScopedUtfChars() {
- if (utf_chars_) {
- env_->ReleaseStringUTFChars(string_, utf_chars_);
- }
- }
-
- ScopedUtfChars& operator=(ScopedUtfChars&& rhs) {
- if (this != &rhs) {
- // Delete the currently owned UTF chars.
- this->~ScopedUtfChars();
-
- // Move the rhs ScopedUtfChars and zero it out.
- env_ = rhs.env_;
- string_ = rhs.string_;
- utf_chars_ = rhs.utf_chars_;
- rhs.env_ = nullptr;
- rhs.string_ = nullptr;
- rhs.utf_chars_ = nullptr;
- }
- return *this;
- }
-
- const char* c_str() const {
- return utf_chars_;
- }
-
- size_t size() const {
- return strlen(utf_chars_);
- }
-
- const char& operator[](size_t n) const {
- return utf_chars_[n];
- }
-
- private:
- JNIEnv* env_;
- jstring string_;
- const char* utf_chars_;
-
- DISALLOW_COPY_AND_ASSIGN(ScopedUtfChars);
-};
-
-}
-}
-
-#endif // SCOPED_UTF_CHARS_H_
diff --git a/hostsidetests/jvmti/base/jni/tagging.cpp b/hostsidetests/jvmti/base/jni/tagging.cpp
index 1e59e13..372805b 100644
--- a/hostsidetests/jvmti/base/jni/tagging.cpp
+++ b/hostsidetests/jvmti/base/jni/tagging.cpp
@@ -18,26 +18,22 @@
#include "android-base/logging.h"
#include "android-base/macros.h"
-#include "common.h"
#include "jni_helper.h"
#include "jvmti_helper.h"
#include "jvmti.h"
#include "scoped_primitive_array.h"
+#include "test_env.h"
-namespace cts {
-namespace jvmti {
-namespace tagging {
+namespace art {
extern "C" JNIEXPORT void JNICALL Java_android_jvmti_cts_JniBindings_setTag(
JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jobject obj, jlong tag) {
- jvmtiEnv* jvmti_env = GetJvmtiEnv();
jvmtiError ret = jvmti_env->SetTag(obj, tag);
JvmtiErrorToException(env, jvmti_env, ret);
}
extern "C" JNIEXPORT jlong JNICALL Java_android_jvmti_cts_JniBindings_getTag(
JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jobject obj) {
- jvmtiEnv* jvmti_env = GetJvmtiEnv();
jlong tag = 0;
jvmtiError ret = jvmti_env->GetTag(obj, &tag);
if (JvmtiErrorToException(env, jvmti_env, ret)) {
@@ -52,7 +48,6 @@
jlongArray searchTags,
jboolean returnObjects,
jboolean returnTags) {
- jvmtiEnv* jvmti_env = GetJvmtiEnv();
ScopedLongArrayRO scoped_array(env);
if (searchTags != nullptr) {
scoped_array.reset(searchTags);
@@ -132,7 +127,5 @@
return CreateObjectArray(env, 3, "java/lang/Object", callback);
}
-} // namespace tagging
-} // namespace jvmti
-} // namespace cts
+} // namespace art
diff --git a/hostsidetests/jvmti/base/jni/tracking.cpp b/hostsidetests/jvmti/base/jni/tracking.cpp
index a46f491..a07d653 100644
--- a/hostsidetests/jvmti/base/jni/tracking.cpp
+++ b/hostsidetests/jvmti/base/jni/tracking.cpp
@@ -21,14 +21,12 @@
#include "android-base/logging.h"
#include "android-base/stringprintf.h"
-#include "common.h"
#include "jvmti_helper.h"
#include "scoped_local_ref.h"
#include "scoped_utf_chars.h"
+#include "test_env.h"
-namespace cts {
-namespace jvmti {
-namespace allocation_tracking {
+namespace art {
static std::string GetClassName(JNIEnv* jni_env, jclass cls) {
ScopedLocalRef<jclass> class_class(jni_env, jni_env->GetObjectClass(cls));
@@ -65,17 +63,17 @@
memset(&callbacks, 0, sizeof(jvmtiEventCallbacks));
callbacks.VMObjectAlloc = enable ? ObjectAllocated : nullptr;
- jvmtiError ret = GetJvmtiEnv()->SetEventCallbacks(&callbacks, sizeof(callbacks));
- JvmtiErrorToException(env, GetJvmtiEnv(), ret);
+ jvmtiError ret = jvmti_env->SetEventCallbacks(&callbacks, sizeof(callbacks));
+ JvmtiErrorToException(env, jvmti_env, ret);
}
extern "C" JNIEXPORT void JNICALL Java_android_jvmti_cts_JvmtiTrackingTest_enableAllocationTracking(
JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jthread thread, jboolean enable) {
- jvmtiError ret = GetJvmtiEnv()->SetEventNotificationMode(
+ jvmtiError ret = jvmti_env->SetEventNotificationMode(
enable ? JVMTI_ENABLE : JVMTI_DISABLE,
JVMTI_EVENT_VM_OBJECT_ALLOC,
thread);
- JvmtiErrorToException(env, GetJvmtiEnv(), ret);
+ JvmtiErrorToException(env, jvmti_env, ret);
}
extern "C" JNIEXPORT
@@ -95,6 +93,4 @@
return env->NewStringUTF(result.c_str());
}
-} // namespace allocation_tracking
-} // namespace jvmti
-} // namespace cts
+} // namespace art
diff --git a/hostsidetests/jvmti/redefining/app/src/android/jvmti/cts/JvmtiRedefineClassesTest.java b/hostsidetests/jvmti/redefining/app/src/android/jvmti/cts/JvmtiRedefineClassesTest.java
index 169afe2..dd40eaa 100644
--- a/hostsidetests/jvmti/redefining/app/src/android/jvmti/cts/JvmtiRedefineClassesTest.java
+++ b/hostsidetests/jvmti/redefining/app/src/android/jvmti/cts/JvmtiRedefineClassesTest.java
@@ -34,6 +34,8 @@
import org.junit.BeforeClass;
import org.junit.Test;
+import art.Main;
+
/**
* Check redefineClasses-related functionality.
*/
@@ -41,7 +43,7 @@
@Before
public void setUp() throws Exception {
- JniBindings.bindAgentJNI("android/jvmti/cts/JvmtiRedefineClassesTest",
+ Main.bindAgentJNI("android/jvmti/cts/JvmtiRedefineClassesTest",
getClass().getClassLoader());
// make sure everything is cleared.
setTransformationEvent(false);
diff --git a/hostsidetests/jvmti/redefining/app/src/art/Main.java b/hostsidetests/jvmti/redefining/app/src/art/Main.java
new file mode 100644
index 0000000..6f569d1
--- /dev/null
+++ b/hostsidetests/jvmti/redefining/app/src/art/Main.java
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+package art;
+
+/**
+ * This is a definition of generically exposed implementations by the CTS JVMTI agent.
+ */
+public class Main {
+ // Load the given class with the given classloader, and bind all native methods to corresponding
+ // C methods in the agent. Will abort if any of the steps fail.
+ public static native void bindAgentJNI(String className, ClassLoader classLoader);
+ // Same as above, giving the class directly.
+ public static native void bindAgentJNIForClass(Class<?> klass);
+
+ // General functionality shared between tests.
+ public static native void setTag(Object o, long tag);
+
+ public static native long getTag(Object o);
+}
diff --git a/hostsidetests/jvmti/tagging/app/src/android/jvmti/cts/JvmtiTaggingTest.java b/hostsidetests/jvmti/tagging/app/src/android/jvmti/cts/JvmtiTaggingTest.java
index 6ba9376..7c77fe7 100644
--- a/hostsidetests/jvmti/tagging/app/src/android/jvmti/cts/JvmtiTaggingTest.java
+++ b/hostsidetests/jvmti/tagging/app/src/android/jvmti/cts/JvmtiTaggingTest.java
@@ -24,6 +24,8 @@
import org.junit.Before;
import org.junit.Test;
+import art.Main;
+
/**
* Check tagging-related functionality.
*/
@@ -32,33 +34,33 @@
@Before
public void setUp() throws Exception {
// Bind our native methods.
- JniBindings.bindAgentJNI("android/jvmti/cts/JvmtiTaggingTest", getClass().getClassLoader());
+ Main.bindAgentJNI("android/jvmti/cts/JvmtiTaggingTest", getClass().getClassLoader());
}
private static WeakReference<Object> test() {
Object o1 = new Object();
- JniBindings.setTag(o1, 1);
+ Main.setTag(o1, 1);
Object o2 = new Object();
- JniBindings.setTag(o2, 2);
+ Main.setTag(o2, 2);
- assertEquals(1, JniBindings.getTag(o1));
- assertEquals(2, JniBindings.getTag(o2));
+ assertEquals(1, Main.getTag(o1));
+ assertEquals(2, Main.getTag(o2));
Runtime.getRuntime().gc();
Runtime.getRuntime().gc();
- assertEquals(1, JniBindings.getTag(o1));
- assertEquals(2, JniBindings.getTag(o2));
+ assertEquals(1, Main.getTag(o1));
+ assertEquals(2, Main.getTag(o2));
Runtime.getRuntime().gc();
Runtime.getRuntime().gc();
- JniBindings.setTag(o1, 10);
- JniBindings.setTag(o2, 20);
+ Main.setTag(o1, 10);
+ Main.setTag(o2, 20);
- assertEquals(10, JniBindings.getTag(o1));
- assertEquals(20, JniBindings.getTag(o2));
+ assertEquals(10, Main.getTag(o1));
+ assertEquals(20, Main.getTag(o2));
return new WeakReference<Object>(o1);
}
@@ -93,7 +95,7 @@
Integer o = new Integer(i);
l.add(o);
if (i % 10 != 0) {
- JniBindings.setTag(o, i % 10);
+ Main.setTag(o, i % 10);
}
}
diff --git a/hostsidetests/jvmti/tagging/app/src/art/Main.java b/hostsidetests/jvmti/tagging/app/src/art/Main.java
new file mode 100644
index 0000000..6f569d1
--- /dev/null
+++ b/hostsidetests/jvmti/tagging/app/src/art/Main.java
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+package art;
+
+/**
+ * This is a definition of generically exposed implementations by the CTS JVMTI agent.
+ */
+public class Main {
+ // Load the given class with the given classloader, and bind all native methods to corresponding
+ // C methods in the agent. Will abort if any of the steps fail.
+ public static native void bindAgentJNI(String className, ClassLoader classLoader);
+ // Same as above, giving the class directly.
+ public static native void bindAgentJNIForClass(Class<?> klass);
+
+ // General functionality shared between tests.
+ public static native void setTag(Object o, long tag);
+
+ public static native long getTag(Object o);
+}