tp: switch unix rpc server to use base::Daemonize (#6333)

Needs slight change to daemonize to allow custom printing instead
of just printing the pid.
diff --git a/include/perfetto/ext/base/utils.h b/include/perfetto/ext/base/utils.h
index 58bbb4f..c43b296 100644
--- a/include/perfetto/ext/base/utils.h
+++ b/include/perfetto/ext/base/utils.h
@@ -120,10 +120,10 @@
 uid_t GetCurrentUserId();
 
 // Forks the process.
-// Parent: prints the PID of the child, calls |parent_cb| and exits from the
-//         process with its return value.
+// Parent: calls |parent_cb| with the child's PID and exits with its return
+//         value. The callback owns any startup output (e.g. printing the PID).
 // Child: redirects stdio onto /dev/null, chdirs into / and returns.
-void Daemonize(std::function<int()> parent_cb);
+void Daemonize(std::function<int(pid_t)> parent_cb);
 
 // Returns the path of the current executable, e.g. /foo/bar/exe.
 std::string GetCurExecutablePath();
diff --git a/src/base/utils.cc b/src/base/utils.cc
index 682c702..2134b12 100644
--- a/src/base/utils.cc
+++ b/src/base/utils.cc
@@ -243,7 +243,7 @@
 #endif
 }
 
-void Daemonize(std::function<int()> parent_cb) {
+void Daemonize(std::function<int(pid_t)> parent_cb) {
 #if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) ||   \
     PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
     PERFETTO_BUILDFLAG(PERFETTO_OS_FREEBSD) || \
@@ -279,8 +279,7 @@
       pipe.wr.reset();
       char one = '\0';
       PERFETTO_CHECK(Read(*pipe.rd, &one, sizeof(one)) == 1 && one == '1');
-      printf("%d\n", pid);
-      int err = parent_cb();
+      int err = parent_cb(pid);
       exit(err);
     }
   }
diff --git a/src/perfetto_cmd/perfetto_cmd.cc b/src/perfetto_cmd/perfetto_cmd.cc
index 87aac1c..7903398 100644
--- a/src/perfetto_cmd/perfetto_cmd.cc
+++ b/src/perfetto_cmd/perfetto_cmd.cc
@@ -888,7 +888,8 @@
     }
 
     PERFETTO_CHECK(snapshot_threads_.empty());  // No threads before Daemonize.
