General command handler is moved to a separate file

Generic CvdCommandHandler has moved to new, separate
implementation files.

Bug: 244899059
Test: build & run locally
Change-Id: Idcd3e3dce31e82dccc198560bb2eb228da73b60b
diff --git a/host/commands/cvd/Android.bp b/host/commands/cvd/Android.bp
index 9010329..0a9fa4e 100644
--- a/host/commands/cvd/Android.bp
+++ b/host/commands/cvd/Android.bp
@@ -107,6 +107,7 @@
         "server.cc",
         "server_client.cpp",
         "server_command.cpp",
+        "server_command_generic_impl.cpp",
         "server_command_fetch_impl.cpp",
         "server_command_impl.cpp",
         "server_command_start_impl.cpp",
diff --git a/host/commands/cvd/server_command.cpp b/host/commands/cvd/server_command.cpp
index 79ad3c2..c8fdbfb 100644
--- a/host/commands/cvd/server_command.cpp
+++ b/host/commands/cvd/server_command.cpp
@@ -20,207 +20,17 @@
 #include <string>
 #include <vector>
 
-#include <android-base/file.h>
-#include <android-base/logging.h>
 #include <fruit/fruit.h>
 
 #include "cvd_server.pb.h"
 
-#include "common/libs/fs/shared_buf.h"
-#include "common/libs/fs/shared_fd.h"
-#include "common/libs/utils/environment.h"
 #include "common/libs/utils/files.h"
-#include "common/libs/utils/flag_parser.h"
-#include "common/libs/utils/result.h"
-#include "common/libs/utils/subprocess.h"
-#include "host/commands/cvd/command_sequence.h"
 #include "host/commands/cvd/instance_manager.h"
 #include "host/commands/cvd/server_command_fetch_impl.h"
-#include "host/commands/cvd/server_command_impl.h"
+#include "host/commands/cvd/server_command_generic_impl.h"
 #include "host/commands/cvd/server_command_start_impl.h"
