summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndreas Gampe <agampe@google.com>2015-05-22 18:31:50 -0700
committerAndreas Gampe <agampe@google.com>2015-05-31 16:59:11 -0700
commit8ee2145d65ed14b267ae4c6396f2333115611a97 (patch)
tree77c4ffa7f2b21e35e9e09bbce26306ca486f64e2
parent93de952df65ca5033bda313712b68b6272b4975f (diff)
downloadart-8ee2145d65ed14b267ae4c6396f2333115611a97.zip
art-8ee2145d65ed14b267ae4c6396f2333115611a97.tar.gz
art-8ee2145d65ed14b267ae4c6396f2333115611a97.tar.bz2
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 (cherry picked from commit 03c2cc89428914adf52229d6a3867eef6127911a) Change-Id: I78cc01fbdabe169154ff6b94c9f3ddb95b5c7448
-rw-r--r--runtime/native_bridge_art_interface.cc17
-rw-r--r--sigchainlib/sigchain.cc53
-rw-r--r--sigchainlib/sigchain.h3
-rw-r--r--sigchainlib/sigchain_dummy.cc6
-rw-r--r--test/115-native-bridge/expected.txt5
-rw-r--r--test/115-native-bridge/nativebridge.cc97
-rw-r--r--test/115-native-bridge/src/NativeBridgeMain.java13
7 files changed, 185 insertions, 9 deletions
diff --git a/runtime/native_bridge_art_interface.cc b/runtime/native_bridge_art_interface.cc
index b7f31f2..0ad560e 100644
--- a/runtime/native_bridge_art_interface.cc
+++ b/runtime/native_bridge_art_interface.cc
@@ -16,6 +16,8 @@
#include "native_bridge_art_interface.h"
+#include <signal.h>
+
#include "nativebridge/native_bridge.h"
#include "base/logging.h"
@@ -24,6 +26,7 @@
#include "mirror/art_method-inl.h"
#include "mirror/class-inl.h"
#include "scoped_thread_state_change.h"
+#include "sigchain.h"
namespace art {
@@ -127,7 +130,19 @@ void PreInitializeNativeBridge(std::string dir) {
}
void InitializeNativeBridge(JNIEnv* env, const char* instruction_set) {
- android::InitializeNativeBridge(env, instruction_set);
+ if (android::InitializeNativeBridge(env, instruction_set)) {
+ if (android::NativeBridgeGetVersion() >= 2U) {
+#ifdef _NSIG // Undefined on Apple, but we don't support running on Mac, anyways.
+ // Managed signal handling support added in version 2.
+ for (int signal = 0; signal < _NSIG; ++signal) {
+ android::NativeBridgeSignalHandlerFn fn = android::NativeBridgeGetSignalHandler(signal);
+ if (fn != nullptr) {
+ SetSpecialSignalHandlerFn(signal, fn);
+ }
+ }
+#endif
+ }
+ }
}
void UnloadNativeBridge() {
diff --git a/sigchainlib/sigchain.cc b/sigchainlib/sigchain.cc
index 0359ed3..1391d14 100644
--- a/sigchainlib/sigchain.cc
+++ b/sigchainlib/sigchain.cc
@@ -39,7 +39,7 @@ typedef int (*SigActionFnPtr)(int, const struct sigaction*, struct sigaction*);
class SignalAction {
public:
- SignalAction() : claimed_(false), uses_old_style_(false) {
+ SignalAction() : claimed_(false), uses_old_style_(false), special_handler_(nullptr) {
}
// Claim the signal and keep the action specified.
@@ -77,10 +77,19 @@ class SignalAction {
return uses_old_style_;
}
+ void SetSpecialHandler(SpecialSignalHandlerFn fn) {
+ special_handler_ = fn;
+ }
+
+ SpecialSignalHandlerFn GetSpecialHandler() {
+ return special_handler_;
+ }
+
private:
- struct sigaction action_; // Action to be performed.
- bool claimed_; // Whether signal is claimed or not.
- bool uses_old_style_; // Action is created using signal(). Use sa_handler.
+ struct sigaction action_; // Action to be performed.
+ bool claimed_; // Whether signal is claimed or not.
+ bool uses_old_style_; // Action is created using signal(). Use sa_handler.
+ SpecialSignalHandlerFn special_handler_; // A special handler executed before user handlers.
};
// User's signal handlers
@@ -109,9 +118,16 @@ static void CheckSignalValid(int signal) {
}
}
+// Sigchainlib's own handler so we can ensure a managed handler is called first even if nobody
+// claimed a chain. Simply forward to InvokeUserSignalHandler.
+static void sigchainlib_managed_handler_sigaction(int sig, siginfo_t* info, void* context) {
+ InvokeUserSignalHandler(sig, info, context);
+}
+
// Claim a signal chain for a particular signal.
extern "C" void ClaimSignalChain(int signal, struct sigaction* oldaction) {
CheckSignalValid(signal);
+
user_sigactions[signal].Claim(*oldaction);
}
@@ -131,6 +147,15 @@ extern "C" void InvokeUserSignalHandler(int sig, siginfo_t* info, void* context)
abort();
}
+ // Do we have a managed handler? If so, run it first.
+ SpecialSignalHandlerFn managed = user_sigactions[sig].GetSpecialHandler();
+ if (managed != nullptr) {
+ // Call the handler. If it succeeds, we're done.
+ if (managed(sig, info, context)) {
+ return;
+ }
+ }
+
const struct sigaction& action = user_sigactions[sig].GetAction();
if (user_sigactions[sig].OldStyle()) {
if (action.sa_handler != nullptr) {
@@ -303,5 +328,25 @@ extern "C" void InitializeSignalChain() {
initialized = true;
}
+extern "C" void SetSpecialSignalHandlerFn(int signal, SpecialSignalHandlerFn fn) {
+ CheckSignalValid(signal);
+
+ // Set the managed_handler.
+ user_sigactions[signal].SetSpecialHandler(fn);
+
+ // In case the chain isn't claimed, claim it for ourself so we can ensure the managed handler
+ // goes first.
+ if (!user_sigactions[signal].IsClaimed()) {
+ struct sigaction tmp;
+ tmp.sa_sigaction = sigchainlib_managed_handler_sigaction;
+ sigemptyset(&tmp.sa_mask);
+ tmp.sa_flags = SA_SIGINFO | SA_ONSTACK;
+#if !defined(__APPLE__) && !defined(__mips__)
+ tmp.sa_restorer = nullptr;
+#endif
+ user_sigactions[signal].Claim(tmp);
+ }
+}
+
} // namespace art
diff --git a/sigchainlib/sigchain.h b/sigchainlib/sigchain.h
index 79b76a7..01ccedf 100644
--- a/sigchainlib/sigchain.h
+++ b/sigchainlib/sigchain.h
@@ -27,6 +27,9 @@ extern "C" void ClaimSignalChain(int signal, struct sigaction* oldaction);
extern "C" void UnclaimSignalChain(int signal);
+typedef bool (*SpecialSignalHandlerFn)(int, siginfo_t*, void*);
+extern "C" void SetSpecialSignalHandlerFn(int signal, SpecialSignalHandlerFn fn);
+
extern "C" void InvokeUserSignalHandler(int sig, siginfo_t* info, void* context);
extern "C" void EnsureFrontOfChain(int signal, struct sigaction* expected_action);
diff --git a/sigchainlib/sigchain_dummy.cc b/sigchainlib/sigchain_dummy.cc
index 70a4f71..8495a54 100644
--- a/sigchainlib/sigchain_dummy.cc
+++ b/sigchainlib/sigchain_dummy.cc
@@ -78,6 +78,12 @@ extern "C" void EnsureFrontOfChain(int signal ATTRIBUTE_UNUSED,
abort();
}
+extern "C" void SetSpecialSignalHandlerFn(int signal ATTRIBUTE_UNUSED,
+ SpecialSignalHandlerFn fn ATTRIBUTE_UNUSED) {
+ log("SetSpecialSignalHandlerFn is not exported by the main executable.");
+ abort();
+}
+
#pragma GCC diagnostic pop
} // namespace art
diff --git a/test/115-native-bridge/expected.txt b/test/115-native-bridge/expected.txt
index deb70ba..464d2c8 100644
--- a/test/115-native-bridge/expected.txt
+++ b/test/115-native-bridge/expected.txt
@@ -4,7 +4,7 @@ Checking for getEnvValues.
Ready for native bridge tests.
Checking for support.
Getting trampoline for JNI_OnLoad with shorty (null).
-Test ART callbacks: all JNI function number is 10.
+Test ART callbacks: all JNI function number is 11.
name:booleanMethod, signature:(ZZZZZZZZZZ)Z, shorty:ZZZZZZZZZZZ.
name:byteMethod, signature:(BBBBBBBBBB)B, shorty:BBBBBBBBBBB.
name:charMethod, signature:(CCCCCCCCCC)C, shorty:CCCCCCCCCCC.
@@ -14,6 +14,7 @@ Test ART callbacks: all JNI function number is 10.
name:testFindFieldOnAttachedNativeThreadNative, signature:()V, shorty:V.
name:testGetMirandaMethodNative, signature:()Ljava/lang/reflect/Method;, shorty:L.
name:testNewStringObject, signature:()V, shorty:V.
+ name:testSignal, signature:()I, shorty:I.
name:testZeroLengthByteBuffers, signature:()V, shorty:V.
trampoline_JNI_OnLoad called!
Getting trampoline for Java_Main_testFindClassOnAttachedNativeThread with shorty V.
@@ -58,3 +59,5 @@ trampoline_Java_Main_charMethod called!
trampoline_Java_Main_charMethod called!
Getting trampoline for Java_Main_testNewStringObject with shorty V.
trampoline_Java_Main_testNewStringObject called!
+Getting trampoline for Java_Main_testSignal with shorty I.
+NB signal handler with signal 11.
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 @@ static jchar trampoline_Java_Main_charMethod(JNIEnv* env, jclass klass, jchar c1
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 @@ NativeBridgeMethod gNativeBridgeMethods[] = {
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 @@ extern "C" const struct android::NativeBridgeRuntimeValues* native_bridge_getApp
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
};
diff --git a/test/115-native-bridge/src/NativeBridgeMain.java b/test/115-native-bridge/src/NativeBridgeMain.java
index c843707..25390f7 100644
--- a/test/115-native-bridge/src/NativeBridgeMain.java
+++ b/test/115-native-bridge/src/NativeBridgeMain.java
@@ -32,6 +32,7 @@ class Main {
testCharMethod();
testEnvironment();
testNewStringObject();
+ testSignalHandler();
}
public static native void testFindClassOnAttachedNativeThread();
@@ -170,6 +171,18 @@ class Main {
}
private static native void testNewStringObject();
+
+ // Test v2 special signal handlers. This uses the native code from 004-SignalTest to cause
+ // a non-managed segfault.
+ private static void testSignalHandler() {
+ // This uses code from 004-SignalTest.
+ int x = testSignal();
+ if (x != 1234) {
+ throw new AssertionError();
+ }
+ }
+
+ private static native int testSignal();
}
public class NativeBridgeMain {