• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "host/commands/cvd/instance_manager.h"
18 
19 #include <map>
20 #include <mutex>
21 #include <optional>
22 #include <thread>
23 
24 #include <android-base/file.h>
25 #include <android-base/logging.h>
26 #include <fruit/fruit.h>
27 
28 #include "cvd_server.pb.h"
29 
30 #include "common/libs/fs/shared_buf.h"
31 #include "common/libs/fs/shared_fd.h"
32 #include "common/libs/utils/files.h"
33 #include "common/libs/utils/flag_parser.h"
34 #include "common/libs/utils/result.h"
35 #include "common/libs/utils/subprocess.h"
36 #include "host/commands/cvd/server_constants.h"
37 #include "host/libs/config/cuttlefish_config.h"
38 #include "host/libs/config/known_paths.h"
39 
40 namespace cuttlefish {
41 
GetCuttlefishConfigPath(const std::string & home)42 std::optional<std::string> GetCuttlefishConfigPath(const std::string& home) {
43   std::string home_realpath;
44   if (DirectoryExists(home)) {
45     CHECK(android::base::Realpath(home, &home_realpath));
46     static const char kSuffix[] = "/cuttlefish_assembly/cuttlefish_config.json";
47     std::string config_path = AbsolutePath(home_realpath + kSuffix);
48     if (FileExists(config_path)) {
49       return config_path;
50     }
51   }
52   return {};
53 }
54 
InstanceManager(InstanceLockFileManager & lock_manager)55 InstanceManager::InstanceManager(InstanceLockFileManager& lock_manager)
56     : lock_manager_(lock_manager) {}
57 
HasInstanceGroups() const58 bool InstanceManager::HasInstanceGroups() const {
59   std::lock_guard lock(instance_groups_mutex_);
60   return !instance_groups_.empty();
61 }
62 
SetInstanceGroup(const InstanceManager::InstanceGroupDir & dir,const InstanceManager::InstanceGroupInfo & info)63 void InstanceManager::SetInstanceGroup(
64     const InstanceManager::InstanceGroupDir& dir,
65     const InstanceManager::InstanceGroupInfo& info) {
66   std::lock_guard assemblies_lock(instance_groups_mutex_);
67   instance_groups_[dir] = info;
68 }
69 
RemoveInstanceGroup(const InstanceManager::InstanceGroupDir & dir)70 void InstanceManager::RemoveInstanceGroup(
71     const InstanceManager::InstanceGroupDir& dir) {
72   std::lock_guard assemblies_lock(instance_groups_mutex_);
73   instance_groups_.erase(dir);
74 }
75 
GetInstanceGroup(const InstanceManager::InstanceGroupDir & dir) const76 Result<InstanceManager::InstanceGroupInfo> InstanceManager::GetInstanceGroup(
77     const InstanceManager::InstanceGroupDir& dir) const {
78   std::lock_guard assemblies_lock(instance_groups_mutex_);
79   auto info_it = instance_groups_.find(dir);
80   if (info_it == instance_groups_.end()) {
81     return CF_ERR("No group dir \"" << dir << "\"");
82   } else {
83     return info_it->second;
84   }
85 }
86 
CvdFleet(const SharedFD & out,const std::string & env_config) const87 cvd::Status InstanceManager::CvdFleet(const SharedFD& out,
88                                       const std::string& env_config) const {
89   std::lock_guard assemblies_lock(instance_groups_mutex_);
90   const char _GroupDeviceInfoStart[] = "[\n";
91   const char _GroupDeviceInfoSeparate[] = ",\n";
92   const char _GroupDeviceInfoEnd[] = "]\n";
93   WriteAll(out, _GroupDeviceInfoStart);
94   for (const auto& [group_dir, group_info] : instance_groups_) {
95     auto config_path = GetCuttlefishConfigPath(group_dir);
96     if (FileExists(env_config)) {
97       config_path = env_config;
98     }
99     if (config_path) {
100       // Reads CuttlefishConfig::instance_names(), which must remain stable
101       // across changes to config file format (within server_constants.h major
102       // version).
103       auto config = CuttlefishConfig::GetFromFile(*config_path);
104       if (config) {
105         Command command(group_info.host_binaries_dir + kStatusBin);
106         command.AddParameter("--print");
107         command.AddParameter("--all_instances");
108         command.RedirectStdIO(Subprocess::StdIOChannel::kStdOut, out);
109         command.AddEnvironmentVariable(kCuttlefishConfigEnvVarName,
110                                        *config_path);
111         if (int wait_result = command.Start().Wait(); wait_result != 0) {
112           WriteAll(out, "      (unknown instance status error)");
113         }
114       }
115     }
116     if (group_dir != instance_groups_.rbegin()->first) {
117       WriteAll(out, _GroupDeviceInfoSeparate);
118     }
119   }
120   WriteAll(out, _GroupDeviceInfoEnd);
121   cvd::Status status;
122   status.set_code(cvd::Status::OK);
123   return status;
124 }
125 
CvdClear(const SharedFD & out,const SharedFD & err)126 cvd::Status InstanceManager::CvdClear(const SharedFD& out,
127                                       const SharedFD& err) {
128   std::lock_guard lock(instance_groups_mutex_);
129   cvd::Status status;
130   for (const auto& [group_dir, group_info] : instance_groups_) {
131     auto config_path = GetCuttlefishConfigPath(group_dir);
132     if (config_path) {
133       // Stop all instances that are using this group dir.
134       Command command(group_info.host_binaries_dir + kStopBin);
135       // Delete the instance dirs.
136       command.AddParameter("--clear_instance_dirs");
137       command.RedirectStdIO(Subprocess::StdIOChannel::kStdOut, out);
138       command.RedirectStdIO(Subprocess::StdIOChannel::kStdErr, err);
139       command.AddEnvironmentVariable(kCuttlefishConfigEnvVarName, *config_path);
140       if (int wait_result = command.Start().Wait(); wait_result != 0) {
141         WriteAll(
142             out,
143             "Warning: error stopping instances for dir \"" + group_dir +
144                 "\".\nThis can happen if instances are already stopped.\n");
145       }
146       for (const auto& instance : group_info.instances) {
147         auto lock = lock_manager_.TryAcquireLock(instance);
148         if (lock.ok() && (*lock)) {
149           (*lock)->Status(InUseState::kNotInUse);
150         }
151       }
152     }
153   }
154   RemoveFile(StringFromEnv("HOME", ".") + "/cuttlefish_runtime");
155   RemoveFile(GetGlobalConfigFileLink());
156   WriteAll(out, "Stopped all known instances\n");
157 
158   instance_groups_.clear();
159   status.set_code(cvd::Status::OK);
160   return status;
161 }
162 
163 }  // namespace cuttlefish
164