-#include "host/libs/config/cuttlefish_config.h"
-#include "host/libs/config/instance_nums.h"
 
 namespace cuttlefish {
-namespace cvd_cmd_impl {
-
-class CvdCommandHandler : public CvdServerHandler {
- public:
-  INJECT(CvdCommandHandler(InstanceManager& instance_manager,
-                           SubprocessWaiter& subprocess_waiter))
-      : instance_manager_(instance_manager),
-        subprocess_waiter_(subprocess_waiter) {}
-
-  Result<bool> CanHandle(const RequestWithStdio& request) const {
-    auto invocation = ParseInvocation(request.Message());
-    return command_to_binary_map_.find(invocation.command) !=
-           command_to_binary_map_.end();
-  }
-  Result<cvd::Response> Handle(const RequestWithStdio& request) override {
-    std::unique_lock interrupt_lock(interruptible_);
-    if (interrupted_) {
-      return CF_ERR("Interrupted");
-    }
-    CF_EXPECT(CanHandle(request));
-    cvd::Response response;
-    response.mutable_command_response();
-
-    auto invocation = ParseInvocation(request.Message());
-
-    auto subcommand_bin = command_to_binary_map_.find(invocation.command);
-    CF_EXPECT(subcommand_bin != command_to_binary_map_.end());
-    auto bin = subcommand_bin->second;
-
-    // HOME is used to possibly set CuttlefishConfig path env variable later.
-    // This env variable is used by subcommands when locating the config.
-    auto request_home = request.Message().command_request().env().find("HOME");
-    std::string home =
-        request_home != request.Message().command_request().env().end()
-            ? request_home->second
-            : StringFromEnv("HOME", ".");
-
-    // Create a copy of args before parsing, to be passed to subcommands.
-    auto args = invocation.arguments;
-    auto args_copy = invocation.arguments;
-
-    auto host_artifacts_path =
-        request.Message().command_request().env().find("ANDROID_HOST_OUT");
-    if (host_artifacts_path ==
-        request.Message().command_request().env().end()) {
-      response.mutable_status()->set_code(cvd::Status::FAILED_PRECONDITION);
-      response.mutable_status()->set_message(
-          "Missing ANDROID_HOST_OUT in client environment.");
-      return response;
-    }
-
-    if (bin == kClearBin) {
-      *response.mutable_status() =
-          instance_manager_.CvdClear(request.Out(), request.Err());
-      return response;
-    }
-
-    if (bin == kFleetBin) {
-      *response.mutable_status() =
-          HandleCvdFleet(request, args, host_artifacts_path->second);
-      return response;
-    }
-
-    Command command("(replaced)");
-    if (bin == kMkdirBin || bin == kLnBin) {
-      command.SetExecutableAndName(bin);
-    } else {
-      auto assembly_info = CF_EXPECT(instance_manager_.GetInstanceGroup(home));
-      command.SetExecutableAndName(assembly_info.host_binaries_dir + bin);
-    }
-    for (const std::string& arg : args_copy) {
-      command.AddParameter(arg);
-    }
-
-    // Set CuttlefishConfig path based on assembly dir,
-    // used by subcommands when locating the CuttlefishConfig.
-    if (request.Message().command_request().env().count(
-            kCuttlefishConfigEnvVarName) == 0) {
-      auto config_path = GetCuttlefishConfigPath(home);
-      if (config_path.ok()) {
-        command.AddEnvironmentVariable(kCuttlefishConfigEnvVarName,
-                                       *config_path);
-      }
-    }
-    for (auto& it : request.Message().command_request().env()) {
-      command.UnsetFromEnvironment(it.first);
-      command.AddEnvironmentVariable(it.first, it.second);
-    }
-
-    // Redirect stdin, stdout, stderr back to the cvd client
-    command.RedirectStdIO(Subprocess::StdIOChannel::kStdIn, request.In());
-    command.RedirectStdIO(Subprocess::StdIOChannel::kStdOut, request.Out());
-    command.RedirectStdIO(Subprocess::StdIOChannel::kStdErr, request.Err());
-    SubprocessOptions options;
-
-    if (request.Message().command_request().wait_behavior() ==
-        cvd::WAIT_BEHAVIOR_START) {
-      options.ExitWithParent(false);
-    }
-
-    const auto& working_dir =
-        request.Message().command_request().working_directory();
-    if (!working_dir.empty()) {
-      auto fd = SharedFD::Open(working_dir, O_RDONLY | O_PATH | O_DIRECTORY);
-      CF_EXPECT(fd->IsOpen(),
-                "Couldn't open \"" << working_dir << "\": " << fd->StrError());
-      command.SetWorkingDirectory(fd);
-    }
-
-    CF_EXPECT(subprocess_waiter_.Setup(command.Start(options)));
-
-    if (request.Message().command_request().wait_behavior() ==
-        cvd::WAIT_BEHAVIOR_START) {
-      response.mutable_status()->set_code(cvd::Status::OK);
-      return response;
-    }
-
-    interrupt_lock.unlock();
-
-    auto infop = CF_EXPECT(subprocess_waiter_.Wait());
-
-    if (infop.si_code == CLD_EXITED && bin == kStopBin) {
-      instance_manager_.RemoveInstanceGroup(home);
-    }
-
-    return ResponseFromSiginfo(infop);
-  }
-  Result<void> Interrupt() override {
-    std::scoped_lock interrupt_lock(interruptible_);
-    interrupted_ = true;
-    CF_EXPECT(subprocess_waiter_.Interrupt());
-    return {};
-  }
-
- private:
-  cvd::Status HandleCvdFleet(const RequestWithStdio& request,
-                             const std::vector<std::string>& args,
-                             const std::string& host_artifacts_path) {
-    auto env_config = request.Message().command_request().env().find(
-        kCuttlefishConfigEnvVarName);
-    std::optional<std::string> config_path = std::nullopt;
-    if (env_config != request.Message().command_request().env().end()) {
-      config_path = env_config->second;
-    }
-    return instance_manager_.CvdFleet(request.Out(), request.Err(), config_path,
-                                      host_artifacts_path, args);
-  }
-  InstanceManager& instance_manager_;
-  SubprocessWaiter& subprocess_waiter_;
-  std::mutex interruptible_;
-  bool interrupted_ = false;
-
-  static constexpr char kHostBugreportBin[] = "cvd_internal_host_bugreport";
-  static constexpr char kLnBin[] = "ln";
-  static constexpr char kMkdirBin[] = "mkdir";
-
-  static constexpr char kClearBin[] =
-      "clear_placeholder";  // Unused, runs CvdClear()
-  static constexpr char kFleetBin[] =
-      "fleet_placeholder";  // Unused, runs CvdFleet()
-
-  static const std::map<std::string, std::string> command_to_binary_map_;
-};
-
-const std::map<std::string, std::string>
-    CvdCommandHandler::command_to_binary_map_ = {
-        {"host_bugreport", kHostBugreportBin},
-        {"cvd_host_bugreport", kHostBugreportBin},
-        {"status", kStatusBin},
-        {"cvd_status", kStatusBin},
-        {"stop", kStopBin},
-        {"stop_cvd", kStopBin},
-        {"clear", kClearBin},
-        {"mkdir", kMkdirBin},
-        {"ln", kLnBin},
-        {"fleet", kFleetBin},
-};
-
-}  // namespace cvd_cmd_impl
 
 CommandInvocation ParseInvocation(const cvd::Request& request) {
   CommandInvocation invocation;
diff --git a/host/commands/cvd/server_command_generic_impl.cpp b/host/commands/cvd/server_command_generic_impl.cpp
new file mode 100644
index 0000000..10e1cdb
--- /dev/null
+++ b/host/commands/cvd/server_command_generic_impl.cpp
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2022 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 "host/commands/cvd/server_command_generic_impl.h"
+
+#include <android-base/file.h>
+
+#include "common/libs/fs/shared_fd.h"
+#include "common/libs/utils/environment.h"
+#include "host/commands/cvd/command_sequence.h"
+#include "host/libs/config/cuttlefish_config.h"
+#include "host/libs/config/instance_nums.h"
+
+namespace cuttlefish {
+namespace cvd_cmd_impl {
+
+Result<bool> CvdCommandHandler::CanHandle(
+    const RequestWithStdio& request) const {
+  auto invocation = ParseInvocation(request.Message());
+  return command_to_binary_map_.find(invocation.command) !=
+         command_to_binary_map_.end();
+}
+
+Result<void> CvdCommandHandler::Interrupt() {
+  std::scoped_lock interrupt_lock(interruptible_);
+  interrupted_ = true;
+  CF_EXPECT(subprocess_waiter_.Interrupt());
+  return {};
+}
+
+Result<cvd::Response> CvdCommandHandler::Handle(
+    const RequestWithStdio& request) {
+  std::unique_lock interrupt_lock(interruptible_);
+  if (interrupted_) {
+    return CF_ERR("Interrupted");
+  }
+  CF_EXPECT(CanHandle(request));
+  cvd::Response response;
+  response.mutable_command_response();
+
+  auto invocation = ParseInvocation(request.Message());
+
+  auto subcommand_bin = command_to_binary_map_.find(invocation.command);
+  CF_EXPECT(subcommand_bin != command_to_binary_map_.end());
+  auto bin = subcommand_bin->second;
+
+  // HOME is used to possibly set CuttlefishConfig path env variable later.
+  // This env variable is used by subcommands when locating the config.
+  auto request_home = request.Message().command_request().env().find("HOME");
+  std::string home =
+      request_home != request.Message().command_request().env().end()
+          ? request_home->second
+          : StringFromEnv("HOME", ".");
+
+  // Create a copy of args before parsing, to be passed to subcommands.
+  auto args = invocation.arguments;
+  auto args_copy = invocation.arguments;
+
+  auto host_artifacts_path =
+      request.Message().command_request().env().find("ANDROID_HOST_OUT");
+  if (host_artifacts_path == request.Message().command_request().env().end()) {
+    response.mutable_status()->set_code(cvd::Status::FAILED_PRECONDITION);
+    response.mutable_status()->set_message(
+        "Missing ANDROID_HOST_OUT in client environment.");
+    return response;
+  }
+
+  if (bin == kClearBin) {
+    *response.mutable_status() =
+        instance_manager_.CvdClear(request.Out(), request.Err());
+    return response;
+  }
+
+  if (bin == kFleetBin) {
+    *response.mutable_status() =
+        HandleCvdFleet(request, args, host_artifacts_path->second);
+    return response;
+  }
+
+  Command command("(replaced)");
+  if (bin == kMkdirBin || bin == kLnBin) {
+    command.SetExecutableAndName(bin);
+  } else {
+    auto assembly_info = CF_EXPECT(instance_manager_.GetInstanceGroup(home));
+    command.SetExecutableAndName(assembly_info.host_binaries_dir + bin);
+  }
+  for (const std::string& arg : args_copy) {
+    command.AddParameter(arg);
+  }
+
+  // Set CuttlefishConfig path based on assembly dir,
+  // used by subcommands when locating the CuttlefishConfig.
+  if (request.Message().command_request().env().count(
+          kCuttlefishConfigEnvVarName) == 0) {
+    auto config_path = GetCuttlefishConfigPath(home);
+    if (config_path.ok()) {
+      command.AddEnvironmentVariable(kCuttlefishConfigEnvVarName, *config_path);
+    }
+  }
+  for (auto& it : request.Message().command_request().env()) {
+    command.UnsetFromEnvironment(it.first);
+    command.AddEnvironmentVariable(it.first, it.second);
+  }
+
+  // Redirect stdin, stdout, stderr back to the cvd client
+  command.RedirectStdIO(Subprocess::StdIOChannel::kStdIn, request.In());
+  command.RedirectStdIO(Subprocess::StdIOChannel::kStdOut, request.Out());
+  command.RedirectStdIO(Subprocess::StdIOChannel::kStdErr, request.Err());
+  SubprocessOptions options;
+
+  if (request.Message().command_request().wait_behavior() ==
+      cvd::WAIT_BEHAVIOR_START) {
+    options.ExitWithParent(false);
+  }
+
+  const auto& working_dir =
+      request.Message().command_request().working_directory();
+  if (!working_dir.empty()) {
+    auto fd = SharedFD::Open(working_dir, O_RDONLY | O_PATH | O_DIRECTORY);
+    CF_EXPECT(fd->IsOpen(),
+              "Couldn't open \"" << working_dir << "\": " << fd->StrError());
+    command.SetWorkingDirectory(fd);
+  }
+
+  CF_EXPECT(subprocess_waiter_.Setup(command.Start(options)));
+
+  if (request.Message().command_request().wait_behavior() ==
+      cvd::WAIT_BEHAVIOR_START) {
+    response.mutable_status()->set_code(cvd::Status::OK);
+    return response;
+  }
+
+  interrupt_lock.unlock();
+
+  auto infop = CF_EXPECT(subprocess_waiter_.Wait());
+
+  if (infop.si_code == CLD_EXITED && bin == kStopBin) {
+    instance_manager_.RemoveInstanceGroup(home);
+  }
+
+  return ResponseFromSiginfo(infop);
+}
+
+cvd::Status CvdCommandHandler::HandleCvdFleet(
+    const RequestWithStdio& request, const std::vector<std::string>& args,
+    const std::string& host_artifacts_path) {
+  auto env_config = request.Message().command_request().env().find(
+      kCuttlefishConfigEnvVarName);
+  std::optional<std::string> config_path = std::nullopt;
+  if (env_config != request.Message().command_request().env().end()) {
+    config_path = env_config->second;
+  }
+  return instance_manager_.CvdFleet(request.Out(), request.Err(), config_path,
+                                    host_artifacts_path, args);
+}
+
+const std::map<std::string, std::string>
+    CvdCommandHandler::command_to_binary_map_ = {
+        {"host_bugreport", kHostBugreportBin},
+        {"cvd_host_bugreport", kHostBugreportBin},
+        {"status", kStatusBin},
+        {"cvd_status", kStatusBin},
+        {"stop", kStopBin},
+        {"stop_cvd", kStopBin},
+        {"clear", kClearBin},
+        {"mkdir", kMkdirBin},
+        {"ln", kLnBin},
+        {"fleet", kFleetBin},
+};
+
+}  // namespace cvd_cmd_impl
+}  // namespace cuttlefish
diff --git a/host/commands/cvd/server_command_generic_impl.h b/host/commands/cvd/server_command_generic_impl.h
new file mode 100644
index 0000000..0815c3a
--- /dev/null
+++ b/host/commands/cvd/server_command_generic_impl.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+#pragma once
+
+#include <mutex>
+
+#include <fruit/fruit.h>
+
+#include "cvd_server.pb.h"
+
+#include "common/libs/utils/result.h"
+#include "common/libs/utils/subprocess.h"
+#include "host/commands/cvd/instance_manager.h"
+#include "host/commands/cvd/server.h"
+#include "host/commands/cvd/server_command_impl.h"
+
+namespace cuttlefish {
+namespace cvd_cmd_impl {
+
+class CvdCommandHandler : public CvdServerHandler {
+ public:
+  INJECT(CvdCommandHandler(InstanceManager& instance_manager,
+                           SubprocessWaiter& subprocess_waiter))
+      : instance_manager_(instance_manager),
+        subprocess_waiter_(subprocess_waiter) {}
+
+  Result<bool> CanHandle(const RequestWithStdio& request) const;
+  Result<cvd::Response> Handle(const RequestWithStdio& request) override;
+  Result<void> Interrupt() override;
+
+ private:
+  cvd::Status HandleCvdFleet(const RequestWithStdio& request,
+                             const std::vector<std::string>& args,
+                             const std::string& host_artifacts_path);
+  InstanceManager& instance_manager_;
+  SubprocessWaiter& subprocess_waiter_;
+  std::mutex interruptible_;
+  bool interrupted_ = false;
+
+  static constexpr char kHostBugreportBin[] = "cvd_internal_host_bugreport";
+  static constexpr char kLnBin[] = "ln";
+  static constexpr char kMkdirBin[] = "mkdir";
+
+  static constexpr char kClearBin[] =
+      "clear_placeholder";  // Unused, runs CvdClear()
+  static constexpr char kFleetBin[] =
+      "fleet_placeholder";  // Unused, runs CvdFleet()
+
+  static const std::map<std::string, std::string> command_to_binary_map_;
+};
+
+}  // namespace cvd_cmd_impl
+}  // namespace cuttlefish