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