Home | History | Annotate | Download | only in 115-native-bridge
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 // A simple implementation of the native-bridge interface.
     18 
     19 #include <algorithm>
     20 #include <dlfcn.h>
     21 #include <vector>
     22 
     23 #include "jni.h"
     24 #include "stdio.h"
     25 #include "unistd.h"
     26 
     27 #include "nativebridge/native_bridge.h"
     28 
     29 struct NativeBridgeMethod {
     30   const char* name;
     31   const char* signature;
     32   bool static_method;
     33   void* fnPtr;
     34   void* trampoline;
     35 };
     36 
     37 static NativeBridgeMethod* find_native_bridge_method(const char *name);
     38 static const android::NativeBridgeRuntimeCallbacks* gNativeBridgeArtCallbacks;
     39 
     40 static jint trampoline_JNI_OnLoad(JavaVM* vm, void* reserved) {
     41   JNIEnv* env = nullptr;
     42   typedef jint (*FnPtr_t)(JavaVM*, void*);
     43   FnPtr_t fnPtr = reinterpret_cast<FnPtr_t>(find_native_bridge_method("JNI_OnLoad")->fnPtr);
     44 
     45   vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6);
     46   if (env == nullptr) {
     47     return 0;
     48   }
     49 
     50   jclass klass = env->FindClass("Main");
     51   if (klass != nullptr) {
     52     int i, count1, count2;
     53     count1 = gNativeBridgeArtCallbacks->getNativeMethodCount(env, klass);
     54     std::unique_ptr<JNINativeMethod[]> methods(new JNINativeMethod[count1]);
     55     if (methods == nullptr) {
     56       return 0;
     57     }
     58     count2 = gNativeBridgeArtCallbacks->getNativeMethods(env, klass, methods.get(), count1);
     59     if (count1 == count2) {
     60       printf("Test ART callbacks: all JNI function number is %d.\n", count1);
     61     }
     62 
     63     for (i = 0; i < count1; i++) {
     64       NativeBridgeMethod* nb_method = find_native_bridge_method(methods[i].name);
     65       if (nb_method != nullptr) {
     66         jmethodID mid = nullptr;
     67         if (nb_method->static_method) {
     68           mid = env->GetStaticMethodID(klass, methods[i].name, nb_method->signature);
     69         } else {
     70           mid = env->GetMethodID(klass, methods[i].name, nb_method->signature);
     71         }
     72         if (mid != nullptr) {
     73           const char* shorty = gNativeBridgeArtCallbacks->getMethodShorty(env, mid);
     74           if (strcmp(shorty, methods[i].signature) == 0) {
     75             printf("    name:%s, signature:%s, shorty:%s.\n",
     76                    methods[i].name, nb_method->signature, shorty);
     77           }
     78         }
     79       }
     80     }
     81     methods.release();
     82   }
     83 
     84   printf("%s called!\n", __FUNCTION__);
     85   return fnPtr(vm, reserved);
     86 }
     87 
     88 static void trampoline_Java_Main_testFindClassOnAttachedNativeThread(JNIEnv* env,
     89                                                                      jclass klass) {
     90   typedef void (*FnPtr_t)(JNIEnv*, jclass);
     91   FnPtr_t fnPtr = reinterpret_cast<FnPtr_t>
     92     (find_native_bridge_method("testFindClassOnAttachedNativeThread")->fnPtr);
     93   printf("%s called!\n", __FUNCTION__);
     94   return fnPtr(env, klass);
     95 }
     96 
     97 static void trampoline_Java_Main_testFindFieldOnAttachedNativeThreadNative(JNIEnv* env,
     98                                                                            jclass klass) {
     99   typedef void (*FnPtr_t)(JNIEnv*, jclass);
    100   FnPtr_t fnPtr = reinterpret_cast<FnPtr_t>
    101     (find_native_bridge_method("testFindFieldOnAttachedNativeThreadNative")->fnPtr);
    102   printf("%s called!\n", __FUNCTION__);
    103   return fnPtr(env, klass);
    104 }
    105 
    106 static void trampoline_Java_Main_testCallStaticVoidMethodOnSubClassNative(JNIEnv* env,
    107                                                                           jclass klass) {
    108   typedef void (*FnPtr_t)(JNIEnv*, jclass);
    109   FnPtr_t fnPtr = reinterpret_cast<FnPtr_t>
    110     (find_native_bridge_method("testCallStaticVoidMethodOnSubClassNative")->fnPtr);
    111   printf("%s called!\n", __FUNCTION__);
    112   return fnPtr(env, klass);
    113 }
    114 
    115 static jobject trampoline_Java_Main_testGetMirandaMethodNative(JNIEnv* env, jclass klass) {
    116   typedef jobject (*FnPtr_t)(JNIEnv*, jclass);
    117   FnPtr_t fnPtr = reinterpret_cast<FnPtr_t>
    118     (find_native_bridge_method("testGetMirandaMethodNative")->fnPtr);
    119   printf("%s called!\n", __FUNCTION__);
    120   return fnPtr(env, klass);
    121 }
    122 
    123 static void trampoline_Java_Main_testZeroLengthByteBuffers(JNIEnv* env, jclass klass) {
    124   typedef void (*FnPtr_t)(JNIEnv*, jclass);
    125   FnPtr_t fnPtr = reinterpret_cast<FnPtr_t>
    126     (find_native_bridge_method("testZeroLengthByteBuffers")->fnPtr);
    127   printf("%s called!\n", __FUNCTION__);
    128   return fnPtr(env, klass);
    129 }
    130 
    131 static jbyte trampoline_Java_Main_byteMethod(JNIEnv* env, jclass klass, jbyte b1, jbyte b2,
    132                                              jbyte b3, jbyte b4, jbyte b5, jbyte b6,
    133                                              jbyte b7, jbyte b8, jbyte b9, jbyte b10) {
    134   typedef jbyte (*FnPtr_t)(JNIEnv*, jclass, jbyte, jbyte, jbyte, jbyte, jbyte,
    135                            jbyte, jbyte, jbyte, jbyte, jbyte);
    136   FnPtr_t fnPtr = reinterpret_cast<FnPtr_t>(find_native_bridge_method("byteMethod")->fnPtr);
    137   printf("%s called!\n", __FUNCTION__);
    138   return fnPtr(env, klass, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10);
    139 }
    140 
    141 static jshort trampoline_Java_Main_shortMethod(JNIEnv* env, jclass klass, jshort s1, jshort s2,
    142                                                jshort s3, jshort s4, jshort s5, jshort s6,
    143                                                jshort s7, jshort s8, jshort s9, jshort s10) {
    144   typedef jshort (*FnPtr_t)(JNIEnv*, jclass, jshort, jshort, jshort, jshort, jshort,
    145                             jshort, jshort, jshort, jshort, jshort);
    146   FnPtr_t fnPtr = reinterpret_cast<FnPtr_t>(find_native_bridge_method("shortMethod")->fnPtr);
    147   printf("%s called!\n", __FUNCTION__);
    148   return fnPtr(env, klass, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10);
    149 }
    150 
    151 static jboolean trampoline_Java_Main_booleanMethod(JNIEnv* env, jclass klass, jboolean b1,
    152                                                    jboolean b2, jboolean b3, jboolean b4,
    153                                                    jboolean b5, jboolean b6, jboolean b7,
    154                                                    jboolean b8, jboolean b9, jboolean b10) {
    155   typedef jboolean (*FnPtr_t)(JNIEnv*, jclass, jboolean, jboolean, jboolean, jboolean, jboolean,
    156                               jboolean, jboolean, jboolean, jboolean, jboolean);
    157   FnPtr_t fnPtr = reinterpret_cast<FnPtr_t>(find_native_bridge_method("booleanMethod")->fnPtr);
    158   printf("%s called!\n", __FUNCTION__);
    159   return fnPtr(env, klass, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10);
    160 }
    161 
    162 static jchar trampoline_Java_Main_charMethod(JNIEnv* env, jclass klass, jchar c1, jchar c2,
    163                                              jchar c3, jchar c4, jchar c5, jchar c6,
    164                                              jchar c7, jchar c8, jchar c9, jchar c10) {
    165   typedef jchar (*FnPtr_t)(JNIEnv*, jclass, jchar, jchar, jchar, jchar, jchar,
    166                            jchar, jchar, jchar, jchar, jchar);
    167   FnPtr_t fnPtr = reinterpret_cast<FnPtr_t>(find_native_bridge_method("charMethod")->fnPtr);
    168   printf("%s called!\n", __FUNCTION__);
    169   return fnPtr(env, klass, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10);
    170 }
    171 
    172 NativeBridgeMethod gNativeBridgeMethods[] = {
    173   { "JNI_OnLoad", "", true, nullptr,
    174     reinterpret_cast<void*>(trampoline_JNI_OnLoad) },
    175   { "booleanMethod", "(ZZZZZZZZZZ)Z", true, nullptr,
    176     reinterpret_cast<void*>(trampoline_Java_Main_booleanMethod) },
    177   { "byteMethod", "(BBBBBBBBBB)B", true, nullptr,
    178     reinterpret_cast<void*>(trampoline_Java_Main_byteMethod) },
    179   { "charMethod", "(CCCCCCCCCC)C", true, nullptr,
    180     reinterpret_cast<void*>(trampoline_Java_Main_charMethod) },
    181   { "shortMethod", "(SSSSSSSSSS)S", true, nullptr,
    182     reinterpret_cast<void*>(trampoline_Java_Main_shortMethod) },
    183   { "testCallStaticVoidMethodOnSubClassNative", "()V", true, nullptr,
    184     reinterpret_cast<void*>(trampoline_Java_Main_testCallStaticVoidMethodOnSubClassNative) },
    185   { "testFindClassOnAttachedNativeThread", "()V", true, nullptr,
    186     reinterpret_cast<void*>(trampoline_Java_Main_testFindClassOnAttachedNativeThread) },
    187   { "testFindFieldOnAttachedNativeThreadNative", "()V", true, nullptr,
    188     reinterpret_cast<void*>(trampoline_Java_Main_testFindFieldOnAttachedNativeThreadNative) },
    189   { "testGetMirandaMethodNative", "()Ljava/lang/reflect/Method;", true, nullptr,
    190     reinterpret_cast<void*>(trampoline_Java_Main_testGetMirandaMethodNative) },
    191   { "testZeroLengthByteBuffers", "()V", true, nullptr,
    192     reinterpret_cast<void*>(trampoline_Java_Main_testZeroLengthByteBuffers) },
    193 };
    194 
    195 static NativeBridgeMethod* find_native_bridge_method(const char *name) {
    196   const char* pname = name;
    197   if (strncmp(name, "Java_Main_", 10) == 0) {
    198     pname += 10;
    199   }
    200 
    201   for (size_t i = 0; i < sizeof(gNativeBridgeMethods) / sizeof(gNativeBridgeMethods[0]); i++) {
    202     if (strcmp(pname, gNativeBridgeMethods[i].name) == 0) {
    203       return &gNativeBridgeMethods[i];
    204     }
    205   }
    206   return nullptr;
    207 }
    208 
    209 // NativeBridgeCallbacks implementations
    210 extern "C" bool native_bridge_initialize(const android::NativeBridgeRuntimeCallbacks* art_cbs,
    211                                          const char* private_dir, const char* isa) {
    212   if (art_cbs != nullptr) {
    213     gNativeBridgeArtCallbacks = art_cbs;
    214     printf("Native bridge initialized.\n");
    215   }
    216   return true;
    217 }
    218 
    219 extern "C" void* native_bridge_loadLibrary(const char* libpath, int flag) {
    220   size_t len = strlen(libpath);
    221   char* tmp = new char[len + 10];
    222   strncpy(tmp, libpath, len);
    223   tmp[len - 3] = '2';
    224   tmp[len - 2] = '.';
    225   tmp[len - 1] = 's';
    226   tmp[len] = 'o';
    227   tmp[len + 1] = 0;
    228   void* handle = dlopen(tmp, flag);
    229   delete[] tmp;
    230 
    231   if (handle == nullptr) {
    232     printf("Handle = nullptr!\n");
    233     printf("Was looking for %s.\n", libpath);
    234     printf("Error = %s.\n", dlerror());
    235     char cwd[1024];
    236     if (getcwd(cwd, sizeof(cwd)) != nullptr) {
    237       printf("Current working dir: %s\n", cwd);
    238     }
    239   }
    240   return handle;
    241 }
    242 
    243 extern "C" void* native_bridge_getTrampoline(void* handle, const char* name, const char* shorty,
    244                                              uint32_t len) {
    245   printf("Getting trampoline for %s with shorty %s.\n", name, shorty);
    246 
    247   // The name here is actually the JNI name, so we can directly do the lookup.
    248   void* sym = dlsym(handle, name);
    249   NativeBridgeMethod* method = find_native_bridge_method(name);
    250   if (method == nullptr)
    251     return nullptr;
    252   method->fnPtr = sym;
    253 
    254   return method->trampoline;
    255 }
    256 
    257 extern "C" bool native_bridge_isSupported(const char* libpath) {
    258   printf("Checking for support.\n");
    259 
    260   if (libpath == nullptr) {
    261     return false;
    262   }
    263   // We don't want to hijack javacore. So we should get libarttest...
    264   return strcmp(libpath, "libjavacore.so") != 0;
    265 }
    266 
    267 namespace android {
    268 
    269 // Environment values required by the apps running with native bridge.
    270 struct NativeBridgeRuntimeValues {
    271   const char* os_arch;
    272   const char* cpu_abi;
    273   const char* cpu_abi2;
    274   const char* *supported_abis;
    275   int32_t abi_count;
    276 };
    277 
    278 }  // namespace android
    279 
    280 const char* supported_abis[] = {
    281     "supported1", "supported2", "supported3"
    282 };
    283 
    284 const struct android::NativeBridgeRuntimeValues nb_env {
    285     .os_arch = "os.arch",
    286     .cpu_abi = "cpu_abi",
    287     .cpu_abi2 = "cpu_abi2",
    288     .supported_abis = supported_abis,
    289     .abi_count = 3
    290 };
    291 
    292 extern "C" const struct android::NativeBridgeRuntimeValues* native_bridge_getAppEnv(
    293     const char* abi) {
    294   printf("Checking for getEnvValues.\n");
    295 
    296   if (abi == nullptr) {
    297     return nullptr;
    298   }
    299 
    300   return &nb_env;
    301 }
    302 
    303 // "NativeBridgeItf" is effectively an API (it is the name of the symbol that will be loaded
    304 // by the native bridge library).
    305 android::NativeBridgeCallbacks NativeBridgeItf {
    306   .version = 1,
    307   .initialize = &native_bridge_initialize,
    308   .loadLibrary = &native_bridge_loadLibrary,
    309   .getTrampoline = &native_bridge_getTrampoline,
    310   .isSupported = &native_bridge_isSupported,
    311   .getAppEnv = &native_bridge_getAppEnv
    312 };
    313