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#include "setjmp.h" 30 31#include "base/macros.h" 32#include "nativebridge/native_bridge.h" 33 34struct NativeBridgeMethod { 35 const char* name; 36 const char* signature; 37 bool static_method; 38 void* fnPtr; 39 void* trampoline; 40}; 41 42static NativeBridgeMethod* find_native_bridge_method(const char *name); 43static const android::NativeBridgeRuntimeCallbacks* gNativeBridgeArtCallbacks; 44 45static jint trampoline_JNI_OnLoad(JavaVM* vm, void* reserved) { 46 JNIEnv* env = nullptr; 47 typedef jint (*FnPtr_t)(JavaVM*, void*); 48 FnPtr_t fnPtr = reinterpret_cast<FnPtr_t>(find_native_bridge_method("JNI_OnLoad")->fnPtr); 49 50 vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6); 51 if (env == nullptr) { 52 return 0; 53 } 54 55 jclass klass = env->FindClass("Main"); 56 if (klass != nullptr) { 57 int i, count1, count2; 58 count1 = gNativeBridgeArtCallbacks->getNativeMethodCount(env, klass); 59 std::unique_ptr<JNINativeMethod[]> methods(new JNINativeMethod[count1]); 60 if (methods == nullptr) { 61 return 0; 62 } 63 count2 = gNativeBridgeArtCallbacks->getNativeMethods(env, klass, methods.get(), count1); 64 if (count1 == count2) { 65 printf("Test ART callbacks: all JNI function number is %d.\n", count1); 66 } 67 68 for (i = 0; i < count1; i++) { 69 NativeBridgeMethod* nb_method = find_native_bridge_method(methods[i].name); 70 if (nb_method != nullptr) { 71 jmethodID mid = nullptr; 72 if (nb_method->static_method) { 73 mid = env->GetStaticMethodID(klass, methods[i].name, nb_method->signature); 74 } else { 75 mid = env->GetMethodID(klass, methods[i].name, nb_method->signature); 76 } 77 if (mid != nullptr) { 78 const char* shorty = gNativeBridgeArtCallbacks->getMethodShorty(env, mid); 79 if (strcmp(shorty, methods[i].signature) == 0) { 80 printf(" name:%s, signature:%s, shorty:%s.\n", 81 methods[i].name, nb_method->signature, shorty); 82 } 83 } 84 } 85 } 86 methods.release(); 87 } 88 89 printf("%s called!\n", __FUNCTION__); 90 return fnPtr(vm, reserved); 91} 92 93static void trampoline_Java_Main_testFindClassOnAttachedNativeThread(JNIEnv* env, 94 jclass klass) { 95 typedef void (*FnPtr_t)(JNIEnv*, jclass); 96 FnPtr_t fnPtr = reinterpret_cast<FnPtr_t> 97 (find_native_bridge_method("testFindClassOnAttachedNativeThread")->fnPtr); 98 printf("%s called!\n", __FUNCTION__); 99 return fnPtr(env, klass); 100} 101 102static void trampoline_Java_Main_testFindFieldOnAttachedNativeThreadNative(JNIEnv* env, 103 jclass klass) { 104 typedef void (*FnPtr_t)(JNIEnv*, jclass); 105 FnPtr_t fnPtr = reinterpret_cast<FnPtr_t> 106 (find_native_bridge_method("testFindFieldOnAttachedNativeThreadNative")->fnPtr); 107 printf("%s called!\n", __FUNCTION__); 108 return fnPtr(env, klass); 109} 110 111static void trampoline_Java_Main_testCallStaticVoidMethodOnSubClassNative(JNIEnv* env, 112 jclass klass) { 113 typedef void (*FnPtr_t)(JNIEnv*, jclass); 114 FnPtr_t fnPtr = reinterpret_cast<FnPtr_t> 115 (find_native_bridge_method("testCallStaticVoidMethodOnSubClassNative")->fnPtr); 116 printf("%s called!\n", __FUNCTION__); 117 return fnPtr(env, klass); 118} 119 120static jobject trampoline_Java_Main_testGetMirandaMethodNative(JNIEnv* env, jclass klass) { 121 typedef jobject (*FnPtr_t)(JNIEnv*, jclass); 122 FnPtr_t fnPtr = reinterpret_cast<FnPtr_t> 123 (find_native_bridge_method("testGetMirandaMethodNative")->fnPtr); 124 printf("%s called!\n", __FUNCTION__); 125 return fnPtr(env, klass); 126} 127 128static void trampoline_Java_Main_testNewStringObject(JNIEnv* env, jclass klass) { 129 typedef void (*FnPtr_t)(JNIEnv*, jclass); 130 FnPtr_t fnPtr = reinterpret_cast<FnPtr_t> 131 (find_native_bridge_method("testNewStringObject")->fnPtr); 132 printf("%s called!\n", __FUNCTION__); 133 return fnPtr(env, klass); 134} 135 136static void trampoline_Java_Main_testZeroLengthByteBuffers(JNIEnv* env, jclass klass) { 137 typedef void (*FnPtr_t)(JNIEnv*, jclass); 138 FnPtr_t fnPtr = reinterpret_cast<FnPtr_t> 139 (find_native_bridge_method("testZeroLengthByteBuffers")->fnPtr); 140 printf("%s called!\n", __FUNCTION__); 141 return fnPtr(env, klass); 142} 143 144static jbyte trampoline_Java_Main_byteMethod(JNIEnv* env, jclass klass, jbyte b1, jbyte b2, 145 jbyte b3, jbyte b4, jbyte b5, jbyte b6, 146 jbyte b7, jbyte b8, jbyte b9, jbyte b10) { 147 typedef jbyte (*FnPtr_t)(JNIEnv*, jclass, jbyte, jbyte, jbyte, jbyte, jbyte, 148 jbyte, jbyte, jbyte, jbyte, jbyte); 149 FnPtr_t fnPtr = reinterpret_cast<FnPtr_t>(find_native_bridge_method("byteMethod")->fnPtr); 150 printf("%s called!\n", __FUNCTION__); 151 return fnPtr(env, klass, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10); 152} 153 154static jshort trampoline_Java_Main_shortMethod(JNIEnv* env, jclass klass, jshort s1, jshort s2, 155 jshort s3, jshort s4, jshort s5, jshort s6, 156 jshort s7, jshort s8, jshort s9, jshort s10) { 157 typedef jshort (*FnPtr_t)(JNIEnv*, jclass, jshort, jshort, jshort, jshort, jshort, 158 jshort, jshort, jshort, jshort, jshort); 159 FnPtr_t fnPtr = reinterpret_cast<FnPtr_t>(find_native_bridge_method("shortMethod")->fnPtr); 160 printf("%s called!\n", __FUNCTION__); 161 return fnPtr(env, klass, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10); 162} 163 164static jboolean trampoline_Java_Main_booleanMethod(JNIEnv* env, jclass klass, jboolean b1, 165 jboolean b2, jboolean b3, jboolean b4, 166 jboolean b5, jboolean b6, jboolean b7, 167 jboolean b8, jboolean b9, jboolean b10) { 168 typedef jboolean (*FnPtr_t)(JNIEnv*, jclass, jboolean, jboolean, jboolean, jboolean, jboolean, 169 jboolean, jboolean, jboolean, jboolean, jboolean); 170 FnPtr_t fnPtr = reinterpret_cast<FnPtr_t>(find_native_bridge_method("booleanMethod")->fnPtr); 171 printf("%s called!\n", __FUNCTION__); 172 return fnPtr(env, klass, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10); 173} 174 175static jchar trampoline_Java_Main_charMethod(JNIEnv* env, jclass klass, jchar c1, jchar c2, 176 jchar c3, jchar c4, jchar c5, jchar c6, 177 jchar c7, jchar c8, jchar c9, jchar c10) { 178 typedef jchar (*FnPtr_t)(JNIEnv*, jclass, jchar, jchar, jchar, jchar, jchar, 179 jchar, jchar, jchar, jchar, jchar); 180 FnPtr_t fnPtr = reinterpret_cast<FnPtr_t>(find_native_bridge_method("charMethod")->fnPtr); 181 printf("%s called!\n", __FUNCTION__); 182 return fnPtr(env, klass, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10); 183} 184 185// This code is adapted from 004-SignalTest and causes a segfault. 186char *go_away_compiler = nullptr; 187 188[[ noreturn ]] static void test_sigaction_handler(int sig ATTRIBUTE_UNUSED, 189 siginfo_t* info ATTRIBUTE_UNUSED, 190 void* context ATTRIBUTE_UNUSED) { 191 printf("Should not reach the test sigaction handler."); 192 abort(); 193} 194 195static void raise_sigsegv() { 196#if defined(__arm__) || defined(__i386__) || defined(__aarch64__) 197 *go_away_compiler = 'a'; 198#elif defined(__x86_64__) 199 // Cause a SEGV using an instruction known to be 2 bytes long to account for hardcoded jump 200 // in the signal handler 201 asm volatile("movl $0, %%eax;" "movb %%ah, (%%rax);" : : : "%eax"); 202#else 203 // On other architectures we simulate SEGV. 204 kill(getpid(), SIGSEGV); 205#endif 206} 207 208static jint trampoline_Java_Main_testSignal(JNIEnv*, jclass) { 209 // Install the sigaction handler above, which should *not* be reached as the native-bridge 210 // handler should be called first. Note: we won't chain at all, if we ever get here, we'll die. 211 struct sigaction tmp; 212 sigemptyset(&tmp.sa_mask); 213 tmp.sa_sigaction = test_sigaction_handler; 214#if !defined(__APPLE__) && !defined(__mips__) 215 tmp.sa_restorer = nullptr; 216#endif 217 218 // Test segv 219 sigaction(SIGSEGV, &tmp, nullptr); 220 raise_sigsegv(); 221 222 // Test sigill 223 sigaction(SIGILL, &tmp, nullptr); 224 kill(getpid(), SIGILL); 225 226 return 1234; 227} 228 229// Status of the tricky control path of testSignalHandlerNotReturn. 230// 231// "kNone" is the default status except testSignalHandlerNotReturn, 232// others are used by testSignalHandlerNotReturn. 233enum class TestStatus { 234 kNone, 235 kRaiseFirst, 236 kHandleFirst, 237 kRaiseSecond, 238 kHandleSecond, 239}; 240 241// State transition helper for testSignalHandlerNotReturn. 242class SignalHandlerTestStatus { 243 public: 244 SignalHandlerTestStatus() : state_(TestStatus::kNone) { 245 } 246 247 TestStatus Get() { 248 return state_; 249 } 250 251 void Reset() { 252 Set(TestStatus::kNone); 253 } 254 255 void Set(TestStatus state) { 256 switch (state) { 257 case TestStatus::kNone: 258 AssertState(TestStatus::kHandleSecond); 259 break; 260 261 case TestStatus::kRaiseFirst: 262 AssertState(TestStatus::kNone); 263 break; 264 265 case TestStatus::kHandleFirst: 266 AssertState(TestStatus::kRaiseFirst); 267 break; 268 269 case TestStatus::kRaiseSecond: 270 AssertState(TestStatus::kHandleFirst); 271 break; 272 273 case TestStatus::kHandleSecond: 274 AssertState(TestStatus::kRaiseSecond); 275 break; 276 277 default: 278 printf("ERROR: unknown state\n"); 279 abort(); 280 } 281 282 state_ = state; 283 } 284 285 private: 286 TestStatus state_; 287 288 void AssertState(TestStatus expected) { 289 if (state_ != expected) { 290 printf("ERROR: unexpected state, was %d, expected %d\n", state_, expected); 291 } 292 } 293}; 294 295static SignalHandlerTestStatus gSignalTestStatus; 296// The context is used to jump out from signal handler. 297static sigjmp_buf gSignalTestJmpBuf; 298 299// Test whether NativeBridge can receive future signal when its handler doesn't return. 300// 301// Control path: 302// 1. Raise first SIGSEGV in test function. 303// 2. Raise another SIGSEGV in NativeBridge's signal handler which is handling 304// the first SIGSEGV. 305// 3. Expect that NativeBridge's signal handler invokes again. And jump back 306// to test function in when handling second SIGSEGV. 307// 4. Exit test. 308// 309// NOTE: sigchain should be aware that "special signal handler" may not return. 310// Pay attention if this case fails. 311static void trampoline_Java_Main_testSignalHandlerNotReturn(JNIEnv*, jclass) { 312 if (gSignalTestStatus.Get() != TestStatus::kNone) { 313 printf("ERROR: test already started?\n"); 314 return; 315 } 316 printf("start testSignalHandlerNotReturn\n"); 317 318 if (sigsetjmp(gSignalTestJmpBuf, 1) == 0) { 319 gSignalTestStatus.Set(TestStatus::kRaiseFirst); 320 printf("raising first SIGSEGV\n"); 321 raise_sigsegv(); 322 } else { 323 // jump to here from signal handler when handling second SIGSEGV. 324 if (gSignalTestStatus.Get() != TestStatus::kHandleSecond) { 325 printf("ERROR: not jump from second SIGSEGV?\n"); 326 return; 327 } 328 gSignalTestStatus.Reset(); 329 printf("back to test from signal handler via siglongjmp(), and done!\n"); 330 } 331} 332 333// Signal handler for testSignalHandlerNotReturn. 334// This handler won't return. 335static bool NotReturnSignalHandler() { 336 if (gSignalTestStatus.Get() == TestStatus::kRaiseFirst) { 337 // handling first SIGSEGV 338 gSignalTestStatus.Set(TestStatus::kHandleFirst); 339 printf("handling first SIGSEGV, will raise another\n"); 340 sigset_t set; 341 sigemptyset(&set); 342 sigaddset(&set, SIGSEGV); 343 printf("unblock SIGSEGV in handler\n"); 344 sigprocmask(SIG_UNBLOCK, &set, nullptr); 345 gSignalTestStatus.Set(TestStatus::kRaiseSecond); 346 printf("raising second SIGSEGV\n"); 347 raise_sigsegv(); // raise second SIGSEGV 348 } else if (gSignalTestStatus.Get() == TestStatus::kRaiseSecond) { 349 // handling second SIGSEGV 350 gSignalTestStatus.Set(TestStatus::kHandleSecond); 351 printf("handling second SIGSEGV, will jump back to test function\n"); 352 siglongjmp(gSignalTestJmpBuf, 1); 353 } 354 printf("ERROR: should not reach here!\n"); 355 return false; 356} 357 358NativeBridgeMethod gNativeBridgeMethods[] = { 359 { "JNI_OnLoad", "", true, nullptr, 360 reinterpret_cast<void*>(trampoline_JNI_OnLoad) }, 361 { "booleanMethod", "(ZZZZZZZZZZ)Z", true, nullptr, 362 reinterpret_cast<void*>(trampoline_Java_Main_booleanMethod) }, 363 { "byteMethod", "(BBBBBBBBBB)B", true, nullptr, 364 reinterpret_cast<void*>(trampoline_Java_Main_byteMethod) }, 365 { "charMethod", "(CCCCCCCCCC)C", true, nullptr, 366 reinterpret_cast<void*>(trampoline_Java_Main_charMethod) }, 367 { "shortMethod", "(SSSSSSSSSS)S", true, nullptr, 368 reinterpret_cast<void*>(trampoline_Java_Main_shortMethod) }, 369 { "testCallStaticVoidMethodOnSubClassNative", "()V", true, nullptr, 370 reinterpret_cast<void*>(trampoline_Java_Main_testCallStaticVoidMethodOnSubClassNative) }, 371 { "testFindClassOnAttachedNativeThread", "()V", true, nullptr, 372 reinterpret_cast<void*>(trampoline_Java_Main_testFindClassOnAttachedNativeThread) }, 373 { "testFindFieldOnAttachedNativeThreadNative", "()V", true, nullptr, 374 reinterpret_cast<void*>(trampoline_Java_Main_testFindFieldOnAttachedNativeThreadNative) }, 375 { "testGetMirandaMethodNative", "()Ljava/lang/reflect/Method;", true, nullptr, 376 reinterpret_cast<void*>(trampoline_Java_Main_testGetMirandaMethodNative) }, 377 { "testNewStringObject", "()V", true, nullptr, 378 reinterpret_cast<void*>(trampoline_Java_Main_testNewStringObject) }, 379 { "testZeroLengthByteBuffers", "()V", true, nullptr, 380 reinterpret_cast<void*>(trampoline_Java_Main_testZeroLengthByteBuffers) }, 381 { "testSignal", "()I", true, nullptr, 382 reinterpret_cast<void*>(trampoline_Java_Main_testSignal) }, 383 { "testSignalHandlerNotReturn", "()V", true, nullptr, 384 reinterpret_cast<void*>(trampoline_Java_Main_testSignalHandlerNotReturn) }, 385}; 386 387static NativeBridgeMethod* find_native_bridge_method(const char *name) { 388 const char* pname = name; 389 if (strncmp(name, "Java_Main_", 10) == 0) { 390 pname += 10; 391 } 392 393 for (size_t i = 0; i < sizeof(gNativeBridgeMethods) / sizeof(gNativeBridgeMethods[0]); i++) { 394 if (strcmp(pname, gNativeBridgeMethods[i].name) == 0) { 395 return &gNativeBridgeMethods[i]; 396 } 397 } 398 return nullptr; 399} 400 401// NativeBridgeCallbacks implementations 402extern "C" bool native_bridge_initialize(const android::NativeBridgeRuntimeCallbacks* art_cbs, 403 const char* app_code_cache_dir, 404 const char* isa ATTRIBUTE_UNUSED) { 405 struct stat st; 406 if (app_code_cache_dir != nullptr) { 407 if (stat(app_code_cache_dir, &st) == 0) { 408 if (!S_ISDIR(st.st_mode)) { 409 printf("Code cache is not a directory.\n"); 410 } 411 } else { 412 perror("Error when stat-ing the code_cache:"); 413 } 414 } 415 416 if (art_cbs != nullptr) { 417 gNativeBridgeArtCallbacks = art_cbs; 418 printf("Native bridge initialized.\n"); 419 } 420 return true; 421} 422 423extern "C" void* native_bridge_loadLibrary(const char* libpath, int flag) { 424 if (strstr(libpath, "libinvalid.so") != nullptr) { 425 printf("Was to load 'libinvalid.so', force fail.\n"); 426 return nullptr; 427 } 428 size_t len = strlen(libpath); 429 char* tmp = new char[len + 10]; 430 strncpy(tmp, libpath, len); 431 tmp[len - 3] = '2'; 432 tmp[len - 2] = '.'; 433 tmp[len - 1] = 's'; 434 tmp[len] = 'o'; 435 tmp[len + 1] = 0; 436 void* handle = dlopen(tmp, flag); 437 delete[] tmp; 438 439 if (handle == nullptr) { 440 printf("Handle = nullptr!\n"); 441 printf("Was looking for %s.\n", libpath); 442 printf("Error = %s.\n", dlerror()); 443 char cwd[1024] = {'\0'}; 444 if (getcwd(cwd, sizeof(cwd)) != nullptr) { 445 printf("Current working dir: %s\n", cwd); 446 } 447 } 448 return handle; 449} 450 451extern "C" void* native_bridge_getTrampoline(void* handle, const char* name, const char* shorty, 452 uint32_t len ATTRIBUTE_UNUSED) { 453 printf("Getting trampoline for %s with shorty %s.\n", name, shorty); 454 455 // The name here is actually the JNI name, so we can directly do the lookup. 456 void* sym = dlsym(handle, name); 457 NativeBridgeMethod* method = find_native_bridge_method(name); 458 if (method == nullptr) 459 return nullptr; 460 method->fnPtr = sym; 461 462 return method->trampoline; 463} 464 465extern "C" bool native_bridge_isSupported(const char* libpath) { 466 printf("Checking for support.\n"); 467 468 if (libpath == nullptr) { 469 return false; 470 } 471 // We don't want to hijack javacore. So we should get libarttest... 472 return strcmp(libpath, "libjavacore.so") != 0; 473} 474 475namespace android { 476 477// Environment values required by the apps running with native bridge. 478struct NativeBridgeRuntimeValues { 479 const char* os_arch; 480 const char* cpu_abi; 481 const char* cpu_abi2; 482 const char* *supported_abis; 483 int32_t abi_count; 484}; 485 486} // namespace android 487 488const char* supported_abis[] = { 489 "supported1", "supported2", "supported3" 490}; 491 492const struct android::NativeBridgeRuntimeValues nb_env { 493 .os_arch = "os.arch", 494 .cpu_abi = "cpu_abi", 495 .cpu_abi2 = "cpu_abi2", 496 .supported_abis = supported_abis, 497 .abi_count = 3 498}; 499 500extern "C" const struct android::NativeBridgeRuntimeValues* native_bridge_getAppEnv( 501 const char* abi) { 502 printf("Checking for getEnvValues.\n"); 503 504 if (abi == nullptr) { 505 return nullptr; 506 } 507 508 return &nb_env; 509} 510 511// v2 parts. 512 513extern "C" bool native_bridge_isCompatibleWith(uint32_t bridge_version ATTRIBUTE_UNUSED) { 514 return true; 515} 516 517#if defined(__i386__) || defined(__x86_64__) 518#if defined(__APPLE__) 519#define ucontext __darwin_ucontext 520 521#if defined(__x86_64__) 522// 64 bit mac build. 523#define CTX_EIP uc_mcontext->__ss.__rip 524#else 525// 32 bit mac build. 526#define CTX_EIP uc_mcontext->__ss.__eip 527#endif 528 529#elif defined(__x86_64__) 530// 64 bit linux build. 531#define CTX_EIP uc_mcontext.gregs[REG_RIP] 532#else 533// 32 bit linux build. 534#define CTX_EIP uc_mcontext.gregs[REG_EIP] 535#endif 536#endif 537 538static bool StandardSignalHandler(int sig, siginfo_t* info ATTRIBUTE_UNUSED, 539 void* context) { 540 if (sig == SIGSEGV) { 541#if defined(__arm__) 542 struct ucontext *uc = reinterpret_cast<struct ucontext*>(context); 543 struct sigcontext *sc = reinterpret_cast<struct sigcontext*>(&uc->uc_mcontext); 544 sc->arm_pc += 2; // Skip instruction causing segv & sigill. 545#elif defined(__aarch64__) 546 struct ucontext *uc = reinterpret_cast<struct ucontext*>(context); 547 struct sigcontext *sc = reinterpret_cast<struct sigcontext*>(&uc->uc_mcontext); 548 sc->pc += 4; // Skip instruction causing segv & sigill. 549#elif defined(__i386__) 550 struct ucontext *uc = reinterpret_cast<struct ucontext*>(context); 551 uc->CTX_EIP += 3; 552#elif defined(__x86_64__) 553 struct ucontext *uc = reinterpret_cast<struct ucontext*>(context); 554 uc->CTX_EIP += 2; 555#else 556 UNUSED(context); 557#endif 558 } 559 560 // We handled this... 561 return true; 562} 563 564// A dummy special handler, continueing after the faulting location. This code comes from 565// 004-SignalTest. 566static bool nb_signalhandler(int sig, siginfo_t* info, void* context) { 567 printf("NB signal handler with signal %d.\n", sig); 568 569 if (gSignalTestStatus.Get() == TestStatus::kNone) { 570 return StandardSignalHandler(sig, info, context); 571 } else if (sig == SIGSEGV) { 572 return NotReturnSignalHandler(); 573 } else { 574 printf("ERROR: should not reach here!\n"); 575 return false; 576 } 577} 578 579static ::android::NativeBridgeSignalHandlerFn native_bridge_getSignalHandler(int signal) { 580 // Test segv for already claimed signal, and sigill for not claimed signal 581 if ((signal == SIGSEGV) || (signal == SIGILL)) { 582 return &nb_signalhandler; 583 } 584 return nullptr; 585} 586 587extern "C" int native_bridge_unloadLibrary(void* handle ATTRIBUTE_UNUSED) { 588 printf("dlclose() in native bridge.\n"); 589 return 0; 590} 591 592extern "C" const char* native_bridge_getError() { 593 printf("getError() in native bridge.\n"); 594 return ""; 595} 596 597extern "C" bool native_bridge_isPathSupported(const char* library_path ATTRIBUTE_UNUSED) { 598 printf("Checking for path support in native bridge.\n"); 599 return false; 600} 601 602extern "C" bool native_bridge_initAnonymousNamespace(const char* public_ns_sonames ATTRIBUTE_UNUSED, 603 const char* anon_ns_library_path ATTRIBUTE_UNUSED) { 604 printf("Initializing anonymous namespace in native bridge.\n"); 605 return false; 606} 607 608extern "C" android::native_bridge_namespace_t* 609native_bridge_createNamespace(const char* name ATTRIBUTE_UNUSED, 610 const char* ld_library_path ATTRIBUTE_UNUSED, 611 const char* default_library_path ATTRIBUTE_UNUSED, 612 uint64_t type ATTRIBUTE_UNUSED, 613 const char* permitted_when_isolated_path ATTRIBUTE_UNUSED, 614 android::native_bridge_namespace_t* parent_ns ATTRIBUTE_UNUSED) { 615 printf("Creating namespace in native bridge.\n"); 616 return nullptr; 617} 618 619extern "C" bool native_bridge_linkNamespaces(android::native_bridge_namespace_t* from ATTRIBUTE_UNUSED, 620 android::native_bridge_namespace_t* to ATTRIBUTE_UNUSED, 621 const char* shared_libs_sonames ATTRIBUTE_UNUSED) { 622 printf("Linking namespaces in native bridge.\n"); 623 return false; 624} 625 626extern "C" void* native_bridge_loadLibraryExt(const char* libpath ATTRIBUTE_UNUSED, 627 int flag ATTRIBUTE_UNUSED, 628 android::native_bridge_namespace_t* ns ATTRIBUTE_UNUSED) { 629 printf("Loading library with Extension in native bridge.\n"); 630 return nullptr; 631} 632 633// "NativeBridgeItf" is effectively an API (it is the name of the symbol that will be loaded 634// by the native bridge library). 635android::NativeBridgeCallbacks NativeBridgeItf { 636 // v1 637 .version = 3, 638 .initialize = &native_bridge_initialize, 639 .loadLibrary = &native_bridge_loadLibrary, 640 .getTrampoline = &native_bridge_getTrampoline, 641 .isSupported = &native_bridge_isSupported, 642 .getAppEnv = &native_bridge_getAppEnv, 643 // v2 644 .isCompatibleWith = &native_bridge_isCompatibleWith, 645 .getSignalHandler = &native_bridge_getSignalHandler, 646 // v3 647 .unloadLibrary = &native_bridge_unloadLibrary, 648 .getError = &native_bridge_getError, 649 .isPathSupported = &native_bridge_isPathSupported, 650 .initAnonymousNamespace = &native_bridge_initAnonymousNamespace, 651 .createNamespace = &native_bridge_createNamespace, 652 .linkNamespaces = &native_bridge_linkNamespaces, 653 .loadLibraryExt = &native_bridge_loadLibraryExt 654}; 655