blob: 998a083b7a71cbd659c909a94791858a239d7695 [file] [log] [blame] [edit]
/*
* 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 <unistd.h>
#include <cstdio>
#include <iostream>
#include <optional>
#include <string>
#include <string_view>
#include <vector>
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/scopeguard.h>
#include <android-base/strings.h>
#include "common/libs/utils/contains.h"
#include "common/libs/utils/environment.h"
#include "common/libs/utils/subprocess.h"
#include "host/commands/cvd/client.h"
#include "host/commands/cvd/common_utils.h"
#include "host/commands/cvd/fetch/fetch_cvd.h"
#include "host/commands/cvd/flag.h"
#include "host/commands/cvd/frontline_parser.h"
#include "host/commands/cvd/metrics/cvd_metrics_api.h"
#include "host/commands/cvd/run_server.h"
#include "host/commands/cvd/server_constants.h"
#include "host/libs/config/host_tools_version.h"
namespace cuttlefish {
namespace {
/**
* Returns --verbosity value if ever exist in the entire commandline args
*
* Note that this will also pick up from the subtool arguments:
* e.g. cvd start --verbosity=DEBUG
*
* This may be incorrect as the verbosity should be ideally applied to the
* launch_cvd/cvd_internal_start only.
*
* However, parsing the --verbosity flag only from the driver is quite
* complicated as we do not know the full list of the subcommands,
* the subcommands flags, and even the selector/driver flags.
*
* Thus, we live with the corner case for now.
*/
android::base::LogSeverity CvdVerbosityOption(const int argc, char** argv) {
cvd_common::Args all_args = ArgsToVec(argc, argv);
std::string verbosity_flag_value;
std::vector<Flag> verbosity_flag{
GflagsCompatFlag("verbosity", verbosity_flag_value)};
if (!ParseFlags(verbosity_flag, all_args).ok()) {
LOG(ERROR) << "Verbosity flag parsing failed, so use the default value.";
return GetMinimumVerbosity();
}
if (verbosity_flag_value.empty()) {
return GetMinimumVerbosity();
}
auto encoded_verbosity = EncodeVerbosity(verbosity_flag_value);
return (encoded_verbosity.ok() ? *encoded_verbosity : GetMinimumVerbosity());
}
/**
* Terminates a cvd server listening on "cvd_server"
*
* So far, the server processes across users were listing on the "cvd_server"
* socket. And, so far, we had one user. Now, we have multiple users. Each
* server listens to cvd_server_<uid>. The thing is if there is a server process
* started out of an old executable it will be listening to "cvd_server," and
* thus we should kill the server process first.
*/
Result<void> KillOldServer() {
CvdClient client_to_old_server(kCvdDefaultVerbosity, "cvd_server");
auto result = client_to_old_server.StopCvdServer(/*clear=*/true);
if (!result.ok()) {
LOG(ERROR) << "Old server listening on \"cvd_server\" socket "
<< "must be killed first but failed to terminate it.";
LOG(ERROR) << "Perhaps, try cvd reset -y";
CF_EXPECT(std::move(result));
}
return {};
}
Result<void> CvdMain(int argc, char** argv, char** envp,
const android::base::LogSeverity verbosity) {
CF_EXPECT(KillOldServer());
cvd_common::Args all_args = ArgsToVec(argc, argv);
CF_EXPECT(!all_args.empty());
if (IsServerModeExpected(all_args[0])) {
auto parsed = CF_EXPECT(ParseIfServer(all_args));
return RunServer(
{.internal_server_fd = parsed.internal_server_fd,
.carryover_client_fd = parsed.carryover_client_fd,
.memory_carryover_fd = parsed.memory_carryover_fd,
.verbosity_level = parsed.verbosity_level,
.acloud_translator_optout = parsed.acloud_translator_optout,
.restarted_in_process = parsed.restarted_in_process});
}
auto env = EnvpToMap(envp);
CvdMetrics::SendCvdMetrics(all_args);
if (android::base::Basename(all_args[0]) == "fetch_cvd") {
CF_EXPECT(FetchCvdMain(argc, argv));
return {};
}
CvdClient client(verbosity);
// TODO(b/206893146): Make this decision inside the server.
if (android::base::Basename(all_args[0]) == "acloud") {
return client.HandleAcloud(all_args, env);
}
if (android::base::Basename(all_args[0]) == "cvd") {
CF_EXPECT(client.HandleCvdCommand(all_args, env));
return {};
}
CF_EXPECT(client.ValidateServerVersion(),
"Unable to ensure cvd_server is running.");
CF_EXPECT(client.HandleCommand(all_args, env, {}));
return {};
}
/**
* Returns the URL as a colored string
*
* If stderr is not terminal, no color.
* If stderr is a tty, tries to use ".deb" file color
* If .deb is not available in LS_COLORS, uses .zip
* color. If none are available, use a default color that
* is red.
*/
std::string ColoredUrl(const std::string& url) {
if (!isatty(STDERR_FILENO)) {
return url;
}
std::string coloring_prefix = "\033[01;31m";
std::string output;
auto ls_colors = StringFromEnv("LS_COLORS", "");
std::vector<std::string> colors_vec = android::base::Tokenize(ls_colors, ":");
std::unordered_map<std::string, std::string> colors;
for (const auto& color_entry : colors_vec) {
std::vector<std::string> tokenized =
android::base::Tokenize(color_entry, "=");
if (tokenized.size() != 2) {
continue;
}
colors[tokenized.front()] = tokenized.back();
}
android::base::ScopeGuard return_action([&coloring_prefix, url, &output]() {
static constexpr char kRestoreColor[] = "\033[0m";
output = fmt::format("{}{}{}", coloring_prefix, url, kRestoreColor);
});
auto deb_color_itr = colors.find("*.deb");
auto zip_color_itr = colors.find("*.zip");
if (deb_color_itr == colors.end() && zip_color_itr == colors.end()) {
return output;
}
coloring_prefix = fmt::format(
"{}{}m", "\033[",
(deb_color_itr == colors.end() ? colors["*.zip"] : colors["*.deb"]));
return output;
}
} // namespace
} // namespace cuttlefish
int main(int argc, char** argv, char** envp) {
android::base::LogSeverity verbosity =
cuttlefish::CvdVerbosityOption(argc, argv);
android::base::InitLogging(argv, android::base::StderrLogger);
// set verbosity for this process
cuttlefish::SetMinimumVerbosity(verbosity);
auto result = cuttlefish::CvdMain(argc, argv, envp, verbosity);
if (result.ok()) {
return 0;
} else {
// TODO: we should not print the stack trace, instead, we should rely on
// each handler to print the error message directly in the client's
// std::cerr. We print the stack trace only in the verbose mode.
std::cerr << result.error().FormatForEnv() << std::endl;
// TODO(kwstephenkim): better coloring
constexpr char kUserReminder[] =
R"( If the error above is unclear, please copy the text into an issue at:)";
constexpr char kCuttlefishBugUrl[] = "http://go/cuttlefish-bug";
std::cerr << std::endl << kUserReminder << std::endl;
std::cerr << " " << cuttlefish::ColoredUrl(kCuttlefishBugUrl)
<< std::endl
<< std::endl;
return -1;
}
}