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