Separated Acloud Command Handlers
Acloud has three command handlers, and one library class.
The four have been separated.
Bug: 266441203
Test: m hosttar
Change-Id: I7bf7cce45eaed6f4a3341c167484532b1a21269e
diff --git a/host/commands/cvd/acloud/converter.cpp b/host/commands/cvd/acloud/converter.cpp
index 7d270d3..7a3ef03 100644
--- a/host/commands/cvd/acloud/converter.cpp
+++ b/host/commands/cvd/acloud/converter.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include "host/commands/cvd/acloud/converter.h"
+
#include <sys/stat.h>
#include <cstdio>
@@ -26,7 +28,6 @@
#include <android-base/strings.h>
#include <google/protobuf/text_format.h>
-#include "common/libs/fs/shared_buf.h"
#include "common/libs/fs/shared_fd.h"
#include "common/libs/utils/files.h"
#include "common/libs/utils/flag_parser.h"
@@ -40,31 +41,13 @@
#include "host/commands/cvd/instance_lock.h"
#include "host/commands/cvd/selector/selector_constants.h"
#include "host/commands/cvd/server_client.h"
-#include "host/commands/cvd/server_command/acloud.h"
#include "host/commands/cvd/server_command/utils.h"
#include "host/commands/cvd/types.h"
#include "host/libs/config/cuttlefish_config.h"
namespace cuttlefish {
-
-static constexpr char kTranslatorHelpMessage[] =
- R"(Cuttlefish Virtual Device (CVD) CLI.
-
-usage: cvd acloud translator <args>
-
-Args:
- --opt-out Opt-out CVD Acloud and choose to run original Python Acloud.
- --opt-in Opt-in and run CVD Acloud as default.
-Both -opt-out and --opt-in are mutually exclusive.
-)";
-
namespace {
-struct ConvertedAcloudCreateCommand {
- InstanceLockFile lock;
- std::vector<RequestWithStdio> requests;
-};
-
// Image names to search
const std::vector<std::string> _KERNEL_IMAGE_NAMES = {"kernel", "bzImage",
"Image"};
@@ -111,13 +94,19 @@
return android::base::Split(stdout_str, "\n");
}
-class ConvertAcloudCreateCommand {
+} // namespace
+
+// body of pure virtual destructor required by C++
+ConvertAcloudCreateCommand::~ConvertAcloudCreateCommand() {}
+
+class ConvertAcloudCreateCommandImpl : public ConvertAcloudCreateCommand {
public:
- INJECT(ConvertAcloudCreateCommand(InstanceLockFileManager& lock_file_manager))
+ INJECT(ConvertAcloudCreateCommandImpl(
+ InstanceLockFileManager& lock_file_manager))
: fetch_cvd_args_file_(""),
fetch_command_str_(""),
lock_file_manager_(lock_file_manager) {}
-
+ ~ConvertAcloudCreateCommandImpl() override = default;
Result<ConvertedAcloudCreateCommand> Convert(
const RequestWithStdio& request) {
auto arguments = ParseInvocation(request.Message()).arguments;
@@ -712,181 +701,25 @@
return ret;
}
- public:
- std::string fetch_cvd_args_file_;
- std::string fetch_command_str_;
+ const std::string& FetchCvdArgsFile() const override {
+ return fetch_cvd_args_file_;
+ }
+
+ const std::string& FetchCommandString() const override {
+ return fetch_command_str_;
+ }
private:
+ std::string fetch_cvd_args_file_;
+ std::string fetch_command_str_;
InstanceLockFileManager& lock_file_manager_;
};
-static bool IsSubOperationSupported(const RequestWithStdio& request) {
- auto invocation = ParseInvocation(request.Message());
- if (invocation.arguments.empty()) {
- return false;
- }
- return invocation.arguments[0] == "create";
-}
-
-class TryAcloudCommand : public CvdServerHandler {
- public:
- INJECT(TryAcloudCommand(ConvertAcloudCreateCommand& converter,
- ANNOTATED(AcloudTranslatorOptOut,
- const std::atomic<bool>&) optout))
- : converter_(converter), optout_(optout) {}
- ~TryAcloudCommand() = default;
-
- Result<bool> CanHandle(const RequestWithStdio& request) const override {
- auto invocation = ParseInvocation(request.Message());
- return invocation.command == "try-acloud";
- }
-
- cvd_common::Args CmdList() const override { return {"try-acloud"}; }
-
- Result<cvd::Response> Handle(const RequestWithStdio& request) override {
- CF_EXPECT(CanHandle(request));
- CF_EXPECT(IsSubOperationSupported(request));
- CF_EXPECT(converter_.Convert(request));
- // currently, optout/optin feature only works in local instance
- // remote instance still uses legacy python acloud
- CF_EXPECT(!optout_);
- cvd::Response response;
- response.mutable_command_response();
- return response;
- }
- Result<void> Interrupt() override { return CF_ERR("Can't be interrupted."); }
-
- private:
- ConvertAcloudCreateCommand& converter_;
- const std::atomic<bool>& optout_;
-};
-
-class AcloudTranslatorCommand : public CvdServerHandler {
- public:
- INJECT(AcloudTranslatorCommand(ANNOTATED(AcloudTranslatorOptOut,
- std::atomic<bool>&) optout))
- : optout_(optout) {}
- ~AcloudTranslatorCommand() = default;
-
- Result<bool> CanHandle(const RequestWithStdio& request) const override {
- auto invocation = ParseInvocation(request.Message());
- if (invocation.arguments.size() >= 2) {
- if (invocation.command == "acloud" &&
- invocation.arguments[0] == "translator") {
- return true;
- }
- }
- return false;
- }
-
- cvd_common::Args CmdList() const override { return {}; }
-
- Result<cvd::Response> Handle(const RequestWithStdio& request) override {
- CF_EXPECT(CanHandle(request));
- auto invocation = ParseInvocation(request.Message());
- if (invocation.arguments.empty() || invocation.arguments.size() < 2) {
- return CF_ERR("Translator command not support");
- }
-
- // cvd acloud translator --opt-out
- // cvd acloud translator --opt-in
- cvd::Response response;
- response.mutable_command_response();
- bool help = false;
- bool flag_optout = false;
- bool flag_optin = false;
- std::vector<Flag> translator_flags = {
- GflagsCompatFlag("help", help),
- GflagsCompatFlag("opt-out", flag_optout),
- GflagsCompatFlag("opt-in", flag_optin),
- };
- CF_EXPECT(ParseFlags(translator_flags, invocation.arguments),
- "Failed to process translator flag.");
- if (help) {
- WriteAll(request.Out(), kTranslatorHelpMessage);
- return response;
- }
- CF_EXPECT(flag_optout != flag_optin,
- "Only one of --opt-out or --opt-in should be given.");
- optout_ = flag_optout;
- return response;
- }
- Result<void> Interrupt() override { return CF_ERR("Can't be interrupted."); }
-
- private:
- std::atomic<bool>& optout_;
-};
-
-class AcloudCommand : public CvdServerHandler {
- public:
- INJECT(AcloudCommand(CommandSequenceExecutor& executor,
- ConvertAcloudCreateCommand& converter))
- : executor_(executor), converter_(converter) {}
- ~AcloudCommand() = default;
-
- Result<bool> CanHandle(const RequestWithStdio& request) const override {
- auto invocation = ParseInvocation(request.Message());
- if (invocation.arguments.size() >= 2) {
- if (invocation.command == "acloud" &&
- invocation.arguments[0] == "translator") {
- return false;
- }
- }
- return invocation.command == "acloud";
- }
-
- cvd_common::Args CmdList() const override { return {"acloud"}; }
-
- Result<cvd::Response> Handle(const RequestWithStdio& request) override {
- std::unique_lock interrupt_lock(interrupt_mutex_);
- if (interrupted_) {
- return CF_ERR("Interrupted");
- }
- CF_EXPECT(CanHandle(request));
- CF_EXPECT(IsSubOperationSupported(request));
- auto converted = CF_EXPECT(converter_.Convert(request));
- interrupt_lock.unlock();
- CF_EXPECT(executor_.Execute(converted.requests, request.Err()));
-
- CF_EXPECT(converted.lock.Status(InUseState::kInUse));
-
- if (converter_.fetch_command_str_ != "") {
- // has cvd fetch command, update the fetch cvd command file
- using android::base::WriteStringToFile;
- CF_EXPECT(WriteStringToFile(converter_.fetch_command_str_,
- converter_.fetch_cvd_args_file_),
- true);
- }
-
- cvd::Response response;
- response.mutable_command_response();
- return response;
- }
- Result<void> Interrupt() override {
- std::scoped_lock interrupt_lock(interrupt_mutex_);
- interrupted_ = true;
- CF_EXPECT(executor_.Interrupt());
- return {};
- }
-
- private:
- CommandSequenceExecutor& executor_;
- ConvertAcloudCreateCommand& converter_;
-
- std::mutex interrupt_mutex_;
- bool interrupted_ = false;
-};
-
-} // namespace
-
-fruit::Component<fruit::Required<
- CommandSequenceExecutor,
- fruit::Annotated<AcloudTranslatorOptOut, std::atomic<bool>>>>
-AcloudCommandComponent() {
+fruit::Component<fruit::Required<InstanceLockFileManager>,
+ ConvertAcloudCreateCommand>
+AcloudCreateConvertCommandComponent() {
return fruit::createComponent()
- .addMultibinding<CvdServerHandler, AcloudCommand>()
- .addMultibinding<CvdServerHandler, TryAcloudCommand>()
- .addMultibinding<CvdServerHandler, AcloudTranslatorCommand>();
+ .bind<ConvertAcloudCreateCommand, ConvertAcloudCreateCommandImpl>();
}
} // namespace cuttlefish
diff --git a/host/commands/cvd/acloud/converter.h b/host/commands/cvd/acloud/converter.h
new file mode 100644
index 0000000..01d1470
--- /dev/null
+++ b/host/commands/cvd/acloud/converter.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2023 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 <atomic>
+
+#include <fruit/fruit.h>
+
+#include "host/commands/cvd/instance_lock.h"
+#include "host/commands/cvd/server_client.h"
+
+namespace cuttlefish {
+
+struct ConvertedAcloudCreateCommand {
+ InstanceLockFile lock;
+ std::vector<RequestWithStdio> requests;
+};
+
+class ConvertAcloudCreateCommand {
+ public:
+ virtual Result<ConvertedAcloudCreateCommand> Convert(
+ const RequestWithStdio& request) = 0;
+ virtual const std::string& FetchCvdArgsFile() const = 0;
+ virtual const std::string& FetchCommandString() const = 0;
+ /*
+ * Android prouction build system appears to mandate virtual
+ * destructor.
+ */
+ virtual ~ConvertAcloudCreateCommand() = 0;
+};
+
+fruit::Component<fruit::Required<InstanceLockFileManager>,
+ ConvertAcloudCreateCommand>
+AcloudCreateConvertCommandComponent();
+
+} // namespace cuttlefish
diff --git a/host/commands/cvd/server.cc b/host/commands/cvd/server.cc
index 780cfba..d4a8622 100644
--- a/host/commands/cvd/server.cc
+++ b/host/commands/cvd/server.cc
@@ -111,7 +111,7 @@
.bindInstance<
fruit::Annotated<AcloudTranslatorOptOut, std::atomic<bool>>>(
server->optout_)
- .install(AcloudCommandComponent)
+ .install(CvdAcloudComponent)
.install(CvdCmdlistComponent)
.install(CommandSequenceExecutorComponent)
.install(CvdCrosVmComponent)
diff --git a/host/commands/cvd/server_command/Android.bp b/host/commands/cvd/server_command/Android.bp
index 44fbe50..a006b80 100644
--- a/host/commands/cvd/server_command/Android.bp
+++ b/host/commands/cvd/server_command/Android.bp
@@ -21,6 +21,10 @@
name: "libcvd_sub_commands",
srcs: [
"utils.cpp",
+ "acloud.cpp",
+ "acloud_command.cpp",
+ "acloud_common.cpp",
+ "acloud_translator.cpp",
"cmd_list.cpp",
"components.cpp",
"crosvm.cpp",
@@ -44,7 +48,11 @@
"start.cpp",
"start_impl.cpp",
"subprocess_waiter.cpp",
+ "try_acloud.cpp",
"version.cpp",
],
+ static_libs: [
+ "libcvd_acloud",
+ ],
defaults: ["cvd_lib_defaults"],
}
diff --git a/host/commands/cvd/server_command/acloud.cpp b/host/commands/cvd/server_command/acloud.cpp
new file mode 100644
index 0000000..df1d73d
--- /dev/null
+++ b/host/commands/cvd/server_command/acloud.cpp
@@ -0,0 +1,42 @@
+/*
+ * 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/acloud.h"
+
+#include <atomic>
+
+#include <fruit/fruit.h>
+
+#include "host/commands/cvd/acloud/converter.h"
+#include "host/commands/cvd/server_command/acloud.h"
+#include "host/commands/cvd/server_command/acloud_command.h"
+#include "host/commands/cvd/server_command/acloud_translator.h"
+#include "host/commands/cvd/server_command/try_acloud.h"
+
+namespace cuttlefish {
+
+fruit::Component<fruit::Required<
+ CommandSequenceExecutor,
+ fruit::Annotated<AcloudTranslatorOptOut, std::atomic<bool>>>>
+CvdAcloudComponent() {
+ return fruit::createComponent()
+ .install(AcloudCreateConvertCommandComponent)
+ .install(AcloudCommandComponent)
+ .install(TryAcloudCommandComponent)
+ .install(AcloudTranslatorCommandComponent);
+}
+
+} // namespace cuttlefish
diff --git a/host/commands/cvd/server_command/acloud.h b/host/commands/cvd/server_command/acloud.h
index 0adf6f2..c476165 100644
--- a/host/commands/cvd/server_command/acloud.h
+++ b/host/commands/cvd/server_command/acloud.h
@@ -21,13 +21,13 @@
#include <fruit/fruit.h>
#include "host/commands/cvd/command_sequence.h"
+#include "host/commands/cvd/server_command/acloud_common.h"
namespace cuttlefish {
-struct AcloudTranslatorOptOut {};
-
fruit::Component<fruit::Required<
CommandSequenceExecutor,
fruit::Annotated<AcloudTranslatorOptOut, std::atomic<bool>>>>
-AcloudCommandComponent();
-} // namespace cuttlefish
+CvdAcloudComponent();
+
+}
diff --git a/host/commands/cvd/server_command/acloud_command.cpp b/host/commands/cvd/server_command/acloud_command.cpp
new file mode 100644
index 0000000..e9ea96d
--- /dev/null
+++ b/host/commands/cvd/server_command/acloud_command.cpp
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2023 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/acloud_command.h"
+
+#include <atomic>
+#include <mutex>
+
+#include <android-base/file.h>
+#include <android-base/strings.h>
+#include <fruit/fruit.h>
+
+#include "common/libs/utils/result.h"
+#include "cvd_server.pb.h"
+#include "host/commands/cvd/instance_lock.h"
+#include "host/commands/cvd/server_command/acloud_common.h"
+#include "host/commands/cvd/server_command/server_handler.h"
+#include "host/commands/cvd/server_command/utils.h"
+#include "host/commands/cvd/types.h"
+
+namespace cuttlefish {
+
+class AcloudCommand : public CvdServerHandler {
+ public:
+ INJECT(AcloudCommand(CommandSequenceExecutor& executor,
+ ConvertAcloudCreateCommand& converter))
+ : executor_(executor), converter_(converter) {}
+ ~AcloudCommand() = default;
+
+ Result<bool> CanHandle(const RequestWithStdio& request) const override {
+ auto invocation = ParseInvocation(request.Message());
+ if (invocation.arguments.size() >= 2) {
+ if (invocation.command == "acloud" &&
+ invocation.arguments[0] == "translator") {
+ return false;
+ }
+ }
+ return invocation.command == "acloud";
+ }
+
+ cvd_common::Args CmdList() const override { return {"acloud"}; }
+
+ Result<cvd::Response> Handle(const RequestWithStdio& request) override {
+ std::unique_lock interrupt_lock(interrupt_mutex_);
+ if (interrupted_) {
+ return CF_ERR("Interrupted");
+ }
+ CF_EXPECT(CanHandle(request));
+ CF_EXPECT(IsSubOperationSupported(request));
+ auto converted = CF_EXPECT(converter_.Convert(request));
+ interrupt_lock.unlock();
+ CF_EXPECT(executor_.Execute(converted.requests, request.Err()));
+
+ CF_EXPECT(converted.lock.Status(InUseState::kInUse));
+
+ if (converter_.FetchCommandString() != "") {
+ // has cvd fetch command, update the fetch cvd command file
+ using android::base::WriteStringToFile;
+ CF_EXPECT(WriteStringToFile(converter_.FetchCommandString(),
+ converter_.FetchCvdArgsFile()),
+ true);
+ }
+
+ cvd::Response response;
+ response.mutable_command_response();
+ return response;
+ }
+ Result<void> Interrupt() override {
+ std::scoped_lock interrupt_lock(interrupt_mutex_);
+ interrupted_ = true;
+ CF_EXPECT(executor_.Interrupt());
+ return {};
+ }
+
+ private:
+ CommandSequenceExecutor& executor_;
+ ConvertAcloudCreateCommand& converter_;
+
+ std::mutex interrupt_mutex_;
+ bool interrupted_ = false;
+};
+
+fruit::Component<
+ fruit::Required<CommandSequenceExecutor, ConvertAcloudCreateCommand>>
+AcloudCommandComponent() {
+ return fruit::createComponent()
+ .addMultibinding<CvdServerHandler, AcloudCommand>();
+}
+
+} // namespace cuttlefish
diff --git a/host/commands/cvd/server_command/acloud_command.h b/host/commands/cvd/server_command/acloud_command.h
new file mode 100644
index 0000000..a0a87e1
--- /dev/null
+++ b/host/commands/cvd/server_command/acloud_command.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2023 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 <atomic>
+
+#include <fruit/fruit.h>
+
+#include "host/commands/cvd/acloud/converter.h"
+#include "host/commands/cvd/command_sequence.h"
+
+namespace cuttlefish {
+
+fruit::Component<
+ fruit::Required<CommandSequenceExecutor, ConvertAcloudCreateCommand>>
+AcloudCommandComponent();
+
+}
diff --git a/host/commands/cvd/server_command/acloud_common.cpp b/host/commands/cvd/server_command/acloud_common.cpp
new file mode 100644
index 0000000..4c343bb
--- /dev/null
+++ b/host/commands/cvd/server_command/acloud_common.cpp
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2023 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/acloud_common.h"
+
+#include "host/commands/cvd/server_command/utils.h"
+
+namespace cuttlefish {
+
+bool IsSubOperationSupported(const RequestWithStdio& request) {
+ auto invocation = ParseInvocation(request.Message());
+ if (invocation.arguments.empty()) {
+ return false;
+ }
+ return invocation.arguments[0] == "create";
+}
+
+} // namespace cuttlefish
diff --git a/host/commands/cvd/server_command/acloud_common.h b/host/commands/cvd/server_command/acloud_common.h
new file mode 100644
index 0000000..820973f
--- /dev/null
+++ b/host/commands/cvd/server_command/acloud_common.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2023 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 "host/commands/cvd/server_client.h"
+
+namespace cuttlefish {
+
+struct AcloudTranslatorOptOut {};
+
+bool IsSubOperationSupported(const RequestWithStdio& request);
+
+} // namespace cuttlefish
diff --git a/host/commands/cvd/server_command/acloud_translator.cpp b/host/commands/cvd/server_command/acloud_translator.cpp
new file mode 100644
index 0000000..7368540
--- /dev/null
+++ b/host/commands/cvd/server_command/acloud_translator.cpp
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2023 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/acloud_translator.h"
+
+#include <mutex>
+
+#include <fruit/fruit.h>
+
+#include "common/libs/fs/shared_buf.h"
+#include "common/libs/utils/flag_parser.h"
+#include "common/libs/utils/result.h"
+#include "cvd_server.pb.h"
+#include "host/commands/cvd/server_client.h"
+#include "host/commands/cvd/server_command/server_handler.h"
+#include "host/commands/cvd/server_command/utils.h"
+#include "host/commands/cvd/types.h"
+
+namespace cuttlefish {
+
+static constexpr char kTranslatorHelpMessage[] =
+ R"(Cuttlefish Virtual Device (CVD) CLI.
+
+usage: cvd acloud translator <args>
+
+Args:
+ --opt-out Opt-out CVD Acloud and choose to run original Python Acloud.
+ --opt-in Opt-in and run CVD Acloud as default.
+Both -opt-out and --opt-in are mutually exclusive.
+)";
+
+class AcloudTranslatorCommand : public CvdServerHandler {
+ public:
+ INJECT(AcloudTranslatorCommand(ANNOTATED(AcloudTranslatorOptOut,
+ std::atomic<bool>&) optout))
+ : optout_(optout) {}
+ ~AcloudTranslatorCommand() = default;
+
+ Result<bool> CanHandle(const RequestWithStdio& request) const override {
+ auto invocation = ParseInvocation(request.Message());
+ if (invocation.arguments.size() >= 2) {
+ if (invocation.command == "acloud" &&
+ invocation.arguments[0] == "translator") {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ cvd_common::Args CmdList() const override { return {}; }
+
+ Result<cvd::Response> Handle(const RequestWithStdio& request) override {
+ CF_EXPECT(CanHandle(request));
+ auto invocation = ParseInvocation(request.Message());
+ if (invocation.arguments.empty() || invocation.arguments.size() < 2) {
+ return CF_ERR("Translator command not support");
+ }
+
+ // cvd acloud translator --opt-out
+ // cvd acloud translator --opt-in
+ cvd::Response response;
+ response.mutable_command_response();
+ bool help = false;
+ bool flag_optout = false;
+ bool flag_optin = false;
+ std::vector<Flag> translator_flags = {
+ GflagsCompatFlag("help", help),
+ GflagsCompatFlag("opt-out", flag_optout),
+ GflagsCompatFlag("opt-in", flag_optin),
+ };
+ CF_EXPECT(ParseFlags(translator_flags, invocation.arguments),
+ "Failed to process translator flag.");
+ if (help) {
+ WriteAll(request.Out(), kTranslatorHelpMessage);
+ return response;
+ }
+ CF_EXPECT(flag_optout != flag_optin,
+ "Only one of --opt-out or --opt-in should be given.");
+ optout_ = flag_optout;
+ return response;
+ }
+ Result<void> Interrupt() override { return CF_ERR("Can't be interrupted."); }
+
+ private:
+ std::atomic<bool>& optout_;
+};
+
+fruit::Component<fruit::Required<
+ fruit::Annotated<AcloudTranslatorOptOut, std::atomic<bool>>>>
+AcloudTranslatorCommandComponent() {
+ return fruit::createComponent()
+ .addMultibinding<CvdServerHandler, AcloudTranslatorCommand>();
+}
+
+} // namespace cuttlefish
diff --git a/host/commands/cvd/server_command/acloud_translator.h b/host/commands/cvd/server_command/acloud_translator.h
new file mode 100644
index 0000000..45232a5
--- /dev/null
+++ b/host/commands/cvd/server_command/acloud_translator.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2023 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 <atomic>
+
+#include <fruit/fruit.h>
+
+#include "host/commands/cvd/server_command/acloud_common.h"
+
+namespace cuttlefish {
+
+fruit::Component<fruit::Required<
+ fruit::Annotated<AcloudTranslatorOptOut, std::atomic<bool>>>>
+AcloudTranslatorCommandComponent();
+
+}
diff --git a/host/commands/cvd/server_command/try_acloud.cpp b/host/commands/cvd/server_command/try_acloud.cpp
new file mode 100644
index 0000000..6b72033
--- /dev/null
+++ b/host/commands/cvd/server_command/try_acloud.cpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2023 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/try_acloud.h"
+
+#include <mutex>
+
+#include <fruit/fruit.h>
+
+#include "common/libs/utils/result.h"
+#include "cvd_server.pb.h"
+#include "host/commands/cvd/server_command/server_handler.h"
+#include "host/commands/cvd/server_command/utils.h"
+#include "host/commands/cvd/types.h"
+
+namespace cuttlefish {
+
+class TryAcloudCommand : public CvdServerHandler {
+ public:
+ INJECT(TryAcloudCommand(ConvertAcloudCreateCommand& converter,
+ ANNOTATED(AcloudTranslatorOptOut,
+ const std::atomic<bool>&) optout))
+ : converter_(converter), optout_(optout) {}
+ ~TryAcloudCommand() = default;
+
+ Result<bool> CanHandle(const RequestWithStdio& request) const override {
+ auto invocation = ParseInvocation(request.Message());
+ return invocation.command == "try-acloud";
+ }
+
+ cvd_common::Args CmdList() const override { return {"try-acloud"}; }
+
+ Result<cvd::Response> Handle(const RequestWithStdio& request) override {
+ CF_EXPECT(CanHandle(request));
+ CF_EXPECT(IsSubOperationSupported(request));
+ CF_EXPECT(converter_.Convert(request));
+ // currently, optout/optin feature only works in local instance
+ // remote instance still uses legacy python acloud
+ CF_EXPECT(!optout_);
+ cvd::Response response;
+ response.mutable_command_response();
+ return response;
+ }
+ Result<void> Interrupt() override { return CF_ERR("Can't be interrupted."); }
+
+ private:
+ ConvertAcloudCreateCommand& converter_;
+ const std::atomic<bool>& optout_;
+};
+
+fruit::Component<fruit::Required<
+ ConvertAcloudCreateCommand,
+ fruit::Annotated<AcloudTranslatorOptOut, std::atomic<bool>>>>
+TryAcloudCommandComponent() {
+ return fruit::createComponent()
+ .addMultibinding<CvdServerHandler, TryAcloudCommand>();
+}
+
+} // namespace cuttlefish
diff --git a/host/commands/cvd/server_command/try_acloud.h b/host/commands/cvd/server_command/try_acloud.h
new file mode 100644
index 0000000..68212c2
--- /dev/null
+++ b/host/commands/cvd/server_command/try_acloud.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2023 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 <fruit/fruit.h>
+
+#include "host/commands/cvd/acloud/converter.h"
+#include "host/commands/cvd/server_command/acloud_common.h"
+
+namespace cuttlefish {
+
+fruit::Component<fruit::Required<
+ ConvertAcloudCreateCommand,
+ fruit::Annotated<AcloudTranslatorOptOut, std::atomic<bool>>>>
+TryAcloudCommandComponent();
+
+}