ART: Add support for special handlers in sigchainlib
Add support for a special managed handler in sigchainlib that
will be called as the first user handler.
Use this support for native bridge v2. Extend test 115-native-bridge
to test the functionality.
Bug: 20217701
Change-Id: I78cc01fbdabe169154ff6b94c9f3ddb95b5c7448
diff --git a/test/115-native-bridge/nativebridge.cc b/test/115-native-bridge/nativebridge.cc
index db2fc9b..fd94b23 100644
--- a/test/115-native-bridge/nativebridge.cc
+++ b/test/115-native-bridge/nativebridge.cc
@@ -19,6 +19,8 @@
#include <algorithm>
#include <dlfcn.h>
#include <jni.h>
+#include <stdlib.h>
+#include <signal.h>
#include <vector>
#include "stdio.h"
@@ -179,6 +181,35 @@
return fnPtr(env, klass, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10);
}
+// This code is adapted from 004-SignalTest and causes a segfault.
+char *go_away_compiler = nullptr;
+
+[[ noreturn ]] static void test_sigaction_handler(int sig ATTRIBUTE_UNUSED,
+ siginfo_t* info ATTRIBUTE_UNUSED,
+ void* context ATTRIBUTE_UNUSED) {
+ printf("Should not reach the test sigaction handler.");
+ abort();
+}
+
+static jint trampoline_Java_Main_testSignal(JNIEnv*, jclass) {
+ // Install the sigaction handler above, which should *not* be reached as the native-bridge
+ // handler should be called first. Note: we won't chain at all, if we ever get here, we'll die.
+ struct sigaction tmp;
+ sigemptyset(&tmp.sa_mask);
+ tmp.sa_sigaction = test_sigaction_handler;
+ tmp.sa_restorer = nullptr;
+ sigaction(SIGSEGV, &tmp, nullptr);
+
+#if defined(__arm__) || defined(__i386__) || defined(__x86_64__) || defined(__aarch64__)
+ // On supported architectures we cause a real SEGV.
+ *go_away_compiler = 'a';
+#else
+ // On other architectures we simulate SEGV.
+ kill(getpid(), SIGSEGV);
+#endif
+ return 1234;
+}
+
NativeBridgeMethod gNativeBridgeMethods[] = {
{ "JNI_OnLoad", "", true, nullptr,
reinterpret_cast<void*>(trampoline_JNI_OnLoad) },
@@ -202,6 +233,8 @@
reinterpret_cast<void*>(trampoline_Java_Main_testNewStringObject) },
{ "testZeroLengthByteBuffers", "()V", true, nullptr,
reinterpret_cast<void*>(trampoline_Java_Main_testZeroLengthByteBuffers) },
+ { "testSignal", "()I", true, nullptr,
+ reinterpret_cast<void*>(trampoline_Java_Main_testSignal) },
};
static NativeBridgeMethod* find_native_bridge_method(const char *name) {
@@ -319,15 +352,73 @@
return &nb_env;
}
+// v2 parts.
+
+extern "C" bool nb_is_compatible(uint32_t bridge_version ATTRIBUTE_UNUSED) {
+ return true;
+}
+
+#if defined(__i386__) || defined(__x86_64__)
+#if defined(__APPLE__)
+#define ucontext __darwin_ucontext
+
+#if defined(__x86_64__)
+// 64 bit mac build.
+#define CTX_EIP uc_mcontext->__ss.__rip
+#else
+// 32 bit mac build.
+#define CTX_EIP uc_mcontext->__ss.__eip
+#endif
+
+#elif defined(__x86_64__)
+// 64 bit linux build.
+#define CTX_EIP uc_mcontext.gregs[REG_RIP]
+#else
+// 32 bit linux build.
+#define CTX_EIP uc_mcontext.gregs[REG_EIP]
+#endif
+#endif
+
+// A dummy special handler, continueing after the faulting location. This code comes from
+// 004-SignalTest.
+static bool nb_signalhandler(int sig, siginfo_t* info ATTRIBUTE_UNUSED, void* context) {
+ printf("NB signal handler with signal %d.\n", sig);
+#if defined(__arm__)
+ struct ucontext *uc = reinterpret_cast<struct ucontext*>(context);
+ struct sigcontext *sc = reinterpret_cast<struct sigcontext*>(&uc->uc_mcontext);
+ sc->arm_pc += 2; // Skip instruction causing segv.
+#elif defined(__aarch64__)
+ struct ucontext *uc = reinterpret_cast<struct ucontext*>(context);
+ struct sigcontext *sc = reinterpret_cast<struct sigcontext*>(&uc->uc_mcontext);
+ sc->pc += 4; // Skip instruction causing segv.
+#elif defined(__i386__) || defined(__x86_64__)
+ struct ucontext *uc = reinterpret_cast<struct ucontext*>(context);
+ uc->CTX_EIP += 3;
+#else
+ UNUSED(context);
+#endif
+ // We handled this...
+ return true;
+}
+
+static ::android::NativeBridgeSignalHandlerFn native_bridge_get_signal_handler(int signal) {
+ // Only test segfault handler.
+ if (signal == SIGSEGV) {
+ return &nb_signalhandler;
+ }
+ return nullptr;
+}
+
+
// "NativeBridgeItf" is effectively an API (it is the name of the symbol that will be loaded
// by the native bridge library).
android::NativeBridgeCallbacks NativeBridgeItf {
- .version = 1,
+ .version = 2,
.initialize = &native_bridge_initialize,
.loadLibrary = &native_bridge_loadLibrary,
.getTrampoline = &native_bridge_getTrampoline,
.isSupported = &native_bridge_isSupported,
.getAppEnv = &native_bridge_getAppEnv,
- .isCompatibleWith = nullptr,
- .getSignalHandler = nullptr
+ .isCompatibleWith = &nb_is_compatible,
+ .getSignalHandler = &native_bridge_get_signal_handler
};