diff options
Diffstat (limited to 'test/115-native-bridge/nativebridge.cc')
| -rw-r--r-- | test/115-native-bridge/nativebridge.cc | 289 |
1 files changed, 289 insertions, 0 deletions
diff --git a/test/115-native-bridge/nativebridge.cc b/test/115-native-bridge/nativebridge.cc new file mode 100644 index 0000000000..268f0bebce --- /dev/null +++ b/test/115-native-bridge/nativebridge.cc @@ -0,0 +1,289 @@ +/* + * Copyright (C) 2014 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. + */ + +// A simple implementation of the native-bridge interface. + +#include <algorithm> +#include <dlfcn.h> +#include <vector> + +#include "jni.h" +#include "stdio.h" +#include "string.h" +#include "unistd.h" + +#include "native_bridge.h" + + +// Native bridge interfaces... + +struct NativeBridgeArtCallbacks { + const char* (*getMethodShorty)(JNIEnv* env, jmethodID mid); + uint32_t (*getNativeMethodCount)(JNIEnv* env, jclass clazz); + uint32_t (*getNativeMethods)(JNIEnv* env, jclass clazz, JNINativeMethod* methods, + uint32_t method_count); +}; + +struct NativeBridgeCallbacks { + bool (*initialize)(NativeBridgeArtCallbacks* art_cbs); + void* (*loadLibrary)(const char* libpath, int flag); + void* (*getTrampoline)(void* handle, const char* name, const char* shorty, uint32_t len); + 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<FnPtr_t>(find_native_bridge_method("JNI_OnLoad")->fnPtr); + + vm->GetEnv(reinterpret_cast<void **>(&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<JNINativeMethod[]> 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<FnPtr_t> + (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<FnPtr_t> + (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<FnPtr_t> + (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<FnPtr_t> + (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<FnPtr_t> + (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<FnPtr_t>(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 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<FnPtr_t>(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<FnPtr_t>(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<FnPtr_t>(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<void*>(trampoline_JNI_OnLoad) }, + { "booleanMethod", "(ZZZZZZZZZZ)Z", true, nullptr, + reinterpret_cast<void*>(trampoline_Java_Main_booleanMethod) }, + { "byteMethod", "(BBBBBBBBBB)B", true, nullptr, + reinterpret_cast<void*>(trampoline_Java_Main_byteMethod) }, + { "charMethod", "(CCCCCCCCCC)C", true, nullptr, + reinterpret_cast<void*>(trampoline_Java_Main_charMethod) }, + { "shortMethod", "(SSSSSSSSSS)S", true, nullptr, + reinterpret_cast<void*>(trampoline_Java_Main_shortMethod) }, + { "testCallStaticVoidMethodOnSubClassNative", "()V", true, nullptr, + reinterpret_cast<void*>(trampoline_Java_Main_testCallStaticVoidMethodOnSubClassNative) }, + { "testFindClassOnAttachedNativeThread", "()V", true, nullptr, + reinterpret_cast<void*>(trampoline_Java_Main_testFindClassOnAttachedNativeThread) }, + { "testFindFieldOnAttachedNativeThreadNative", "()V", true, nullptr, + reinterpret_cast<void*>(trampoline_Java_Main_testFindFieldOnAttachedNativeThreadNative) }, + { "testGetMirandaMethodNative", "()Ljava/lang/reflect/Method;", true, nullptr, + reinterpret_cast<void*>(trampoline_Java_Main_testGetMirandaMethodNative) }, + { "testZeroLengthByteBuffers", "()V", true, nullptr, + reinterpret_cast<void*>(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) { + if (art_cbs != nullptr) { + gNativeBridgeArtCallbacks = art_cbs; + printf("Native bridge initialized.\n"); + } + return true; +} + +extern "C" void* native_bridge_loadLibrary(const char* libpath, int flag) { + size_t len = strlen(libpath); + char* tmp = new char[len + 10]; + strncpy(tmp, libpath, len); + tmp[len - 3] = '2'; + tmp[len - 2] = '.'; + tmp[len - 1] = 's'; + tmp[len] = 'o'; + tmp[len + 1] = 0; + void* handle = dlopen(tmp, flag); + delete[] tmp; + + if (handle == nullptr) { + printf("Handle = nullptr!\n"); + printf("Was looking for %s.\n", libpath); + printf("Error = %s.\n", dlerror()); + char cwd[1024]; + if (getcwd(cwd, sizeof(cwd)) != nullptr) { + printf("Current working dir: %s\n", cwd); + } + } + return handle; +} + +extern "C" void* native_bridge_getTrampoline(void* handle, const char* name, const char* shorty, + uint32_t len) { + 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); + NativeBridgeMethod* method = find_native_bridge_method(name); + if (method == nullptr) + return nullptr; + method->fnPtr = sym; + + return method->trampoline; +} + +extern "C" bool native_bridge_isSupported(const char* libpath) { + printf("Checking for support.\n"); + + if (libpath == nullptr) { + return false; + } + // We don't want to hijack javacore. So we should get libarttest... + return strcmp(libpath, "libjavacore.so") != 0; +} + +NativeBridgeCallbacks NativeBridgeItf { + .initialize = &native_bridge_initialize, + .loadLibrary = &native_bridge_loadLibrary, + .getTrampoline = &native_bridge_getTrampoline, + .isSupported = &native_bridge_isSupported +}; |