1 //
2 // Copyright (C) 2019 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 #include <fstream>
17 #include <iostream>
18 #include <sstream>
19 #include <unordered_set>
20 
21 #include <android-base/file.h>
22 #include <android-base/logging.h>
23 #include <android-base/no_destructor.h>
24 #include <android-base/parseint.h>
25 #include <gflags/gflags.h>
26 
27 #include "common/libs/fs/shared_buf.h"
28 #include "common/libs/fs/shared_fd.h"
29 #include "common/libs/utils/files.h"
30 #include "common/libs/utils/flag_parser.h"
31 #include "common/libs/utils/subprocess.h"
32 #include "host/commands/assemble_cvd/flags_defaults.h"
33 #include "host/commands/start/filesystem_explorer.h"
34 #include "host/commands/start/flag_forwarder.h"
35 #include "host/commands/start/override_bool_arg.h"
36 #include "host/commands/start/validate_metrics_confirmation.h"
37 #include "host/libs/config/config_utils.h"
38 #include "host/libs/config/cuttlefish_config.h"
39 #include "host/libs/config/fetcher_config.h"
40 #include "host/libs/config/host_tools_version.h"
41 #include "host/libs/config/instance_nums.h"
42 
43 DEFINE_int32(num_instances, CF_DEFAULTS_NUM_INSTANCES,
44              "Number of Android guests to launch");
45 DEFINE_string(report_anonymous_usage_stats,
46               CF_DEFAULTS_REPORT_ANONYMOUS_USAGE_STATS,
47               "Report anonymous usage "
48               "statistics for metrics collection and analysis.");
49 DEFINE_int32(
50     base_instance_num, CF_DEFAULTS_BASE_INSTANCE_NUM,
51     "The instance number of the device created. When `-num_instances N`"
52     " is used, N instance numbers are claimed starting at this number.");
53 DEFINE_string(instance_nums, CF_DEFAULTS_INSTANCE_NUMS,
54               "A comma-separated list of instance numbers "
55               "to use. Mutually exclusive with base_instance_num.");
56 DEFINE_string(verbosity, CF_DEFAULTS_VERBOSITY,
57               "Console logging verbosity. Options are VERBOSE,"
58               "DEBUG,INFO,WARNING,ERROR");
59 DEFINE_string(file_verbosity, CF_DEFAULTS_FILE_VERBOSITY,
60               "Log file logging verbosity. Options are VERBOSE,DEBUG,INFO,"
61               "WARNING,ERROR");
62 DEFINE_bool(use_overlay, CF_DEFAULTS_USE_OVERLAY,
63             "Capture disk writes an overlay. This is a "
64             "prerequisite for powerwash_cvd or multiple instances.");
65 DEFINE_bool(track_host_tools_crc, CF_DEFAULTS_TRACK_HOST_TOOLS_CRC,
66             "Track changes to host executables");
67 
68 namespace cuttlefish {
69 namespace {
70 
71 using android::base::NoDestructor;
72 
SubtoolPath(const std::string & subtool_base)73 std::string SubtoolPath(const std::string& subtool_base) {
74   auto my_own_dir = android::base::GetExecutableDirectory();
75   std::stringstream subtool_path_stream;
76   subtool_path_stream << my_own_dir << "/" << subtool_base;
77   auto subtool_path = subtool_path_stream.str();
78   if (my_own_dir.empty() || !FileExists(subtool_path)) {
79     return HostBinaryPath(subtool_base);
80   }
81   return subtool_path;
82 }
83 
AssemblerPath()84 std::string AssemblerPath() { return SubtoolPath("assemble_cvd"); }
RunnerPath()85 std::string RunnerPath() { return SubtoolPath("run_cvd"); }
86 
InvokeAssembler(const std::string & assembler_stdin,std::string & assembler_stdout,const std::vector<std::string> & argv)87 int InvokeAssembler(const std::string& assembler_stdin,
88                     std::string& assembler_stdout,
89                     const std::vector<std::string>& argv) {
90   Command assemble_cmd(AssemblerPath());
91   for (const auto& arg : argv) {
92     assemble_cmd.AddParameter(arg);
93   }
94   return RunWithManagedStdio(std::move(assemble_cmd), &assembler_stdin,
95                              &assembler_stdout, nullptr);
96 }
97 
StartRunner(SharedFD runner_stdin,const CuttlefishConfig::InstanceSpecific & instance,const std::vector<std::string> & argv)98 Subprocess StartRunner(SharedFD runner_stdin,
99                        const CuttlefishConfig::InstanceSpecific& instance,
100                        const std::vector<std::string>& argv) {
101   Command run_cmd(RunnerPath());
102   for (const auto& arg : argv) {
103     run_cmd.AddParameter(arg);
104   }
105   run_cmd.RedirectStdIO(Subprocess::StdIOChannel::kStdIn, runner_stdin);
106   run_cmd.SetWorkingDirectory(instance.instance_dir());
107   return run_cmd.Start();
108 }
109 
WriteFiles(FetcherConfig fetcher_config)110 std::string WriteFiles(FetcherConfig fetcher_config) {
111   std::stringstream output_streambuf;
112   for (const auto& file : fetcher_config.get_cvd_files()) {
113     output_streambuf << file.first << "\n";
114   }
115   return output_streambuf.str();
116 }
117 
HostToolsUpdated()118 bool HostToolsUpdated() {
119   if (CuttlefishConfig::ConfigExists()) {
120     auto config = CuttlefishConfig::Get();
121     if (config) {
122       auto current_tools = HostToolsCrc();
123       auto last_tools = config->host_tools_version();
124       return current_tools != last_tools;
125     }
126   }
127   return true;
128 }
129 
130 // Hash table for all bool flag names
131 // Used to find bool flag and convert "flag"/"noflag" to "--flag=value"
132 // This is the solution for vectorize bool flags in gFlags
133 
BoolFlags()134 const std::unordered_set<std::string>& BoolFlags() {
135   static const NoDestructor<std::unordered_set<std::string>> bool_flags({
136       "chromeos_boot",
137       "console",
138       "daemon",
139       "enable_audio",
140       "enable_bootanimation",
141       "enable_gpu_udmabuf",
142       "enable_gpu_vhost_user",
143       "enable_kernel_log",
144       "enable_minimal_mode",
145       "enable_modem_simulator",
146       "enable_sandbox",
147       "enable_usb",
148       "enable_virtiofs",
149       "fail_fast",
150       "guest_enforce_security",
151       "kgdb",
152       "pause_in_bootloader",
153       "protected_vm",
154       "record_screen",
155       "restart_subprocesses",
156       "smt",
157       "start_gnss_proxy",
158       "start_webrtc",
159       "use_allocd",
160       "use_random_serial",
161       "use_sdcard",
162       "vhost_net",
163       "vhost_user_block",
164       "vhost_user_vsock",
165   });
166   return *bool_flags;
167 }
168 
CvdInternalStartMain(int argc,char ** argv)169 int CvdInternalStartMain(int argc, char** argv) {
170   ::android::base::InitLogging(argv, android::base::StderrLogger);
171 
172   std::vector<std::string> args(argv + 1, argv + argc);
173 
174   std::vector<std::string> assemble_args;
175   std::string image_dir;
176   std::vector<std::string> args_copy = args;
177   auto parse_res = ConsumeFlags(
178       {GflagsCompatFlag("system_image_dir", image_dir)}, args_copy);
179   LOG(INFO) << "Using system_image_dir of: " << image_dir;
180 
181   if (!parse_res.ok()) {
182     LOG(ERROR) << "Error extracting system_image_dir from args: "
183                << parse_res.error().FormatForEnv();
184     return -1;
185   } else if (!image_dir.empty()) {
186     assemble_args = {"--system_image_dir=" + image_dir};
187   }
188 
189   std::vector<std::vector<std::string>> spargs = {assemble_args, {}};
190   FlagForwarder forwarder({AssemblerPath(), RunnerPath()}, spargs);
191 
192   // Used to find bool flag and convert "flag"/"noflag" to "--flag=value"
193   // This is the solution for vectorize bool flags in gFlags
194   args = OverrideBoolArg(std::move(args), BoolFlags());
195   for (int i = 1; i < argc; i++) {
196     argv[i] = args[i - 1].data();  // args[] start from 0
197   }
198 
199   gflags::ParseCommandLineNonHelpFlags(&argc, &argv, false);
200 
201   forwarder.UpdateFlagDefaults();
202 
203   gflags::HandleCommandLineHelpFlags();
204 
205   setenv("CF_CONSOLE_SEVERITY", FLAGS_verbosity.c_str(), /* replace */ false);
206   setenv("CF_FILE_SEVERITY", FLAGS_file_verbosity.c_str(), /* replace */ false);
207 
208   auto use_metrics = FLAGS_report_anonymous_usage_stats;
209   FLAGS_report_anonymous_usage_stats = ValidateMetricsConfirmation(use_metrics);
210 
211   if (FLAGS_track_host_tools_crc) {
212     // TODO(b/159068082) Make decisions based on this value in assemble_cvd
213     LOG(INFO) << "Host changed from last run: " << HostToolsUpdated();
214   }
215 
216   auto instance_nums = InstanceNumsCalculator().FromGlobalGflags().Calculate();
217   if (!instance_nums.ok()) {
218     LOG(ERROR) << instance_nums.error().FormatForEnv();
219     abort();
220   }
221 
222   // TODO(schuffelen): Lift instance id assumptions in sandboxing
223 
224   if (CuttlefishConfig::ConfigExists()) {
225     auto previous_config = CuttlefishConfig::Get();
226     CHECK(previous_config);
227     CHECK(!previous_config->Instances().empty());
228     auto previous_instance = previous_config->Instances()[0];
229     const auto& disks = previous_instance.virtual_disk_paths();
230     auto overlay = previous_instance.PerInstancePath("overlay.img");
231     auto used_overlay =
232         std::find(disks.begin(), disks.end(), overlay) != disks.end();
233     CHECK(used_overlay == FLAGS_use_overlay)
234         << "Cannot transition between different values of --use_overlay "
235         << "(Previous = " << used_overlay << ", current = " << FLAGS_use_overlay
236         << "). To fix this, delete \"" << previous_config->root_dir()
237         << "\" and any image files.";
238   }
239 
240   CHECK(!instance_nums->empty()) << "Expected at least one instance";
241   auto instance_num_str = std::to_string(*instance_nums->begin());
242   setenv(kCuttlefishInstanceEnvVarName, instance_num_str.c_str(),
243          /* overwrite */ 1);
244 
245 #if defined(__BIONIC__)
246   // These environment variables are needed in case when Bionic is used.
247   // b/171754977
248   setenv("ANDROID_DATA", DefaultHostArtifactsPath("").c_str(),
249          /* overwrite */ 0);
250   setenv("ANDROID_TZDATA_ROOT", DefaultHostArtifactsPath("").c_str(),
251          /* overwrite */ 0);
252   setenv("ANDROID_ROOT", DefaultHostArtifactsPath("").c_str(),
253          /* overwrite */ 0);
254 #endif
255 
256   auto assembler_input = WriteFiles(AvailableFilesReport());
257   std::string assembler_output;
258   auto assemble_ret =
259       InvokeAssembler(assembler_input, assembler_output,
260                       forwarder.ArgvForSubprocess(AssemblerPath(), args));
261 
262   if (assemble_ret != 0) {
263     LOG(ERROR) << "assemble_cvd returned " << assemble_ret;
264     return assemble_ret;
265   } else {
266     LOG(DEBUG) << "assemble_cvd exited successfully.";
267   }
268 
269   std::string conf_path;
270   for (const auto& line : android::base::Tokenize(assembler_output, "\n")) {
271     if (android::base::EndsWith(line, "cuttlefish_config.json")) {
272       conf_path = line;
273     }
274   }
275   CHECK(!conf_path.empty()) << "could not find config";
276   auto config = CuttlefishConfig::GetFromFile(conf_path);
277   CHECK(config) << "Could not load config object";
278   setenv(kCuttlefishConfigEnvVarName, conf_path.c_str(), /* overwrite */ true);
279 
280   std::vector<Subprocess> runners;
281   for (const auto& instance : config->Instances()) {
282     SharedFD runner_stdin = SharedFD::Open("/dev/null", O_RDONLY);
283     CHECK(runner_stdin->IsOpen()) << runner_stdin->StrError();
284     setenv(kCuttlefishInstanceEnvVarName, instance.id().c_str(),
285            /* overwrite */ 1);
286 
287     auto run_proc = StartRunner(std::move(runner_stdin), instance,
288                                 forwarder.ArgvForSubprocess(RunnerPath()));
289     runners.push_back(std::move(run_proc));
290   }
291 
292   bool run_cvd_failure = false;
293   for (auto& run_proc : runners) {
294     auto run_ret = run_proc.Wait();
295     if (run_ret != 0) {
296       run_cvd_failure = true;
297       LOG(ERROR) << "run_cvd returned " << run_ret;
298     } else {
299       LOG(DEBUG) << "run_cvd exited successfully.";
300     }
301   }
302   return run_cvd_failure ? -1 : 0;
303 }
304 
305 }  // namespace
306 }  // namespace cuttlefish
307 
main(int argc,char ** argv)308 int main(int argc, char** argv) {
309   return cuttlefish::CvdInternalStartMain(argc, argv);
310 }
311