From: Yong WU Date: Sun, 3 Aug 2014 08:06:52 +0000 (+0800) Subject: Add trampoline invoke and ART callback tests for native-bridge X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=f7a68c1bd01db4e80003eb19cc8a4cdc8330adbe;p=android-x86%2Fart.git Add trampoline invoke and ART callback tests for native-bridge Create trampolines for JNI functions in native-bridge. Test trampoline invoking from ART side. Add tests for ART callbacks which called from native-bridge. In this test they are invoked from the trampoline of JNI_OnLoad. Change-Id: Ibaa5103fdf49a6b29a1c12f45410fe5f82d46b1e --- diff --git a/test/115-native-bridge/expected.txt b/test/115-native-bridge/expected.txt index f852620b3..5b41606b5 100644 --- a/test/115-native-bridge/expected.txt +++ b/test/115-native-bridge/expected.txt @@ -1,13 +1,55 @@ Ready for native bridge tests. Native bridge initialized. Checking for support. -Getting trampoline. -Getting trampoline. -Getting trampoline. -Getting trampoline. -Getting trampoline. -Getting trampoline. -Getting trampoline. -Getting trampoline. -Getting trampoline. -Getting trampoline. +Getting trampoline for JNI_OnLoad with shorty (null). +Test ART callbacks: all JNI function number is 9. + name:booleanMethod, signature:(ZZZZZZZZZZ)Z, shorty:ZZZZZZZZZZZ. + name:byteMethod, signature:(BBBBBBBBBB)B, shorty:BBBBBBBBBBB. + name:charMethod, signature:(CCCCCCCCCC)C, shorty:CCCCCCCCCCC. + name:shortMethod, signature:(SSSSSSSSSS)S, shorty:SSSSSSSSSSS. + name:testCallStaticVoidMethodOnSubClassNative, signature:()V, shorty:V. + name:testFindClassOnAttachedNativeThread, signature:()V, shorty:V. + name:testFindFieldOnAttachedNativeThreadNative, signature:()V, shorty:V. + name:testGetMirandaMethodNative, signature:()Ljava/lang/reflect/Method;, shorty:L. + name:testZeroLengthByteBuffers, signature:()V, shorty:V. +trampoline_JNI_OnLoad called! +Getting trampoline for Java_Main_testFindClassOnAttachedNativeThread with shorty V. +trampoline_Java_Main_testFindClassOnAttachedNativeThread called! +Getting trampoline for Java_Main_testFindFieldOnAttachedNativeThreadNative with shorty V. +trampoline_Java_Main_testFindFieldOnAttachedNativeThreadNative called! +Getting trampoline for Java_Main_testCallStaticVoidMethodOnSubClassNative with shorty V. +trampoline_Java_Main_testCallStaticVoidMethodOnSubClassNative called! +Getting trampoline for Java_Main_testGetMirandaMethodNative with shorty L. +trampoline_Java_Main_testGetMirandaMethodNative called! +Getting trampoline for Java_Main_testZeroLengthByteBuffers with shorty V. +trampoline_Java_Main_testZeroLengthByteBuffers called! +Getting trampoline for Java_Main_byteMethod with shorty BBBBBBBBBBB. +trampoline_Java_Main_byteMethod called! +trampoline_Java_Main_byteMethod called! +trampoline_Java_Main_byteMethod called! +trampoline_Java_Main_byteMethod called! +trampoline_Java_Main_byteMethod called! +trampoline_Java_Main_byteMethod called! +trampoline_Java_Main_byteMethod called! +Getting trampoline for Java_Main_shortMethod with shorty SSSSSSSSSSS. +trampoline_Java_Main_shortMethod called! +trampoline_Java_Main_shortMethod called! +trampoline_Java_Main_shortMethod called! +trampoline_Java_Main_shortMethod called! +trampoline_Java_Main_shortMethod called! +trampoline_Java_Main_shortMethod called! +trampoline_Java_Main_shortMethod called! +trampoline_Java_Main_shortMethod called! +trampoline_Java_Main_shortMethod called! +Getting trampoline for Java_Main_booleanMethod with shorty ZZZZZZZZZZZ. +trampoline_Java_Main_booleanMethod called! +trampoline_Java_Main_booleanMethod called! +Getting trampoline for Java_Main_charMethod with shorty CCCCCCCCCCC. +trampoline_Java_Main_charMethod called! +trampoline_Java_Main_charMethod called! +trampoline_Java_Main_charMethod called! +trampoline_Java_Main_charMethod called! +trampoline_Java_Main_charMethod called! +trampoline_Java_Main_charMethod called! +trampoline_Java_Main_charMethod called! +trampoline_Java_Main_charMethod called! diff --git a/test/115-native-bridge/nativebridge.cc b/test/115-native-bridge/nativebridge.cc index bd3ae13a3..82211a557 100644 --- a/test/115-native-bridge/nativebridge.cc +++ b/test/115-native-bridge/nativebridge.cc @@ -44,13 +44,192 @@ struct NativeBridgeCallbacks { bool (*isSupported)(const char* libpath); }; +struct NativeBridgeMethod { + const char* name; + const char* signature; + bool static_method; + void* fnPtr; + void* trampoline; +}; + +static NativeBridgeMethod* find_native_bridge_method(const char *name); +static NativeBridgeArtCallbacks* gNativeBridgeArtCallbacks; + +static jint trampoline_JNI_OnLoad(JavaVM* vm, void* reserved) { + JNIEnv* env = nullptr; + typedef jint (*FnPtr_t)(JavaVM*, void*); + FnPtr_t fnPtr = reinterpret_cast(find_native_bridge_method("JNI_OnLoad")->fnPtr); + + vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6); + if (env == nullptr) { + return 0; + } + + jclass klass = env->FindClass("Main"); + if (klass != nullptr) { + int i, count1, count2; + count1 = gNativeBridgeArtCallbacks->getNativeMethodCount(env, klass); + std::unique_ptr methods(new JNINativeMethod[count1]); + if (methods == nullptr) { + return 0; + } + count2 = gNativeBridgeArtCallbacks->getNativeMethods(env, klass, methods.get(), count1); + if (count1 == count2) { + printf("Test ART callbacks: all JNI function number is %d.\n", count1); + } + + for (i = 0; i < count1; i++) { + NativeBridgeMethod* nb_method = find_native_bridge_method(methods[i].name); + if (nb_method != nullptr) { + jmethodID mid = nullptr; + if (nb_method->static_method) { + mid = env->GetStaticMethodID(klass, methods[i].name, nb_method->signature); + } else { + mid = env->GetMethodID(klass, methods[i].name, nb_method->signature); + } + if (mid != nullptr) { + const char* shorty = gNativeBridgeArtCallbacks->getMethodShorty(env, mid); + if (strcmp(shorty, methods[i].signature) == 0) { + printf(" name:%s, signature:%s, shorty:%s.\n", + methods[i].name, nb_method->signature, shorty); + } + } + } + } + methods.release(); + } + + printf("%s called!\n", __FUNCTION__); + return fnPtr(vm, reserved); +} + +static void trampoline_Java_Main_testFindClassOnAttachedNativeThread(JNIEnv* env, + jclass klass) { + typedef void (*FnPtr_t)(JNIEnv*, jclass); + FnPtr_t fnPtr = reinterpret_cast + (find_native_bridge_method("testFindClassOnAttachedNativeThread")->fnPtr); + printf("%s called!\n", __FUNCTION__); + return fnPtr(env, klass); +} + +static void trampoline_Java_Main_testFindFieldOnAttachedNativeThreadNative(JNIEnv* env, + jclass klass) { + typedef void (*FnPtr_t)(JNIEnv*, jclass); + FnPtr_t fnPtr = reinterpret_cast + (find_native_bridge_method("testFindFieldOnAttachedNativeThreadNative")->fnPtr); + printf("%s called!\n", __FUNCTION__); + return fnPtr(env, klass); +} + +static void trampoline_Java_Main_testCallStaticVoidMethodOnSubClassNative(JNIEnv* env, + jclass klass) { + typedef void (*FnPtr_t)(JNIEnv*, jclass); + FnPtr_t fnPtr = reinterpret_cast + (find_native_bridge_method("testCallStaticVoidMethodOnSubClassNative")->fnPtr); + printf("%s called!\n", __FUNCTION__); + return fnPtr(env, klass); +} + +static jobject trampoline_Java_Main_testGetMirandaMethodNative(JNIEnv* env, jclass klass) { + typedef jobject (*FnPtr_t)(JNIEnv*, jclass); + FnPtr_t fnPtr = reinterpret_cast + (find_native_bridge_method("testGetMirandaMethodNative")->fnPtr); + printf("%s called!\n", __FUNCTION__); + return fnPtr(env, klass); +} +static void trampoline_Java_Main_testZeroLengthByteBuffers(JNIEnv* env, jclass klass) { + typedef void (*FnPtr_t)(JNIEnv*, jclass); + FnPtr_t fnPtr = reinterpret_cast + (find_native_bridge_method("testZeroLengthByteBuffers")->fnPtr); + printf("%s called!\n", __FUNCTION__); + return fnPtr(env, klass); +} + +static jbyte trampoline_Java_Main_byteMethod(JNIEnv* env, jclass klass, jbyte b1, jbyte b2, + jbyte b3, jbyte b4, jbyte b5, jbyte b6, + jbyte b7, jbyte b8, jbyte b9, jbyte b10) { + typedef jbyte (*FnPtr_t)(JNIEnv*, jclass, jbyte, jbyte, jbyte, jbyte, jbyte, + jbyte, jbyte, jbyte, jbyte, jbyte); + FnPtr_t fnPtr = reinterpret_cast(find_native_bridge_method("byteMethod")->fnPtr); + printf("%s called!\n", __FUNCTION__); + return fnPtr(env, klass, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10); +} -static std::vector symbols; +static jshort trampoline_Java_Main_shortMethod(JNIEnv* env, jclass klass, jshort s1, jshort s2, + jshort s3, jshort s4, jshort s5, jshort s6, + jshort s7, jshort s8, jshort s9, jshort s10) { + typedef jshort (*FnPtr_t)(JNIEnv*, jclass, jshort, jshort, jshort, jshort, jshort, + jshort, jshort, jshort, jshort, jshort); + FnPtr_t fnPtr = reinterpret_cast(find_native_bridge_method("shortMethod")->fnPtr); + printf("%s called!\n", __FUNCTION__); + return fnPtr(env, klass, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10); +} + +static jboolean trampoline_Java_Main_booleanMethod(JNIEnv* env, jclass klass, jboolean b1, + jboolean b2, jboolean b3, jboolean b4, + jboolean b5, jboolean b6, jboolean b7, + jboolean b8, jboolean b9, jboolean b10) { + typedef jboolean (*FnPtr_t)(JNIEnv*, jclass, jboolean, jboolean, jboolean, jboolean, jboolean, + jboolean, jboolean, jboolean, jboolean, jboolean); + FnPtr_t fnPtr = reinterpret_cast(find_native_bridge_method("booleanMethod")->fnPtr); + printf("%s called!\n", __FUNCTION__); + return fnPtr(env, klass, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10); +} + +static jchar trampoline_Java_Main_charMethod(JNIEnv* env, jclass klass, jchar c1, jchar c2, + jchar c3, jchar c4, jchar c5, jchar c6, + jchar c7, jchar c8, jchar c9, jchar c10) { + typedef jchar (*FnPtr_t)(JNIEnv*, jclass, jchar, jchar, jchar, jchar, jchar, + jchar, jchar, jchar, jchar, jchar); + FnPtr_t fnPtr = reinterpret_cast(find_native_bridge_method("charMethod")->fnPtr); + printf("%s called!\n", __FUNCTION__); + return fnPtr(env, klass, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10); +} + +NativeBridgeMethod gNativeBridgeMethods[] = { + { "JNI_OnLoad", "", true, nullptr, + reinterpret_cast(trampoline_JNI_OnLoad) }, + { "booleanMethod", "(ZZZZZZZZZZ)Z", true, nullptr, + reinterpret_cast(trampoline_Java_Main_booleanMethod) }, + { "byteMethod", "(BBBBBBBBBB)B", true, nullptr, + reinterpret_cast(trampoline_Java_Main_byteMethod) }, + { "charMethod", "(CCCCCCCCCC)C", true, nullptr, + reinterpret_cast(trampoline_Java_Main_charMethod) }, + { "shortMethod", "(SSSSSSSSSS)S", true, nullptr, + reinterpret_cast(trampoline_Java_Main_shortMethod) }, + { "testCallStaticVoidMethodOnSubClassNative", "()V", true, nullptr, + reinterpret_cast(trampoline_Java_Main_testCallStaticVoidMethodOnSubClassNative) }, + { "testFindClassOnAttachedNativeThread", "()V", true, nullptr, + reinterpret_cast(trampoline_Java_Main_testFindClassOnAttachedNativeThread) }, + { "testFindFieldOnAttachedNativeThreadNative", "()V", true, nullptr, + reinterpret_cast(trampoline_Java_Main_testFindFieldOnAttachedNativeThreadNative) }, + { "testGetMirandaMethodNative", "()Ljava/lang/reflect/Method;", true, nullptr, + reinterpret_cast(trampoline_Java_Main_testGetMirandaMethodNative) }, + { "testZeroLengthByteBuffers", "()V", true, nullptr, + reinterpret_cast(trampoline_Java_Main_testZeroLengthByteBuffers) }, +}; + +static NativeBridgeMethod* find_native_bridge_method(const char *name) { + const char* pname = name; + if (strncmp(name, "Java_Main_", 10) == 0) { + pname += 10; + } + + for (size_t i = 0; i < sizeof(gNativeBridgeMethods) / sizeof(gNativeBridgeMethods[0]); i++) { + if (strcmp(pname, gNativeBridgeMethods[i].name) == 0) { + return &gNativeBridgeMethods[i]; + } + } + return nullptr; +} // NativeBridgeCallbacks implementations extern "C" bool native_bridge_initialize(NativeBridgeArtCallbacks* art_cbs) { - printf("Native bridge initialized.\n"); + if (art_cbs != nullptr) { + gNativeBridgeArtCallbacks = art_cbs; + printf("Native bridge initialized.\n"); + } return true; } @@ -80,17 +259,16 @@ extern "C" void* native_bridge_loadLibrary(const char* libpath, int flag) { extern "C" void* native_bridge_getTrampoline(void* handle, const char* name, const char* shorty, uint32_t len) { - printf("Getting trampoline.\n"); + printf("Getting trampoline for %s with shorty %s.\n", name, shorty); // The name here is actually the JNI name, so we can directly do the lookup. void* sym = dlsym(handle, name); - if (sym != nullptr) { - symbols.push_back(sym); - } + NativeBridgeMethod* method = find_native_bridge_method(name); + if (method == nullptr) + return nullptr; + method->fnPtr = sym; - // As libarttest is the same arch as the host, we can actually directly use the code and do not - // need to create a trampoline. :-) - return sym; + return method->trampoline; } extern "C" bool native_bridge_isSupported(const char* libpath) { @@ -109,6 +287,3 @@ NativeBridgeCallbacks NativeBridgeItf { .getTrampoline = &native_bridge_getTrampoline, .isSupported = &native_bridge_isSupported }; - - -