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
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 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 @@
 
 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 @@
     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 @@
   }
 }
 
+// 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 @@
     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 @@
   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 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 @@
   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 @@
 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 @@
     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!
 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 @@
   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
 };
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 @@
         testCharMethod();
         testEnvironment();
         testNewStringObject();
+        testSignalHandler();
     }
 
     public static native void testFindClassOnAttachedNativeThread();
@@ -170,6 +171,18 @@
     }
 
     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 {