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 <jni.h>
     22 #include <stdlib.h>
     23 #include <signal.h>
     24 #include <vector>
     25 
     26 #include "stdio.h"
     27 #include "unistd.h"
     28 #include "sys/stat.h"
     29 
     30 #include "base/macros.h"
     31 #include "nativebridge/native_bridge.h"
     32 
     33 struct NativeBridgeMethod {
     34   const char* name;
     35   const char* signature;
     36   bool static_method;
     37   void* fnPtr;
     38   void* trampoline;
     39 };
     40 
     41 static NativeBridgeMethod* find_native_bridge_method(const char *name);
     42 static const android::NativeBridgeRuntimeCallbacks* gNativeBridgeArtCallbacks;
     43 
     44 static jint trampoline_JNI_OnLoad(JavaVM* vm, void* reserved) {
     45   JNIEnv* env = nullptr;
     46   typedef jint (*FnPtr_t)(JavaVM*, void*);
     47   FnPtr_t fnPtr = reinterpret_cast<FnPtr_t>(find_native_bridge_method("JNI_OnLoad")->fnPtr);
     48 
     49   vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6);
     50   if (env == nullptr) {
     51     return 0;
     52   }
     53 
     54   jclass klass = env->FindClass("Main");
     55   if (klass != nullptr) {
     56     int i, count1, count2;
     57     count1 = gNativeBridgeArtCallbacks->getNativeMethodCount(env, klass);
     58     std::unique_ptr<JNINativeMethod[]> methods(new JNINativeMethod[count1]);
     59     if (methods == nullptr) {
     60       return 0;
     61     }
     62     count2 = gNativeBridgeArtCallbacks->getNativeMethods(env, klass, methods.get(), count1);
     63     if (count1 == count2) {
     64       printf("Test ART callbacks: all JNI function number is %d.\n", count1);
     65     }
     66 
     67     for (i = 0; i < count1; i++) {
     68       NativeBridgeMethod* nb_method = find_native_bridge_method(methods[i].name);
     69       if (nb_method != nullptr) {
     70         jmethodID mid = nullptr;
     71         if (nb_method->static_method) {
     72           mid = env->GetStaticMethodID(klass, methods[i].name, nb_method->signature);
     73         } else {
     74           mid = env->GetMethodID(klass, methods[i].name, nb_method->signature);
     75         }
     76         if (mid != nullptr) {
     77           const char* shorty = gNativeBridgeArtCallbacks->getMethodShorty(env, mid);
     78           if (strcmp(shorty, methods[i].signature) == 0) {
     79             printf("    name:%s, signature:%s, shorty:%s.\n",
     80                    methods[i].name, nb_method->signature, shorty);
     81           }
     82         }
     83       }
     84     }
     85     methods.release();
     86   }
     87 
     88   printf("%s called!\n", __FUNCTION__);
     89   return fnPtr(vm, reserved);
     90 }
     91 
     92 static void trampoline_Java_Main_testFindClassOnAttachedNativeThread(JNIEnv* env,
     93                                                                      jclass klass) {
     94   typedef void (*FnPtr_t)(JNIEnv*, jclass);
     95   FnPtr_t fnPtr = reinterpret_cast<FnPtr_t>
     96     (find_native_bridge_method("testFindClassOnAttachedNativeThread")->fnPtr);
     97   printf("%s called!\n", __FUNCTION__);
     98   return fnPtr(env, klass);
     99 }
    100 
    101 static void trampoline_Java_Main_testFindFieldOnAttachedNativeThreadNative(JNIEnv* env,
    102                                                                            jclass klass) {
    103   typedef void (*FnPtr_t)(JNIEnv*, jclass);
    104   FnPtr_t fnPtr = reinterpret_cast<FnPtr_t>
    105     (find_native_bridge_method("testFindFieldOnAttachedNativeThreadNative")->fnPtr);
    106   printf("%s called!\n", __FUNCTION__);
    107   return fnPtr(env, klass);
    108 }
    109 
    110 static void trampoline_Java_Main_testCallStaticVoidMethodOnSubClassNative(JNIEnv* env,
    111                                                                           jclass klass) {
    112   typedef void (*FnPtr_t)(JNIEnv*, jclass);
    113   FnPtr_t fnPtr = reinterpret_cast<FnPtr_t>
    114     (find_native_bridge_method("testCallStaticVoidMethodOnSubClassNative")->fnPtr);
    115   printf("%s called!\n", __FUNCTION__);
    116   return fnPtr(env, klass);
    117 }
    118 
    119 static jobject trampoline_Java_Main_testGetMirandaMethodNative(JNIEnv* env, jclass klass) {
    120   typedef jobject (*FnPtr_t)(JNIEnv*, jclass);
    121   FnPtr_t fnPtr = reinterpret_cast<FnPtr_t>
    122     (find_native_bridge_method("testGetMirandaMethodNative")->fnPtr);
    123   printf("%s called!\n", __FUNCTION__);
    124   return fnPtr(env, klass);
    125 }
    126 
    127 static void trampoline_Java_Main_testNewStringObject(JNIEnv* env, jclass klass) {
    128   typedef void (*FnPtr_t)(JNIEnv*, jclass);
    129   FnPtr_t fnPtr = reinterpret_cast<FnPtr_t>
    130     (find_native_bridge_method("testNewStringObject")->fnPtr);
    131   printf("%s called!\n", __FUNCTION__);
    132   return fnPtr(env, klass);
    133 }
    134 
    135 static void trampoline_Java_Main_testZeroLengthByteBuffers(JNIEnv* env, jclass klass) {
    136   typedef void (*FnPtr_t)(JNIEnv*, jclass);
    137   FnPtr_t fnPtr = reinterpret_cast<FnPtr_t>
    138     (find_native_bridge_method("testZeroLengthByteBuffers")->fnPtr);
    139   printf("%s called!\n", __FUNCTION__);
    140   return fnPtr(env, klass);
    141 }
    142 
    143 static jbyte trampoline_Java_Main_byteMethod(JNIEnv* env, jclass klass, jbyte b1, jbyte b2,
    144                                              jbyte b3, jbyte b4, jbyte b5, jbyte b6,
    145                                              jbyte b7, jbyte b8, jbyte b9, jbyte b10) {
    146   typedef jbyte (*FnPtr_t)(JNIEnv*, jclass, jbyte, jbyte, jbyte, jbyte, jbyte,
    147                            jbyte, jbyte, jbyte, jbyte, jbyte);
    148   FnPtr_t fnPtr = reinterpret_cast<FnPtr_t>(find_native_bridge_method("byteMethod")->fnPtr);
    149   printf("%s called!\n", __FUNCTION__);
    150   return fnPtr(env, klass, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10);
    151 }
    152 
    153 static jshort trampoline_Java_Main_shortMethod(JNIEnv* env, jclass klass, jshort s1, jshort s2,
    154                                                jshort s3, jshort s4, jshort s5, jshort s6,
    155                                                jshort s7, jshort s8, jshort s9, jshort s10) {
    156   typedef jshort (*FnPtr_t)(JNIEnv*, jclass, jshort, jshort, jshort, jshort, jshort,
    157                             jshort, jshort, jshort, jshort, jshort);
    158   FnPtr_t fnPtr = reinterpret_cast<FnPtr_t>(find_native_bridge_method("shortMethod")->fnPtr);
    159   printf("%s called!\n", __FUNCTION__);
    160   return fnPtr(env, klass, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10);
    161 }
    162 
    163 static jboolean trampoline_Java_Main_booleanMethod(JNIEnv* env, jclass klass, jboolean b1,
    164                                                    jboolean b2, jboolean b3, jboolean b4,
    165                                                    jboolean b5, jboolean b6, jboolean b7,
    166                                                    jboolean b8, jboolean b9, jboolean b10) {
    167   typedef jboolean (*FnPtr_t)(JNIEnv*, jclass, jboolean, jboolean, jboolean, jboolean, jboolean,
    168                               jboolean, jboolean, jboolean, jboolean, jboolean);
    169   FnPtr_t fnPtr = reinterpret_cast<FnPtr_t>(find_native_bridge_method("booleanMethod")->fnPtr);
    170   printf("%s called!\n", __FUNCTION__);
    171   return fnPtr(env, klass, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10);
    172 }
    173 
    174 static jchar trampoline_Java_Main_charMethod(JNIEnv* env, jclass klass, jchar c1, jchar c2,
    175                                              jchar c3, jchar c4, jchar c5, jchar c6,
    176                                              jchar c7, jchar c8, jchar c9, jchar c10) {
    177   typedef jchar (*FnPtr_t)(JNIEnv*, jclass, jchar, jchar, jchar, jchar, jchar,
    178                            jchar, jchar, jchar, jchar, jchar);
    179   FnPtr_t fnPtr = reinterpret_cast<FnPtr_t>(find_native_bridge_method("charMethod")->fnPtr);
    180   printf("%s called!\n", __FUNCTION__);
    181   return fnPtr(env, klass, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10);
    182 }
    183 
    184 // This code is adapted from 004-SignalTest and causes a segfault.
    185 char *go_away_compiler = nullptr;
    186 
    187 [[ noreturn ]] static void test_sigaction_handler(int sig ATTRIBUTE_UNUSED,
    188                                                   siginfo_t* info ATTRIBUTE_UNUSED,
    189                                                   void* context ATTRIBUTE_UNUSED) {
    190   printf("Should not reach the test sigaction handler.");
    191   abort();
    192 }
    193 
    194 static jint trampoline_Java_Main_testSignal(JNIEnv*, jclass) {
    195   // Install the sigaction handler above, which should *not* be reached as the native-bridge
    196   // handler should be called first. Note: we won't chain at all, if we ever get here, we'll die.
    197   struct sigaction tmp;
    198   sigemptyset(&tmp.sa_mask);
    199   tmp.sa_sigaction = test_sigaction_handler;
    200 #if !defined(__APPLE__) && !defined(__mips__)
    201   tmp.sa_restorer = nullptr;
    202 #endif
    203 
    204   // Test segv
    205   sigaction(SIGSEGV, &tmp, nullptr);
    206 #if defined(__arm__) || defined(__i386__) || defined(__aarch64__)
    207   *go_away_compiler = 'a';
    208 #elif defined(__x86_64__)
    209   // Cause a SEGV using an instruction known to be 2 bytes long to account for hardcoded jump
    210   // in the signal handler
    211   asm volatile("movl $0, %%eax;" "movb %%ah, (%%rax);" : : : "%eax");
    212 #else
    213   // On other architectures we simulate SEGV.
    214   kill(getpid(), SIGSEGV);
    215 #endif
    216 
    217   // Test sigill
    218   sigaction(SIGILL, &tmp, nullptr);
    219   kill(getpid(), SIGILL);
    220 
    221   return 1234;
    222 }
    223 
    224 NativeBridgeMethod gNativeBridgeMethods[] = {
    225   { "JNI_OnLoad", "", true, nullptr,
    226     reinterpret_cast<void*>(trampoline_JNI_OnLoad) },
    227   { "booleanMethod", "(ZZZZZZZZZZ)Z", true, nullptr,
    228     reinterpret_cast<void*>(trampoline_Java_Main_booleanMethod) },
    229   { "byteMethod", "(BBBBBBBBBB)B", true, nullptr,
    230     reinterpret_cast<void*>(trampoline_Java_Main_byteMethod) },
    231   { "charMethod", "(CCCCCCCCCC)C", true, nullptr,
    232     reinterpret_cast<void*>(trampoline_Java_Main_charMethod) },
    233   { "shortMethod", "(SSSSSSSSSS)S", true, nullptr,
    234     reinterpret_cast<void*>(trampoline_Java_Main_shortMethod) },
    235   { "testCallStaticVoidMethodOnSubClassNative", "()V", true, nullptr,
    236     reinterpret_cast<void*>(trampoline_Java_Main_testCallStaticVoidMethodOnSubClassNative) },
    237   { "testFindClassOnAttachedNativeThread", "()V", true, nullptr,
    238     reinterpret_cast<void*>(trampoline_Java_Main_testFindClassOnAttachedNativeThread) },
    239   { "testFindFieldOnAttachedNativeThreadNative", "()V", true, nullptr,
    240     reinterpret_cast<void*>(trampoline_Java_Main_testFindFieldOnAttachedNativeThreadNative) },
    241   { "testGetMirandaMethodNative", "()Ljava/lang/reflect/Method;", true, nullptr,
    242     reinterpret_cast<void*>(trampoline_Java_Main_testGetMirandaMethodNative) },
    243   { "testNewStringObject", "()V", true, nullptr,
    244     reinterpret_cast<void*>(trampoline_Java_Main_testNewStringObject) },
    245   { "testZeroLengthByteBuffers", "()V", true, nullptr,
    246     reinterpret_cast<void*>(trampoline_Java_Main_testZeroLengthByteBuffers) },
    247   { "testSignal", "()I", true, nullptr,
    248     reinterpret_cast<void*>(trampoline_Java_Main_testSignal) },
    249 };
    250 
    251 static NativeBridgeMethod* find_native_bridge_method(const char *name) {
    252   const char* pname = name;
    253   if (strncmp(name, "Java_Main_", 10) == 0) {
    254     pname += 10;
    255   }
    256 
    257   for (size_t i = 0; i < sizeof(gNativeBridgeMethods) / sizeof(gNativeBridgeMethods[0]); i++) {
    258     if (strcmp(pname, gNativeBridgeMethods[i].name) == 0) {
    259       return &gNativeBridgeMethods[i];
    260     }
    261   }
    262   return nullptr;
    263 }
    264 
    265 // NativeBridgeCallbacks implementations
    266 extern "C" bool native_bridge_initialize(const android::NativeBridgeRuntimeCallbacks* art_cbs,
    267                                          const char* app_code_cache_dir,
    268                                          const char* isa ATTRIBUTE_UNUSED) {
    269   struct stat st;
    270   if (app_code_cache_dir != nullptr) {
    271     if (stat(app_code_cache_dir, &st) == 0) {
    272       if (!S_ISDIR(st.st_mode)) {
    273         printf("Code cache is not a directory.\n");
    274       }
    275     } else {
    276       perror("Error when stat-ing the code_cache:");
    277     }
    278   }
    279 
    280   if (art_cbs != nullptr) {
    281     gNativeBridgeArtCallbacks = art_cbs;
    282     printf("Native bridge initialized.\n");
    283   }
    284   return true;
    285 }
    286 
    287 extern "C" void* native_bridge_loadLibrary(const char* libpath, int flag) {
    288   size_t len = strlen(libpath);
    289   char* tmp = new char[len + 10];
    290   strncpy(tmp, libpath, len);
    291   tmp[len - 3] = '2';
    292   tmp[len - 2] = '.';
    293   tmp[len - 1] = 's';
    294   tmp[len] = 'o';
    295   tmp[len + 1] = 0;
    296   void* handle = dlopen(tmp, flag);
    297   delete[] tmp;
    298 
    299   if (handle == nullptr) {
    300     printf("Handle = nullptr!\n");
    301     printf("Was looking for %s.\n", libpath);
    302     printf("Error = %s.\n", dlerror());
    303     char cwd[1024];
    304     if (getcwd(cwd, sizeof(cwd)) != nullptr) {
    305       printf("Current working dir: %s\n", cwd);
    306     }
    307   }
    308   return handle;
    309 }
    310 
    311 extern "C" void* native_bridge_getTrampoline(void* handle, const char* name, const char* shorty,
    312                                              uint32_t len ATTRIBUTE_UNUSED) {
    313   printf("Getting trampoline for %s with shorty %s.\n", name, shorty);
    314 
    315   // The name here is actually the JNI name, so we can directly do the lookup.
    316   void* sym = dlsym(handle, name);
    317   NativeBridgeMethod* method = find_native_bridge_method(name);
    318   if (method == nullptr)
    319     return nullptr;
    320   method->fnPtr = sym;
    321 
    322   return method->trampoline;
    323 }
    324 
    325 extern "C" bool native_bridge_isSupported(const char* libpath) {
    326   printf("Checking for support.\n");
    327 
    328   if (libpath == nullptr) {
    329     return false;
    330   }
    331   // We don't want to hijack javacore. So we should get libarttest...
    332   return strcmp(libpath, "libjavacore.so") != 0;
    333 }
    334 
    335 namespace android {
    336 
    337 // Environment values required by the apps running with native bridge.
    338 struct NativeBridgeRuntimeValues {
    339   const char* os_arch;
    340   const char* cpu_abi;
    341   const char* cpu_abi2;
    342   const char* *supported_abis;
    343   int32_t abi_count;
    344 };
    345 
    346 }  // namespace android
    347 
    348 const char* supported_abis[] = {
    349     "supported1", "supported2", "supported3"
    350 };
    351 
    352 const struct android::NativeBridgeRuntimeValues nb_env {
    353     .os_arch = "os.arch",
    354     .cpu_abi = "cpu_abi",
    355     .cpu_abi2 = "cpu_abi2",
    356     .supported_abis = supported_abis,
    357     .abi_count = 3
    358 };
    359 
    360 extern "C" const struct android::NativeBridgeRuntimeValues* native_bridge_getAppEnv(
    361     const char* abi) {
    362   printf("Checking for getEnvValues.\n");
    363 
    364   if (abi == nullptr) {
    365     return nullptr;
    366   }
    367 
    368   return &nb_env;
    369 }
    370 
    371 // v2 parts.
    372 
    373 extern "C" bool nb_is_compatible(uint32_t bridge_version ATTRIBUTE_UNUSED) {
    374   return true;
    375 }
    376 
    377 #if defined(__i386__) || defined(__x86_64__)
    378 #if defined(__APPLE__)
    379 #define ucontext __darwin_ucontext
    380 
    381 #if defined(__x86_64__)
    382 // 64 bit mac build.
    383 #define CTX_EIP uc_mcontext->__ss.__rip
    384 #else
    385 // 32 bit mac build.
    386 #define CTX_EIP uc_mcontext->__ss.__eip
    387 #endif
    388 
    389 #elif defined(__x86_64__)
    390 // 64 bit linux build.
    391 #define CTX_EIP uc_mcontext.gregs[REG_RIP]
    392 #else
    393 // 32 bit linux build.
    394 #define CTX_EIP uc_mcontext.gregs[REG_EIP]
    395 #endif
    396 #endif
    397 
    398 static bool cannot_be_blocked(int signum) {
    399   // These two sigs cannot be blocked anywhere.
    400   if ((signum == SIGKILL) || (signum == SIGSTOP)) {
    401       return true;
    402   }
    403 
    404   // The invalid rt_sig cannot be blocked.
    405   if (((signum >= 32) && (signum < SIGRTMIN)) || (signum > SIGRTMAX)) {
    406       return true;
    407   }
    408 
    409   return false;
    410 }
    411 
    412 // A dummy special handler, continueing after the faulting location. This code comes from
    413 // 004-SignalTest.
    414 static bool nb_signalhandler(int sig, siginfo_t* info ATTRIBUTE_UNUSED, void* context) {
    415   printf("NB signal handler with signal %d.\n", sig);
    416   if (sig == SIGSEGV) {
    417 #if defined(__arm__)
    418     struct ucontext *uc = reinterpret_cast<struct ucontext*>(context);
    419     struct sigcontext *sc = reinterpret_cast<struct sigcontext*>(&uc->uc_mcontext);
    420     sc->arm_pc += 2;          // Skip instruction causing segv & sigill.
    421 #elif defined(__aarch64__)
    422     struct ucontext *uc = reinterpret_cast<struct ucontext*>(context);
    423     struct sigcontext *sc = reinterpret_cast<struct sigcontext*>(&uc->uc_mcontext);
    424     sc->pc += 4;          // Skip instruction causing segv & sigill.
    425 #elif defined(__i386__)
    426     struct ucontext *uc = reinterpret_cast<struct ucontext*>(context);
    427     uc->CTX_EIP += 3;
    428 #elif defined(__x86_64__)
    429     struct ucontext *uc = reinterpret_cast<struct ucontext*>(context);
    430     uc->CTX_EIP += 2;
    431 #else
    432     UNUSED(context);
    433 #endif
    434   }
    435 
    436   // Before invoking this handler, all other unclaimed signals must be blocked.
    437   // We're trying to check the signal mask to verify its status here.
    438   sigset_t tmpset;
    439   sigemptyset(&tmpset);
    440   sigprocmask(SIG_SETMASK, nullptr, &tmpset);
    441   int other_claimed = (sig == SIGSEGV) ? SIGILL : SIGSEGV;
    442   for (int signum = 0; signum < NSIG; ++signum) {
    443     if (cannot_be_blocked(signum)) {
    444         continue;
    445     } else if ((sigismember(&tmpset, signum)) && (signum == other_claimed)) {
    446       printf("ERROR: The claimed signal %d is blocked\n", signum);
    447     } else if ((!sigismember(&tmpset, signum)) && (signum != other_claimed)) {
    448       printf("ERROR: The unclaimed signal %d is not blocked\n", signum);
    449     }
    450   }
    451 
    452   // We handled this...
    453   return true;
    454 }
    455 
    456 static ::android::NativeBridgeSignalHandlerFn native_bridge_get_signal_handler(int signal) {
    457   // Test segv for already claimed signal, and sigill for not claimed signal
    458   if ((signal == SIGSEGV) || (signal == SIGILL)) {
    459     return &nb_signalhandler;
    460   }
    461   return nullptr;
    462 }
    463 
    464 
    465 // "NativeBridgeItf" is effectively an API (it is the name of the symbol that will be loaded
    466 // by the native bridge library).
    467 android::NativeBridgeCallbacks NativeBridgeItf {
    468   .version = 2,
    469   .initialize = &native_bridge_initialize,
    470   .loadLibrary = &native_bridge_loadLibrary,
    471   .getTrampoline = &native_bridge_getTrampoline,
    472   .isSupported = &native_bridge_isSupported,
    473   .getAppEnv = &native_bridge_getAppEnv,
    474   .isCompatibleWith = &nb_is_compatible,
    475   .getSignalHandler = &native_bridge_get_signal_handler
    476 };
    477