blob: 6a173ea701d5c84df4e5ee06b63465c62f9cc5bc [file] [log] [blame]
/*
* Copyright (C) 2021 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 <algorithm>
#include <iostream>
#include <optional>
#include <string>
#include <vector>
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/result.h>
#include "common/libs/fs/shared_fd.h"
#include "common/libs/utils/contains.h"
#include "common/libs/utils/flag_parser.h"
#include "common/libs/utils/result.h"
#include "common/libs/utils/shared_fd_flag.h"
#include "host/commands/cvd/client.h"
#include "host/commands/cvd/fetch/fetch_cvd.h"
#include "host/commands/cvd/selector/selector_cmdline_parser.h"
#include "host/commands/cvd/server.h"
#include "host/commands/cvd/server_constants.h"
#include "host/libs/config/host_tools_version.h"
namespace cuttlefish {
namespace {
bool IsServerModeExpected(const SharedFD& internal_server_fd,
const std::string& exec_file) {
return internal_server_fd->IsOpen() || exec_file == "/proc/self/exe";
}
Result<void> RunServer(const SharedFD& internal_server_fd,
const SharedFD& carryover_client_fd) {
if (!internal_server_fd->IsOpen()) {
return CF_ERR(
"Expected to be in server mode, but didn't get a server "
"fd: "
<< internal_server_fd->StrError());
}
CF_EXPECT(CvdServerMain(internal_server_fd, carryover_client_fd));
return {};
}
struct ParseResult {
bool clean_;
SharedFD internal_server_fd_;
SharedFD carryover_client_fd_;
};
Result<ParseResult> Parse(std::vector<std::string>& args) {
std::vector<Flag> flags;
bool clean = false;
flags.emplace_back(GflagsCompatFlag("clean", clean));
SharedFD internal_server_fd;
flags.emplace_back(SharedFDFlag("INTERNAL_server_fd", internal_server_fd));
SharedFD carryover_client_fd;
flags.emplace_back(
SharedFDFlag("INTERNAL_carryover_client_fd", carryover_client_fd));
CF_EXPECT(ParseFlags(flags, args));
ParseResult result = {clean, internal_server_fd, carryover_client_fd};
return {result};
}
Result<void> CvdMain(int argc, char** argv, char** envp) {
android::base::InitLogging(argv, android::base::StderrLogger);
std::vector<std::string> all_args = ArgsToVec(argc, argv);
if (android::base::Basename(all_args[0]) == "fetch_cvd") {
CF_EXPECT(FetchCvdMain(argc, argv));
return {};
}
auto [args, selector_args] =
CF_EXPECT(selector::GetCommandAndSelectorArguments(all_args));
std::vector<std::string> env;
for (char** e = envp; *e != 0; e++) {
env.emplace_back(*e);
}
CvdClient client;
auto host_tool_dir =
android::base::Dirname(android::base::GetExecutableDirectory());
// TODO(b/206893146): Make this decision inside the server.
if (android::base::Basename(args[0]) == "acloud") {
return client.HandleAcloud(args, env, host_tool_dir);
}
auto [clean, internal_server_fd, carryover_client_fd] =
CF_EXPECT(Parse(args));
if (IsServerModeExpected(internal_server_fd, args[0])) {
return RunServer(internal_server_fd, carryover_client_fd);
}
// Special case for `cvd kill-server`, handled by directly
// stopping the cvd_server.
std::vector<std::string> kill_server_cmds{"kill-server", "server-kill"};
if (args.size() > 1 && Contains(kill_server_cmds, args[1])) {
CF_EXPECT(client.StopCvdServer(/*clear=*/true));
return {};
}
// Special case for --clean flag, used to clear any existing state.
if (clean) {
LOG(INFO) << "cvd invoked with --clean; "
<< "stopping the cvd_server before continuing.";
CF_EXPECT(client.StopCvdServer(/*clear=*/true));
}
// Handle all remaining commands by forwarding them to the cvd_server.
CF_EXPECT(client.ValidateServerVersion(host_tool_dir),
"Unable to ensure cvd_server is running.");
// Special case for `cvd version`, handled by using the version command.
if (args.size() > 1 && android::base::Basename(args[0]) == "cvd" &&
args[1] == "version") {
auto version_msg = CF_EXPECT(client.HandleVersion(host_tool_dir));
std::cout << version_msg;
return {};
}
if (args.size() > 1 && android::base::Basename(args[0]) == "cvd" &&
args[1] == "cmd-list") {
return {};
}
// TODO(schuffelen): Deduplicate when calls to setenv are removed.
CF_EXPECT(client.HandleCommand(args, env, selector_args));
return {};
}
} // namespace
} // namespace cuttlefish
int main(int argc, char** argv, char** envp) {
auto result = cuttlefish::CvdMain(argc, argv, envp);
if (result.ok()) {
return 0;
} else {
std::cerr << result.error().Message() << std::endl;
return -1;
}
}