nativebridge.cc revision 93de4273d72a2558a7b3423547b5074cd76c5796
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
29struct NativeBridgeMethod {
30  const char* name;
31  const char* signature;
32  bool static_method;
33  void* fnPtr;
34  void* trampoline;
35};
36
37static NativeBridgeMethod* find_native_bridge_method(const char *name);
38static const android::NativeBridgeRuntimeCallbacks* gNativeBridgeArtCallbacks;
39
40static 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
88static 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
97static 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
106static 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
115static 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
123static 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
131static 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
141static 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
151static 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
162static 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
172NativeBridgeMethod 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
195static 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
210extern "C" bool native_bridge_initialize(const android::NativeBridgeRuntimeCallbacks* art_cbs) {
211  if (art_cbs != nullptr) {
212    gNativeBridgeArtCallbacks = art_cbs;
213    printf("Native bridge initialized.\n");
214  }
215  return true;
216}
217
218extern "C" void* native_bridge_loadLibrary(const char* libpath, int flag) {
219  size_t len = strlen(libpath);
220  char* tmp = new char[len + 10];
221  strncpy(tmp, libpath, len);
222  tmp[len - 3] = '2';
223  tmp[len - 2] = '.';
224  tmp[len - 1] = 's';
225  tmp[len] = 'o';
226  tmp[len + 1] = 0;
227  void* handle = dlopen(tmp, flag);
228  delete[] tmp;
229
230  if (handle == nullptr) {
231    printf("Handle = nullptr!\n");
232    printf("Was looking for %s.\n", libpath);
233    printf("Error = %s.\n", dlerror());
234    char cwd[1024];
235    if (getcwd(cwd, sizeof(cwd)) != nullptr) {
236      printf("Current working dir: %s\n", cwd);
237    }
238  }
239  return handle;
240}
241
242extern "C" void* native_bridge_getTrampoline(void* handle, const char* name, const char* shorty,
243                                             uint32_t len) {
244  printf("Getting trampoline for %s with shorty %s.\n", name, shorty);
245
246  // The name here is actually the JNI name, so we can directly do the lookup.
247  void* sym = dlsym(handle, name);
248  NativeBridgeMethod* method = find_native_bridge_method(name);
249  if (method == nullptr)
250    return nullptr;
251  method->fnPtr = sym;
252
253  return method->trampoline;
254}
255
256extern "C" bool native_bridge_isSupported(const char* libpath) {
257  printf("Checking for support.\n");
258
259  if (libpath == nullptr) {
260    return false;
261  }
262  // We don't want to hijack javacore. So we should get libarttest...
263  return strcmp(libpath, "libjavacore.so") != 0;
264}
265
266// "NativeBridgeItf" is effectively an API (it is the name of the symbol that will be loaded
267// by the native bridge library).
268android::NativeBridgeCallbacks NativeBridgeItf {
269  .initialize = &native_bridge_initialize,
270  .loadLibrary = &native_bridge_loadLibrary,
271  .getTrampoline = &native_bridge_getTrampoline,
272  .isSupported = &native_bridge_isSupported
273};
274