}
static jvmtiError GetClassLoader(jvmtiEnv* env, jclass klass, jobject* classloader_ptr) {
- return ERR(NOT_IMPLEMENTED);
+ return ClassUtil::GetClassLoader(env, klass, classloader_ptr);
}
static jvmtiError GetSourceDebugExtension(jvmtiEnv* env,
return ERR(NONE);
}
+jvmtiError ClassUtil::GetClassLoader(jvmtiEnv* env ATTRIBUTE_UNUSED,
+ jclass jklass,
+ jobject* classloader_ptr) {
+ art::ScopedObjectAccess soa(art::Thread::Current());
+ art::ObjPtr<art::mirror::Class> klass = soa.Decode<art::mirror::Class>(jklass);
+ if (klass == nullptr) {
+ return ERR(INVALID_CLASS);
+ }
+
+ if (classloader_ptr == nullptr) {
+ return ERR(NULL_POINTER);
+ }
+
+ *classloader_ptr = soa.AddLocalReference<jobject>(klass->GetClassLoader());
+
+ return ERR(NONE);
+}
+
} // namespace openjdkjvmti
static jvmtiError GetClassStatus(jvmtiEnv* env, jclass klass, jint* status_ptr);
+ static jvmtiError GetClassLoader(jvmtiEnv* env, jclass klass, jobject* classloader_ptr);
+
static jvmtiError IsInterface(jvmtiEnv* env, jclass klass, jboolean* is_interface_ptr);
static jvmtiError IsArrayClass(jvmtiEnv* env, jclass klass, jboolean* is_array_class_ptr);
};
return status;
}
+extern "C" JNIEXPORT jobject JNICALL Java_Main_getClassLoader(
+ JNIEnv* env ATTRIBUTE_UNUSED, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) {
+ jobject classloader;
+ jvmtiError result = jvmti_env->GetClassLoader(klass, &classloader);
+ if (result != JVMTI_ERROR_NONE) {
+ char* err;
+ jvmti_env->GetErrorName(result, &err);
+ printf("Failure running GetClassLoader: %s\n", err);
+ jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(err));
+ return nullptr;
+ }
+ return classloader;
+}
+
// Don't do anything
jint OnLoad(JavaVM* vm,
char* options ATTRIBUTE_UNUSED,
class Main$ClassA [interface Main$InfA]
class Main$ClassB [interface Main$InfB]
class Main$ClassC [interface Main$InfA, interface Main$InfC]
+class java.lang.String null
+class [Ljava.lang.String; null
+interface Main$InfA dalvik.system.PathClassLoader
+class $Proxy0 dalvik.system.PathClassLoader
testInterfaces(ClassA.class);
testInterfaces(ClassB.class);
testInterfaces(ClassC.class);
+
+ testClassLoader(String.class);
+ testClassLoader(String[].class);
+ testClassLoader(InfA.class);
+ testClassLoader(getProxyClass());
}
private static Class<?> proxyClass = null;
System.out.println(c + " " + Arrays.toString(getImplementedInterfaces(c)));
}
+ private static boolean IsBootClassLoader(ClassLoader l) {
+ // Hacky check for Android's fake boot classloader.
+ return l.getClass().getName().equals("java.lang.BootClassLoader");
+ }
+
+ private static void testClassLoader(Class<?> c) {
+ Object cl = getClassLoader(c);
+ System.out.println(c + " " + (cl != null ? cl.getClass().getName() : "null"));
+ if (cl == null) {
+ if (c.getClassLoader() != null && !IsBootClassLoader(c.getClassLoader())) {
+ throw new RuntimeException("Expected " + c.getClassLoader() + ", but got null.");
+ }
+ } else {
+ if (!(cl instanceof ClassLoader)) {
+ throw new RuntimeException("Unexpected \"classloader\": " + cl + " (" + cl.getClass() +
+ ")");
+ }
+ if (cl != c.getClassLoader()) {
+ throw new RuntimeException("Unexpected classloader: " + c.getClassLoader() + " vs " + cl);
+ }
+ }
+ }
+
private static native String[] getClassSignature(Class<?> c);
private static native boolean isInterface(Class<?> c);
private static native int getClassStatus(Class<?> c);
+ private static native Object getClassLoader(Class<?> c);
+
private static class TestForNonInit {
public static double dummy = Math.random(); // So it can't be compile-time initialized.
}