-    base::Daemonize([this]() -> int {
+    base::Daemonize([this](pid_t pid) -> int {
+      printf("%d\n", pid);
       background_wait_pipe_.wr.reset();
 
       if (background_wait_) {
diff --git a/src/profiling/perf/traced_perf.cc b/src/profiling/perf/traced_perf.cc
index a00d048..c67057a 100644
--- a/src/profiling/perf/traced_perf.cc
+++ b/src/profiling/perf/traced_perf.cc
@@ -78,7 +78,10 @@
   }
 
   if (background) {
-    base::Daemonize([] { return 0; });
+    base::Daemonize([](pid_t pid) {
+      printf("%d\n", pid);
+      return 0;
+    });
   }
 
   base::MaybeLockFreeTaskRunner task_runner;
diff --git a/src/trace_processor/rpc/session_paths.cc b/src/trace_processor/rpc/session_paths.cc
index 62fa65e..96ee91f 100644
--- a/src/trace_processor/rpc/session_paths.cc
+++ b/src/trace_processor/rpc/session_paths.cc
@@ -25,6 +25,13 @@
 #include "perfetto/base/build_config.h"
 #include "perfetto/base/proc_utils.h"
 #include "perfetto/base/time.h"
+
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+#include <direct.h>  // _getcwd()
+#else
+#include <unistd.h>  // getcwd()
+#endif
+
 #include "perfetto/ext/base/file_utils.h"
 #include "perfetto/ext/base/murmur_hash.h"
 #include "perfetto/ext/base/status_macros.h"
@@ -160,6 +167,20 @@
   return base::OkStatus();
 }
 
+std::string MakeAbsolutePath(const std::string& path) {
+  if (path.empty() || IsAbsolutePath(path))
+    return path;
+  char cwd[4096];
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+  if (!_getcwd(cwd, sizeof(cwd)))
+    return path;
+#else
+  if (!getcwd(cwd, sizeof(cwd)))
+    return path;
+#endif
+  return std::string(cwd) + kPathSep + path;
+}
+
 base::StatusOr<uint32_t> ParseDurationMs(const std::string& s) {
   if (s.empty())
     return base::ErrStatus("Empty duration");
diff --git a/src/trace_processor/rpc/session_paths.h b/src/trace_processor/rpc/session_paths.h
index 8d69ea3..0a5a7b4 100644
--- a/src/trace_processor/rpc/session_paths.h
+++ b/src/trace_processor/rpc/session_paths.h
@@ -61,6 +61,11 @@
 // Returns an error if |path| does not fit within the AF_UNIX sun_path limit.
 base::Status ValidateAfUnixPathLength(const std::string& path);
 
+// Resolves |path| against the cwd if relative; returns it unchanged if already
+// absolute (or empty, or cwd is unavailable). Daemonizing chdirs to "/", so the
+// socket/pid paths must be absolute to survive the fork.
+std::string MakeAbsolutePath(const std::string& path);
+
 // Parses a human duration into milliseconds. Accepts a bare integer (seconds),
 // or a value suffixed with 's' (seconds), 'm' (minutes) or 'h' (hours). "0",
 // "never" and "off" all parse to 0 (meaning "no timeout").
diff --git a/src/trace_processor/rpc/unixd.cc b/src/trace_processor/rpc/unixd.cc
index 720f7be..8fe6518 100644
--- a/src/trace_processor/rpc/unixd.cc
+++ b/src/trace_processor/rpc/unixd.cc
@@ -31,6 +31,7 @@
 #include "perfetto/ext/base/file_utils.h"
 #include "perfetto/ext/base/lock_free_task_runner.h"
 #include "perfetto/ext/base/unix_socket.h"
+#include "perfetto/ext/base/utils.h"
 #include "perfetto/ext/protozero/proto_ring_buffer.h"
 #include "perfetto/protozero/proto_utils.h"
 #include "src/trace_processor/rpc/rpc.h"
@@ -42,10 +43,7 @@
     PERFETTO_BUILDFLAG(PERFETTO_OS_FREEBSD) || \
     PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
 #define PERFETTO_TP_UNIXD_POSIX() 1
-#include <fcntl.h>
 #include <unistd.h>
-#include "perfetto/ext/base/pipe.h"
-#include "perfetto/ext/base/scoped_file.h"
 #else
 #define PERFETTO_TP_UNIXD_POSIX() 0
 #endif
@@ -165,36 +163,6 @@
 }
 #endif  // PERFETTO_TP_UNIXD_CTRL_C()
 
-#if PERFETTO_TP_UNIXD_POSIX()
-// Forks into the background. The parent prints the startup record (it knows the
-// child pid) and exits; the child detaches (setsid + redirect std fds) and
-// returns to keep serving. The socket is already bound before this is called,
-// so the record the parent prints is accurate.
-void DaemonizeAndPrintRecord(const UnixServerArgs& args) {
-  base::Pipe pipe = base::Pipe::Create(base::Pipe::kBothBlock);
-  pid_t pid = fork();
-  PERFETTO_CHECK(pid != -1);
-  if (pid > 0) {
-    // Parent: wait for the child to detach, print the record, exit.
-    pipe.wr.reset();
-    char c = '\0';
-    base::ignore_result(base::Read(*pipe.rd, &c, 1));
-    PrintStartupRecord(stdout, pid, args.session_name, args.socket_path,
-                       args.idle_timeout_ms);
-    _exit(0);
-  }
-  // Child: detach from the controlling terminal and silence std fds.
-  PERFETTO_CHECK(setsid() != -1);
-  base::ScopedFile null = base::OpenFile("/dev/null", O_RDWR);
-  if (null) {
-    base::ignore_result(dup2(*null, STDIN_FILENO));
-    base::ignore_result(dup2(*null, STDOUT_FILENO));
-    base::ignore_result(dup2(*null, STDERR_FILENO));
-  }
-  base::ignore_result(base::WriteAll(*pipe.wr, "1", 1));
-}
-#endif  // PERFETTO_TP_UNIXD_POSIX()
-
 base::Status UnixRpcServer::Run() {
   if (args_.daemonize && !PERFETTO_TP_UNIXD_POSIX()) {
     return base::ErrStatus("--daemonize is not supported on this platform yet");
@@ -235,7 +203,15 @@
   bool printed_record = false;
 #if PERFETTO_TP_UNIXD_POSIX()
   if (args_.daemonize) {
-    DaemonizeAndPrintRecord(args_);  // Parent exits inside; child returns.
+    // base::Daemonize forks: the parent prints the record via the callback and
+    // exits; the child detaches and keeps serving. The socket is already bound,
+    // so the printed record is accurate.
+    const UnixServerArgs& args = args_;
+    base::Daemonize([&args](pid_t pid) -> int {
+      PrintStartupRecord(stdout, pid, args.session_name, args.socket_path,
+                         args.idle_timeout_ms);
+      return 0;
+    });
     printed_record = true;
   }
 #endif
diff --git a/src/trace_processor/shell/server_subcommand.cc b/src/trace_processor/shell/server_subcommand.cc
index 5ea21c2..d695ce2 100644
--- a/src/trace_processor/shell/server_subcommand.cc
+++ b/src/trace_processor/shell/server_subcommand.cc
@@ -334,6 +334,8 @@
       }
       ASSIGN_OR_RETURN(socket_path, session::SessionSocketPath(session_name));
     } else {
+      // Anchor a relative --path before binding: daemonizing chdirs to "/".
+      socket_path = session::MakeAbsolutePath(socket_path);
       RETURN_IF_ERROR(session::ValidateAfUnixPathLength(socket_path));
       if (session_name.empty())
         session_name = socket_path;
diff --git a/src/traced/probes/probes.cc b/src/traced/probes/probes.cc
index a70b6ab..04ee6e3 100644
--- a/src/traced/probes/probes.cc
+++ b/src/traced/probes/probes.cc
@@ -89,7 +89,10 @@
   }
 
   if (background) {
-    base::Daemonize([] { return 0; });
+    base::Daemonize([](pid_t pid) {
+      printf("%d\n", pid);
+      return 0;
+    });
   }
 
   PERFETTO_LOG("Starting %s service", argv[0]);
diff --git a/src/traced/service/service.cc b/src/traced/service/service.cc
index 027c2d5..25776c6 100644
--- a/src/traced/service/service.cc
+++ b/src/traced/service/service.cc
@@ -146,7 +146,10 @@
   }
 
   if (background) {
-    base::Daemonize([] { return 0; });
+    base::Daemonize([](pid_t pid) {
+      printf("%d\n", pid);
+      return 0;
+    });
   }
 
   base::MaybeLockFreeTaskRunner task_runner;
diff --git a/src/traced_relay/relay_service.cc b/src/traced_relay/relay_service.cc
index 4ef4ee9..c4b9400 100644
--- a/src/traced_relay/relay_service.cc
+++ b/src/traced_relay/relay_service.cc
@@ -565,7 +565,10 @@
   }
 
   if (background) {
-    base::Daemonize([] { return 0; });
+    base::Daemonize([](pid_t pid) {
+      printf("%d\n", pid);
+      return 0;
+    });
   }
 
   base::MaybeLockFreeTaskRunner task_runner;