Fix ExecUtils.WaitChildWithTimeoutFallback by adding a fallback.

`WaitChildWithTimeout` didn't work with old Linux kernels because it
uses a syscall `pidfd_open`, which was added in Linux 5.4.

This change adds a fallback implementation of `WaitChildWithTimeout`
that creates a thread to wait instead of relying on `pidfd_open`.

Also:
- Use android::base::unique_fd to hold pidfd so that the fd is
  guaranteed to be closed.
- Allow timeout_sec to be negative, in which case it blocks until the
  subprocess exits.

Bug: 229268202
Test: m test-art-host-gtest-art_runtime_tests
Ignore-AOSP-First: Will cherry-pick later.
Change-Id: Iec3f21db135d9a8a3a915372253f1ff3e285e5cf
diff --git a/runtime/exec_utils.h b/runtime/exec_utils.h
index ff90ebd..79a12d7 100644
--- a/runtime/exec_utils.h
+++ b/runtime/exec_utils.h
@@ -22,46 +22,46 @@
 #include <string>
 #include <vector>
 
+#include "android-base/unique_fd.h"
+
 namespace art {
 
 // Wrapper on fork/execv to run a command in a subprocess.
 // These spawn child processes using the environment as it was set when the single instance
 // of the runtime (Runtime::Current()) was started.  If no instance of the runtime was started, it
 // will use the current environment settings.
-
-bool Exec(const std::vector<std::string>& arg_vector, /*out*/ std::string* error_msg);
-int ExecAndReturnCode(const std::vector<std::string>& arg_vector, /*out*/ std::string* error_msg);
-
-// Execute the command specified in `argv_vector` in a subprocess with a timeout.
-// Returns the process exit code on success, -1 otherwise.
-int ExecAndReturnCode(const std::vector<std::string>& arg_vector,
-                      int timeout_sec,
-                      /*out*/ bool* timed_out,
-                      /*out*/ std::string* error_msg);
-
-// A wrapper class to make the functions above mockable.
 class ExecUtils {
  public:
   virtual ~ExecUtils() = default;
 
   virtual bool Exec(const std::vector<std::string>& arg_vector,
-                    /*out*/ std::string* error_msg) const {
-    return art::Exec(arg_vector, error_msg);
-  }
+                    /*out*/ std::string* error_msg) const;
 
   virtual int ExecAndReturnCode(const std::vector<std::string>& arg_vector,
-                                /*out*/ std::string* error_msg) const {
-    return art::ExecAndReturnCode(arg_vector, error_msg);
-  }
+                                /*out*/ std::string* error_msg) const;
 
+  // Executes the command specified in `arg_vector` in a subprocess with a timeout.
+  // If `timeout_sec` is negative, blocks until the subprocess exits.
+  // Returns the process exit code on success, -1 otherwise.
+  // Sets `timed_out` to true if the process times out, or false otherwise.
   virtual int ExecAndReturnCode(const std::vector<std::string>& arg_vector,
                                 int timeout_sec,
                                 /*out*/ bool* timed_out,
-                                /*out*/ std::string* error_msg) const {
-    return art::ExecAndReturnCode(arg_vector, timeout_sec, timed_out, error_msg);
-  }
+                                /*out*/ std::string* error_msg) const;
+
+ protected:
+  virtual android::base::unique_fd PidfdOpen(pid_t pid) const;
 };
 
+inline bool Exec(const std::vector<std::string>& arg_vector, /*out*/ std::string* error_msg) {
+  return ExecUtils().Exec(arg_vector, error_msg);
+}
+
+inline int ExecAndReturnCode(const std::vector<std::string>& arg_vector,
+                             /*out*/ std::string* error_msg) {
+  return ExecUtils().ExecAndReturnCode(arg_vector, error_msg);
+}
+
 }  // namespace art
 
 #endif  // ART_RUNTIME_EXEC_UTILS_H_