Add WatchDog class to kill process after a timeout.

Change-Id: I014e8a1148b5b0e731b14c39d2410aaedd877d2f
Bug: 72652321
diff --git a/Android.bp b/Android.bp
index 95237e3..98e5208 100644
--- a/Android.bp
+++ b/Android.bp
@@ -28,6 +28,7 @@
     "src/base/page_allocator.cc",
     "src/base/thread_checker.cc",
     "src/base/unix_task_runner.cc",
+    "src/base/watchdog.cc",
     "src/ftrace_reader/cpu_reader.cc",
     "src/ftrace_reader/event_info.cc",
     "src/ftrace_reader/event_info_constants.cc",
@@ -100,6 +101,7 @@
     "src/base/page_allocator.cc",
     "src/base/thread_checker.cc",
     "src/base/unix_task_runner.cc",
+    "src/base/watchdog.cc",
     "src/ipc/buffered_frame_deserializer.cc",
     "src/ipc/client_impl.cc",
     "src/ipc/deferred.cc",
@@ -187,6 +189,7 @@
     "src/base/test/vm_test_utils.cc",
     "src/base/thread_checker.cc",
     "src/base/unix_task_runner.cc",
+    "src/base/watchdog.cc",
     "src/ftrace_reader/cpu_reader.cc",
     "src/ftrace_reader/end_to_end_integrationtest.cc",
     "src/ftrace_reader/event_info.cc",
@@ -912,6 +915,7 @@
     "src/base/page_allocator.cc",
     "src/base/thread_checker.cc",
     "src/base/unix_task_runner.cc",
+    "src/base/watchdog.cc",
     "src/ipc/buffered_frame_deserializer.cc",
     "src/ipc/client_impl.cc",
     "src/ipc/deferred.cc",
@@ -1003,6 +1007,8 @@
     "src/base/thread_checker_unittest.cc",
     "src/base/unix_task_runner.cc",
     "src/base/utils_unittest.cc",
+    "src/base/watchdog.cc",
+    "src/base/watchdog_unittest.cc",
     "src/base/weak_ptr_unittest.cc",
     "src/ftrace_reader/cpu_reader.cc",
     "src/ftrace_reader/cpu_reader_unittest.cc",
diff --git a/include/perfetto/base/BUILD.gn b/include/perfetto/base/BUILD.gn
index d1d188a..27ee980 100644
--- a/include/perfetto/base/BUILD.gn
+++ b/include/perfetto/base/BUILD.gn
@@ -22,6 +22,7 @@
     "thread_checker.h",
     "unix_task_runner.h",
     "utils.h",
+    "watchdog.h",
     "weak_ptr.h",
   ]
   if (is_android) {
diff --git a/include/perfetto/base/watchdog.h b/include/perfetto/base/watchdog.h
new file mode 100644
index 0000000..969059b
--- /dev/null
+++ b/include/perfetto/base/watchdog.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef INCLUDE_PERFETTO_BASE_WATCHDOG_H_
+#define INCLUDE_PERFETTO_BASE_WATCHDOG_H_
+
+#include <stdint.h>
+#include <time.h>
+
+namespace perfetto {
+namespace base {
+
+// WatchDog crashes the calling program using SIGABRT if it does
+// not go out of scope within the number of milliseconds passed
+// to the constructor.
+class WatchDog {
+ public:
+  explicit WatchDog(time_t millisecs);
+  ~WatchDog();
+
+  WatchDog(const WatchDog&) = delete;
+  WatchDog& operator=(const WatchDog&) = delete;
+
+ private:
+  timer_t timerid_;
+};
+
+}  // namespace base
+}  // namespace perfetto
+#endif
diff --git a/src/base/BUILD.gn b/src/base/BUILD.gn
index a1b6f7b..64fa733 100644
--- a/src/base/BUILD.gn
+++ b/src/base/BUILD.gn
@@ -25,6 +25,7 @@
     "page_allocator.cc",
     "thread_checker.cc",
     "unix_task_runner.cc",
+    "watchdog.cc",
   ]
   if (is_debug) {
     deps += [ ":debug_crash_stack_trace" ]
@@ -98,6 +99,7 @@
     "task_runner_unittest.cc",
     "thread_checker_unittest.cc",
     "utils_unittest.cc",
+    "watchdog_unittest.cc",
     "weak_ptr_unittest.cc",
   ]
 }
