Perfprofd: Move invoke code to its own file

So that it's easier to isolate and change.

Bug: 110555909
Test: mmma system/extras/perfprofd
Test: perfprofd_test
Change-Id: I8bf379232277ee1cad8041368ccf2b40b3bf4f8c
diff --git a/perfprofd/Android.bp b/perfprofd/Android.bp
index 7db4d49..8adde50 100644
--- a/perfprofd/Android.bp
+++ b/perfprofd/Android.bp
@@ -136,6 +136,7 @@
         "cpuconfig.cc",
         "perfprofdcore.cc",
         "perfprofd_cmdline.cc",
+        "perfprofd_perf.cc",
         "symbolizer.cc"
     ],
 
diff --git a/perfprofd/perfprofd_perf.cc b/perfprofd/perfprofd_perf.cc
new file mode 100644
index 0000000..5b26c72
--- /dev/null
+++ b/perfprofd/perfprofd_perf.cc
@@ -0,0 +1,182 @@
+/*
+**
+** Copyright 2015, 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 "perfprofd_perf.h"
+
+
+#include <assert.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <cerrno>
+#include <cstdio>
+#include <cstring>
+#include <memory>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+
+#include "config.h"
+
+namespace android {
+namespace perfprofd {
+
+//
+// Invoke "perf record". Return value is OK_PROFILE_COLLECTION for
+// success, or some other error code if something went wrong.
+//
+PerfResult InvokePerf(Config& config,
+                      const std::string &perf_path,
+                      const char *stack_profile_opt,
+                      unsigned duration,
+                      const std::string &data_file_path,
+                      const std::string &perf_stderr_path)
+{
+  pid_t pid = fork();
+
+  if (pid == -1) {
+    PLOG(ERROR) << "Fork failed";
+    return PerfResult::kForkFailed;
+  }
+
+  if (pid == 0) {
+    // child
+
+    // Open file to receive stderr/stdout from perf
+    FILE *efp = fopen(perf_stderr_path.c_str(), "w");
+    if (efp) {
+      dup2(fileno(efp), STDERR_FILENO);
+      dup2(fileno(efp), STDOUT_FILENO);
+    } else {
+      PLOG(WARNING) << "unable to open " << perf_stderr_path << " for writing";
+    }
+
+    // marshall arguments
+    constexpr unsigned max_args = 17;
+    const char *argv[max_args];
+    unsigned slot = 0;
+    argv[slot++] = perf_path.c_str();
+    argv[slot++] = "record";
+
+    // -o perf.data
+    argv[slot++] = "-o";
+    argv[slot++] = data_file_path.c_str();
+
+    // -c/f N
+    std::string p_str;
+    if (config.sampling_frequency > 0) {
+      argv[slot++] = "-f";
+      p_str = android::base::StringPrintf("%u", config.sampling_frequency);
+      argv[slot++] = p_str.c_str();
+    } else if (config.sampling_period > 0) {
+      argv[slot++] = "-c";
+      p_str = android::base::StringPrintf("%u", config.sampling_period);
+      argv[slot++] = p_str.c_str();
+    }
+
+    // -g if desired
+    if (stack_profile_opt) {
+      argv[slot++] = stack_profile_opt;
+      argv[slot++] = "-m";
+      argv[slot++] = "8192";
+    }
+
+    std::string pid_str;
+    if (config.process < 0) {
+      // system wide profiling
+      argv[slot++] = "-a";
+    } else {
+      argv[slot++] = "-p";
+      pid_str = std::to_string(config.process);
+      argv[slot++] = pid_str.c_str();
+    }
+
+    // no need for kernel or other symbols
+    argv[slot++] = "--no-dump-kernel-symbols";
+    argv[slot++] = "--no-dump-symbols";
+
+    // sleep <duration>
+    argv[slot++] = "--duration";
+    std::string d_str = android::base::StringPrintf("%u", duration);
+    argv[slot++] = d_str.c_str();
+
+    // terminator
+    argv[slot++] = nullptr;
+    assert(slot < max_args);
+
+    // record the final command line in the error output file for
+    // posterity/debugging purposes
+    fprintf(stderr, "perf invocation (pid=%d):\n", getpid());
+    for (unsigned i = 0; argv[i] != nullptr; ++i) {
+      fprintf(stderr, "%s%s", i ? " " : "", argv[i]);
+    }
+    fprintf(stderr, "\n");
+
+    // exec
+    execvp(argv[0], (char * const *)argv);
+    fprintf(stderr, "exec failed: %s\n", strerror(errno));
+    exit(1);
+
+  } else {
+    // parent
+
+    // Try to sleep.
+    config.Sleep(duration);
+
+    // We may have been woken up to stop profiling.
+    if (config.ShouldStopProfiling()) {
+      // Send SIGHUP to simpleperf to make it stop.
+      kill(pid, SIGHUP);
+    }
+
+    // Wait for the child, so it's reaped correctly.
+    int st = 0;
+    pid_t reaped = TEMP_FAILURE_RETRY(waitpid(pid, &st, 0));
+
+    auto print_perferr = [&perf_stderr_path]() {
+      std::string tmp;
+      if (android::base::ReadFileToString(perf_stderr_path, &tmp)) {
+        LOG(WARNING) << tmp;
+      } else {
+        PLOG(WARNING) << "Could not read " << perf_stderr_path;
+      }
+    };
+
+    if (reaped == -1) {
+      PLOG(WARNING) << "waitpid failed";
+    } else if (WIFSIGNALED(st)) {
+      if (WTERMSIG(st) == SIGHUP && config.ShouldStopProfiling()) {
+        // That was us...
+        return PerfResult::kOK;
+      }
+      LOG(WARNING) << "perf killed by signal " << WTERMSIG(st);
+      print_perferr();
+    } else if (WEXITSTATUS(st) != 0) {
+      LOG(WARNING) << "perf bad exit status " << WEXITSTATUS(st);
+      print_perferr();
+    } else {
+      return PerfResult::kOK;
+    }
+  }
+
+  return PerfResult::kRecordFailed;
+}
+
+}  // namespace perfprofd
+}  // namespace android
diff --git a/perfprofd/perfprofd_perf.h b/perfprofd/perfprofd_perf.h
new file mode 100644
index 0000000..8cc9d50
--- /dev/null
+++ b/perfprofd/perfprofd_perf.h
@@ -0,0 +1,50 @@
+/*
+**
+** Copyright 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 SYSTEM_EXTRAS_PERFPROFD_PERFPROFD_PERF_H_
+#define SYSTEM_EXTRAS_PERFPROFD_PERFPROFD_PERF_H_
+
+#include <string>
+
+struct Config;
+
+namespace android {
+namespace perfprofd {
+
+
+
+enum PerfResult {
+  kOK,
+  kForkFailed,
+  kRecordFailed,
+};
+
+//
+// Invoke "perf record". Return value is PerfResult::kOK for
+// success, or some other error code if something went wrong.
+//
+PerfResult InvokePerf(Config& config,
+                      const std::string &perf_path,
+                      const char *stack_profile_opt,
+                      unsigned duration,
+                      const std::string &data_file_path,
+                      const std::string &perf_stderr_path);
+
+}  // namespace perfprofd
+}  // namespace android
+
+#endif  // SYSTEM_EXTRAS_PERFPROFD_PERFPROFD_PERF_H_
diff --git a/perfprofd/perfprofdcore.cc b/perfprofd/perfprofdcore.cc
index 57cee81..067745f 100644
--- a/perfprofd/perfprofdcore.cc
+++ b/perfprofd/perfprofdcore.cc
@@ -50,6 +50,7 @@
 #include "perf_data_converter.h"
 #include "perfprofdcore.h"
 #include "perfprofd_io.h"
+#include "perfprofd_perf.h"
 #include "symbolizer.h"
 
 //
@@ -452,147 +453,6 @@
 }
 
 //
-// Invoke "perf record". Return value is OK_PROFILE_COLLECTION for
-// success, or some other error code if something went wrong.
-//
-static PROFILE_RESULT invoke_perf(Config& config,
-                                  const std::string &perf_path,
-                                  const char *stack_profile_opt,
-                                  unsigned duration,
-                                  const std::string &data_file_path,
-                                  const std::string &perf_stderr_path)
-{
-  pid_t pid = fork();
-
-  if (pid == -1) {
-    PLOG(ERROR) << "Fork failed";
-    return ERR_FORK_FAILED;
-  }
-
-  if (pid == 0) {
-    // child
-
-    // Open file to receive stderr/stdout from perf
-    FILE *efp = fopen(perf_stderr_path.c_str(), "w");
-    if (efp) {
-      dup2(fileno(efp), STDERR_FILENO);
-      dup2(fileno(efp), STDOUT_FILENO);
-    } else {
-      PLOG(WARNING) << "unable to open " << perf_stderr_path << " for writing";
-    }
-
-    // marshall arguments
-    constexpr unsigned max_args = 17;
-    const char *argv[max_args];
-    unsigned slot = 0;
-    argv[slot++] = perf_path.c_str();
-    argv[slot++] = "record";
-
-    // -o perf.data
-    argv[slot++] = "-o";
-    argv[slot++] = data_file_path.c_str();
-
-    // -c/f N
-    std::string p_str;
-    if (config.sampling_frequency > 0) {
-      argv[slot++] = "-f";
-      p_str = android::base::StringPrintf("%u", config.sampling_frequency);
-      argv[slot++] = p_str.c_str();
-    } else if (config.sampling_period > 0) {
-      argv[slot++] = "-c";
-      p_str = android::base::StringPrintf("%u", config.sampling_period);
-      argv[slot++] = p_str.c_str();
-    }
-
-    // -g if desired
-    if (stack_profile_opt) {
-      argv[slot++] = stack_profile_opt;
-      argv[slot++] = "-m";
-      argv[slot++] = "8192";
-    }
-
-    std::string pid_str;
-    if (config.process < 0) {
-      // system wide profiling
-      argv[slot++] = "-a";
-    } else {
-      argv[slot++] = "-p";
-      pid_str = std::to_string(config.process);
-      argv[slot++] = pid_str.c_str();
-    }
-
-    // no need for kernel or other symbols
-    argv[slot++] = "--no-dump-kernel-symbols";
-    argv[slot++] = "--no-dump-symbols";
-
-    // sleep <duration>
-    argv[slot++] = "--duration";
-    std::string d_str = android::base::StringPrintf("%u", duration);
-    argv[slot++] = d_str.c_str();
-
-    // terminator
-    argv[slot++] = nullptr;
-    assert(slot < max_args);
-
-    // record the final command line in the error output file for
-    // posterity/debugging purposes
-    fprintf(stderr, "perf invocation (pid=%d):\n", getpid());
-    for (unsigned i = 0; argv[i] != nullptr; ++i) {
-      fprintf(stderr, "%s%s", i ? " " : "", argv[i]);
-    }
-    fprintf(stderr, "\n");
-
-    // exec
-    execvp(argv[0], (char * const *)argv);
-    fprintf(stderr, "exec failed: %s\n", strerror(errno));
-    exit(1);
-
-  } else {
-    // parent
-
-    // Try to sleep.
-    config.Sleep(duration);
-
-    // We may have been woken up to stop profiling.
-    if (config.ShouldStopProfiling()) {
-      // Send SIGHUP to simpleperf to make it stop.
-      kill(pid, SIGHUP);
-    }
-
-    // Wait for the child, so it's reaped correctly.
-    int st = 0;
-    pid_t reaped = TEMP_FAILURE_RETRY(waitpid(pid, &st, 0));
-
-    auto print_perferr = [&perf_stderr_path]() {
-      std::string tmp;
-      if (android::base::ReadFileToString(perf_stderr_path, &tmp)) {
-        LOG(WARNING) << tmp;
-      } else {
-        PLOG(WARNING) << "Could not read " << perf_stderr_path;
-      }
-    };
-
-    if (reaped == -1) {
-      PLOG(WARNING) << "waitpid failed";
-    } else if (WIFSIGNALED(st)) {
-      if (WTERMSIG(st) == SIGHUP && config.ShouldStopProfiling()) {
-        // That was us...
-        return OK_PROFILE_COLLECTION;
-      }
-      LOG(WARNING) << "perf killed by signal " << WTERMSIG(st);
-      print_perferr();
-    } else if (WEXITSTATUS(st) != 0) {
-      LOG(WARNING) << "perf bad exit status " << WEXITSTATUS(st);
-      print_perferr();
-    } else {
-      return OK_PROFILE_COLLECTION;
-    }
-  }
-
-  return ERR_PERF_RECORD_FAILED;
-}
-
-//
 // Remove all files in the destination directory during initialization
 //
 static void cleanup_destination_dir(const std::string& dest_dir)
@@ -676,13 +536,14 @@
       (config.stack_profile ? "-g" : nullptr);
   const std::string& perf_path = config.perf_path;
 
-  PROFILE_RESULT ret = invoke_perf(config,
-                                   perf_path,
-                                   stack_profile_opt,
-                                   duration,
-                                   data_file_path,
-                                   perf_stderr_path);
-  if (ret != OK_PROFILE_COLLECTION) {
+  android::perfprofd::PerfResult invoke_res =
+      android::perfprofd::InvokePerf(config,
+                                     perf_path,
+                                     stack_profile_opt,
+                                     duration,
+                                     data_file_path,
+                                     perf_stderr_path);
+  if (invoke_res != android::perfprofd::PerfResult::kOK) {
     return nullptr;
   }