164 lines
5.7 KiB
C++
164 lines
5.7 KiB
C++
/*
|
|
* 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/instance_manager.h"
|
|
|
|
#include <map>
|
|
#include <mutex>
|
|
#include <optional>
|
|
#include <thread>
|
|
|
|
#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/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/server_constants.h"
|
|
#include "host/libs/config/cuttlefish_config.h"
|
|
#include "host/libs/config/known_paths.h"
|
|
|
|
namespace cuttlefish {
|
|
|
|
std::optional<std::string> GetCuttlefishConfigPath(const std::string& home) {
|
|
std::string home_realpath;
|
|
if (DirectoryExists(home)) {
|
|
CHECK(android::base::Realpath(home, &home_realpath));
|
|
static const char kSuffix[] = "/cuttlefish_assembly/cuttlefish_config.json";
|
|
std::string config_path = AbsolutePath(home_realpath + kSuffix);
|
|
if (FileExists(config_path)) {
|
|
return config_path;
|
|
}
|
|
}
|
|
return {};
|
|
}
|
|
|
|
InstanceManager::InstanceManager(InstanceLockFileManager& lock_manager)
|
|
: lock_manager_(lock_manager) {}
|
|
|
|
bool InstanceManager::HasInstanceGroups() const {
|
|
std::lock_guard lock(instance_groups_mutex_);
|
|
return !instance_groups_.empty();
|
|
}
|
|
|
|
void InstanceManager::SetInstanceGroup(
|
|
const InstanceManager::InstanceGroupDir& dir,
|
|
const InstanceManager::InstanceGroupInfo& info) {
|
|
std::lock_guard assemblies_lock(instance_groups_mutex_);
|
|
instance_groups_[dir] = info;
|
|
}
|
|
|
|
void InstanceManager::RemoveInstanceGroup(
|
|
const InstanceManager::InstanceGroupDir& dir) {
|
|
std::lock_guard assemblies_lock(instance_groups_mutex_);
|
|
instance_groups_.erase(dir);
|
|
}
|
|
|
|
Result<InstanceManager::InstanceGroupInfo> InstanceManager::GetInstanceGroup(
|
|
const InstanceManager::InstanceGroupDir& dir) const {
|
|
std::lock_guard assemblies_lock(instance_groups_mutex_);
|
|
auto info_it = instance_groups_.find(dir);
|
|
if (info_it == instance_groups_.end()) {
|
|
return CF_ERR("No group dir \"" << dir << "\"");
|
|
} else {
|
|
return info_it->second;
|
|
}
|
|
}
|
|
|
|
cvd::Status InstanceManager::CvdFleet(const SharedFD& out,
|
|
const std::string& env_config) const {
|
|
std::lock_guard assemblies_lock(instance_groups_mutex_);
|
|
const char _GroupDeviceInfoStart[] = "[\n";
|
|
const char _GroupDeviceInfoSeparate[] = ",\n";
|
|
const char _GroupDeviceInfoEnd[] = "]\n";
|
|
WriteAll(out, _GroupDeviceInfoStart);
|
|
for (const auto& [group_dir, group_info] : instance_groups_) {
|
|
auto config_path = GetCuttlefishConfigPath(group_dir);
|
|
if (FileExists(env_config)) {
|
|
config_path = env_config;
|
|
}
|
|
if (config_path) {
|
|
// Reads CuttlefishConfig::instance_names(), which must remain stable
|
|
// across changes to config file format (within server_constants.h major
|
|
// version).
|
|
auto config = CuttlefishConfig::GetFromFile(*config_path);
|
|
if (config) {
|
|
Command command(group_info.host_binaries_dir + kStatusBin);
|
|
command.AddParameter("--print");
|
|
command.AddParameter("--all_instances");
|
|
command.RedirectStdIO(Subprocess::StdIOChannel::kStdOut, out);
|
|
command.AddEnvironmentVariable(kCuttlefishConfigEnvVarName,
|
|
*config_path);
|
|
if (int wait_result = command.Start().Wait(); wait_result != 0) {
|
|
WriteAll(out, " (unknown instance status error)");
|
|
}
|
|
}
|
|
}
|
|
if (group_dir != instance_groups_.rbegin()->first) {
|
|
WriteAll(out, _GroupDeviceInfoSeparate);
|
|
}
|
|
}
|
|
WriteAll(out, _GroupDeviceInfoEnd);
|
|
cvd::Status status;
|
|
status.set_code(cvd::Status::OK);
|
|
return status;
|
|
}
|
|
|
|
cvd::Status InstanceManager::CvdClear(const SharedFD& out,
|
|
const SharedFD& err) {
|
|
std::lock_guard lock(instance_groups_mutex_);
|
|
cvd::Status status;
|
|
for (const auto& [group_dir, group_info] : instance_groups_) {
|
|
auto config_path = GetCuttlefishConfigPath(group_dir);
|
|
if (config_path) {
|
|
// Stop all instances that are using this group dir.
|
|
Command command(group_info.host_binaries_dir + kStopBin);
|
|
// Delete the instance dirs.
|
|
command.AddParameter("--clear_instance_dirs");
|
|
command.RedirectStdIO(Subprocess::StdIOChannel::kStdOut, out);
|
|
command.RedirectStdIO(Subprocess::StdIOChannel::kStdErr, err);
|
|
command.AddEnvironmentVariable(kCuttlefishConfigEnvVarName, *config_path);
|
|
if (int wait_result = command.Start().Wait(); wait_result != 0) {
|
|
WriteAll(
|
|
out,
|
|
"Warning: error stopping instances for dir \"" + group_dir +
|
|
"\".\nThis can happen if instances are already stopped.\n");
|
|
}
|
|
for (const auto& instance : group_info.instances) {
|
|
auto lock = lock_manager_.TryAcquireLock(instance);
|
|
if (lock.ok() && (*lock)) {
|
|
(*lock)->Status(InUseState::kNotInUse);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
RemoveFile(StringFromEnv("HOME", ".") + "/cuttlefish_runtime");
|
|
RemoveFile(GetGlobalConfigFileLink());
|
|
WriteAll(out, "Stopped all known instances\n");
|
|
|
|
instance_groups_.clear();
|
|
status.set_code(cvd::Status::OK);
|
|
return status;
|
|
}
|
|
|
|
} // namespace cuttlefish
|