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/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