diff --git a/src/base/debug_crash_stack_trace.cc b/src/base/debug_crash_stack_trace.cc
index 8990a14..6e1f6c2 100644
--- a/src/base/debug_crash_stack_trace.cc
+++ b/src/base/debug_crash_stack_trace.cc
@@ -20,6 +20,8 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
 #include <unistd.h>
 #include <unwind.h>
 
@@ -151,6 +153,19 @@
   }
 
   Print("------------------ END OF CRASH ------------------\n");
+  // info->si_code <= 0 iff SI_FROMUSER (SI_FROMKERNEL otherwise).
+  if (info->si_code <= 0 || sig_num == SIGABRT) {
+    // This signal was triggered by somebody sending us the signal with kill().
+    // In order to retrigger it, we have to queue a new signal by calling
+    // kill() ourselves.  The special case (si_pid == 0 && sig == SIGABRT) is
+    // due to the kernel sending a SIGABRT from a user request via SysRQ.
+    if (syscall(__NR_tgkill, getpid(), syscall(__NR_gettid), sig_num) < 0) {
+      // If we failed to kill ourselves (e.g. because a sandbox disallows us
+      // to do so), we instead resort to terminating our process. This will
+      // result in an incorrect exit code.
+      _exit(1);
+    }
+  }
 }
 
 // __attribute__((constructor)) causes a static initializer that automagically
diff --git a/src/base/watchdog.cc b/src/base/watchdog.cc
new file mode 100644
index 0000000..8ba7981
--- /dev/null
+++ b/src/base/watchdog.cc
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "perfetto/base/watchdog.h"
+
+#include "perfetto/base/logging.h"
+
+#include <signal.h>
+#include <stdint.h>
+
+namespace perfetto {
+namespace base {
+
+WatchDog::WatchDog(time_t millisecs) {
+  struct sigevent sev;
+  sev.sigev_notify = SIGEV_SIGNAL;
+  sev.sigev_signo = SIGABRT;
+  sev.sigev_value.sival_ptr = &timerid_;
+  PERFETTO_CHECK(timer_create(CLOCK_MONOTONIC, &sev, &timerid_) != -1);
+  struct itimerspec its;
+  its.it_value.tv_sec = millisecs / 1000;
+  its.it_value.tv_nsec = 1000000L * (millisecs % 1000);
+  its.it_interval.tv_sec = 0;
+  its.it_interval.tv_nsec = 0;
+  PERFETTO_CHECK(timer_settime(timerid_, 0, &its, nullptr) != -1);
+}
+
+WatchDog::~WatchDog() {
+  PERFETTO_CHECK(timer_delete(timerid_) != -1);
+}
+
+}  // namespace base
+}  // namespace perfetto
diff --git a/src/base/watchdog_unittest.cc b/src/base/watchdog_unittest.cc
new file mode 100644
index 0000000..b61e493
--- /dev/null
+++ b/src/base/watchdog_unittest.cc
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "perfetto/base/watchdog.h"
+
+#include "gtest/gtest.h"
+
+#include <time.h>
+
+namespace perfetto {
+namespace base {
+namespace {
+
+TEST(WatchDogTest, Crash) {
+  EXPECT_DEATH(
+      {
+        WatchDog watchdog(1);
+        usleep(20000);
+      },
+      "");
+}
+
+TEST(WatchDogTest, NoCrash) {
+  WatchDog watchdog(100000);
+  usleep(5000);
+}
+
+}  // namespace
+}  // namespace base
+}  // namespace perfetto