nativebridge.cc revision 44a3506627833deb17d21d6a7d51245a5af2c3e9
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
30struct NativeBridgeMethod {
31  const char* name;
32  const char* signature;
33  bool static_method;
34  void* fnPtr;
35  void* trampoline;
36};
37
38static NativeBridgeMethod* find_native_bridge_method(const char *name);
39static const android::NativeBridgeRuntimeCallbacks* gNativeBridgeArtCallbacks;
40
41static 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
89static 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
98static 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
107static 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
116static 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
124static 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
132static 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
142static 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
152static 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
163static 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
173NativeBridgeMethod 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
196static 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
211extern "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
226extern "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
250extern "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
264extern "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
274namespace android {
275
276// Environment values required by the apps running with native bridge.
277struct 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
287const char* supported_abis[] = {
288    "supported1", "supported2", "supported3"
289};
290
291const 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
299extern "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).
312android::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