blob: 56344831f8ab493b458ebb5f2068b002a1c7f19f [file] [log] [blame]
Greg Hartman86b114a2017-11-03 21:04:14 -07001/*
2 * Copyright (C) 2017 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
Tomasz Wiszkowskie99c4112017-07-05 10:17:43 -070017#include <limits.h>
Greg Hartman610c03f2017-10-31 17:44:11 -070018#include <stdio.h>
Romit Dasgupta61b572a2017-06-23 17:48:22 -070019#include <stdlib.h>
20#include <unistd.h>
Tomasz Wiszkowskie99c4112017-07-05 10:17:43 -070021
22#include <fstream>
Romit Dasgupta61b572a2017-06-23 17:48:22 -070023#include <memory>
Tomasz Wiszkowski64446de2017-08-15 15:40:37 -070024#include <sstream>
Romit Dasgupta61b572a2017-06-23 17:48:22 -070025
Tomasz Wiszkowskie99c4112017-07-05 10:17:43 -070026#include <gflags/gflags.h>
Romit Dasgupta61b572a2017-06-23 17:48:22 -070027#include <glog/logging.h>
28
Tomasz Wiszkowski525d02b2017-08-14 11:43:04 -070029#include "common/libs/fs/shared_select.h"
Greg Hartman610c03f2017-10-31 17:44:11 -070030#include "host/libs/config/file_partition.h"
31#include "host/libs/config/guest_config.h"
32#include "host/libs/ivserver/ivserver.h"
33#include "host/libs/ivserver/options.h"
34#include "host/libs/usbip/server.h"
35#include "host/libs/vadb/virtual_adb_server.h"
Greg Hartman86b114a2017-11-03 21:04:14 -070036#include "host/vsoc/lib/region_control.h"
Romit Dasgupta61b572a2017-06-23 17:48:22 -070037
Tomasz Wiszkowskibb6c1622017-09-05 14:03:11 -070038namespace {
Tomasz Wiszkowskie4c52f62017-10-02 14:06:21 -070039std::string StringFromEnv(const char* varname, std::string defval) {
Tomasz Wiszkowskibb6c1622017-09-05 14:03:11 -070040 const char* const valstr = getenv(varname);
41 if (!valstr) {
42 return defval;
43 }
44 return valstr;
45}
46} // namespace
47
Greg Hartman9be67ff2017-11-03 15:10:21 -070048DEFINE_string(cache_image, "", "Location of the cache partition image.");
Tomasz Wiszkowskibb6c1622017-09-05 14:03:11 -070049DEFINE_int32(cpus, 2, "Virtual CPU count.");
Greg Hartman9be67ff2017-11-03 15:10:21 -070050DEFINE_string(data_image, "", "Location of the data partition image.");
51DEFINE_bool(disable_app_armor_security, false,
52 "Disable AppArmor security in libvirt. For debug only.");
53DEFINE_bool(disable_dac_security, false,
54 "Disable DAC security in libvirt. For debug only.");
55DEFINE_string(extra_kernel_command_line, "",
56 "Additional flags to put on the kernel command line");
Greg Hartmanefe487a2017-11-10 20:39:06 -080057DECLARE_int32(instance);
Greg Hartman9be67ff2017-11-03 15:10:21 -070058DEFINE_string(initrd, "", "Location of cuttlefish initrd file.");
Greg Hartman9be67ff2017-11-03 15:10:21 -070059DEFINE_string(kernel, "", "Location of cuttlefish kernel file.");
60DEFINE_string(kernel_command_line, "",
61 "Location of a text file with the kernel command line.");
Greg Hartman610c03f2017-10-31 17:44:11 -070062DEFINE_string(launch_command, "virsh create /dev/fd/0",
63 "Command to start an instance");
Greg Hartman610c03f2017-10-31 17:44:11 -070064DEFINE_string(layout,
65 StringFromEnv("ANDROID_HOST_OUT", StringFromEnv("HOME", ".")) +
Greg Hartmanbaa4c912017-11-02 00:33:15 -070066 "/config/vsoc_mem.json",
Tomasz Wiszkowski6c0ce632017-08-15 15:58:19 -070067 "Location of the vsoc_mem.json file.");
Greg Hartman9be67ff2017-11-03 15:10:21 -070068DEFINE_bool(log_xml, false, "Log the XML machine configuration");
69DEFINE_int32(memory_mb, 2048,
70 "Total amount of memory available for guest, MB.");
Tomasz Wiszkowskie99c4112017-07-05 10:17:43 -070071DEFINE_string(mempath, "/dev/shm/ivshmem",
72 "Target location for the shmem file.");
Greg Hartman9be67ff2017-11-03 15:10:21 -070073DEFINE_string(mobile_interface, "abr0",
74 "Network interface to use for mobile networking");
Tomasz Wiszkowskie99c4112017-07-05 10:17:43 -070075DEFINE_string(qemusocket, "/tmp/ivshmem_socket_qemu", "QEmu socket path");
Tomasz Wiszkowskie4c52f62017-10-02 14:06:21 -070076DEFINE_string(system_image_dir,
77 StringFromEnv("ANDROID_PRODUCT_OUT", StringFromEnv("HOME", ".")),
Tomasz Wiszkowskibb6c1622017-09-05 14:03:11 -070078 "Location of the system partition images.");
Tomasz Wiszkowskie54deb52017-09-19 12:56:04 -070079DEFINE_string(vendor_image, "", "Location of the vendor partition image.");
Romit Dasgupta61b572a2017-06-23 17:48:22 -070080
Tomasz Wiszkowski525d02b2017-08-14 11:43:04 -070081DEFINE_string(usbipsocket, "android_usbip", "Name of the USB/IP socket.");
Greg Hartman9be67ff2017-11-03 15:10:21 -070082DEFINE_string(uuid, "", "UUID to use for the device. Random if not specified");
Tomasz Wiszkowski525d02b2017-08-14 11:43:04 -070083
Tomasz Wiszkowskie99c4112017-07-05 10:17:43 -070084namespace {
Tomasz Wiszkowski64446de2017-08-15 15:40:37 -070085Json::Value LoadLayoutFile(const std::string& file) {
Tomasz Wiszkowskie99c4112017-07-05 10:17:43 -070086 char real_file_path[PATH_MAX];
87 if (realpath(file.c_str(), real_file_path) == nullptr) {
88 LOG(FATAL) << "Could not get real path for file " << file << ": "
89 << strerror(errno);
Romit Dasgupta61b572a2017-06-23 17:48:22 -070090 }
91
Tomasz Wiszkowskie99c4112017-07-05 10:17:43 -070092 Json::Value result;
93 Json::Reader reader;
94 std::ifstream ifs(real_file_path);
95 if (!reader.parse(ifs, result)) {
96 LOG(FATAL) << "Could not read layout file " << file << ": "
97 << reader.getFormattedErrorMessages();
98 }
99 return result;
Romit Dasgupta61b572a2017-06-23 17:48:22 -0700100}
Tomasz Wiszkowski525d02b2017-08-14 11:43:04 -0700101
Tomasz Wiszkowski64446de2017-08-15 15:40:37 -0700102// VirtualUSBManager manages virtual USB device presence for Cuttlefish.
103class VirtualUSBManager {
104 public:
105 VirtualUSBManager(const std::string& usbsocket)
106 : adb_{usbsocket, FLAGS_usbipsocket},
107 usbip_{FLAGS_usbipsocket, adb_.Pool()} {}
Tomasz Wiszkowski525d02b2017-08-14 11:43:04 -0700108
Tomasz Wiszkowski64446de2017-08-15 15:40:37 -0700109 ~VirtualUSBManager() = default;
Tomasz Wiszkowski525d02b2017-08-14 11:43:04 -0700110
Tomasz Wiszkowski64446de2017-08-15 15:40:37 -0700111 // Initialize Virtual USB and start USB management thread.
112 void Start() {
113 CHECK(adb_.Init()) << "Could not initialize Virtual ADB server";
114 CHECK(usbip_.Init()) << "Could not start USB/IP server";
115 thread_.reset(new std::thread([this]() { Thread(); }));
Tomasz Wiszkowski525d02b2017-08-14 11:43:04 -0700116 }
Tomasz Wiszkowski64446de2017-08-15 15:40:37 -0700117
118 private:
119 void Thread() {
120 for (;;) {
121 avd::SharedFDSet fd_read;
122 fd_read.Zero();
123
124 adb_.BeforeSelect(&fd_read);
125 usbip_.BeforeSelect(&fd_read);
126
127 int ret = avd::Select(&fd_read, nullptr, nullptr, nullptr);
128 if (ret <= 0) continue;
129
130 adb_.AfterSelect(fd_read);
131 usbip_.AfterSelect(fd_read);
132 }
133 }
134
135 vadb::VirtualADBServer adb_;
136 vadb::usbip::Server usbip_;
137 std::unique_ptr<std::thread> thread_;
138
139 VirtualUSBManager(const VirtualUSBManager&) = delete;
140 VirtualUSBManager& operator=(const VirtualUSBManager&) = delete;
141};
142
143// IVServerManager takes care of serving shared memory segments between
144// Cuttlefish and host-side daemons.
145class IVServerManager {
146 public:
147 IVServerManager(const Json::Value& json_root)
148 : server_(ivserver::IVServerOptions(FLAGS_layout, FLAGS_mempath,
Greg Hartmanefe487a2017-11-10 20:39:06 -0800149 FLAGS_qemusocket,
150 vsoc::GetShmClientSocketPath()),
Tomasz Wiszkowski64446de2017-08-15 15:40:37 -0700151 json_root) {}
152
153 ~IVServerManager() = default;
154
155 // Start IVServer thread.
156 void Start() {
157 thread_.reset(new std::thread([this]() { server_.Serve(); }));
158 }
159
160 private:
161 ivserver::IVServer server_;
162 std::unique_ptr<std::thread> thread_;
163
164 IVServerManager(const IVServerManager&) = delete;
165 IVServerManager& operator=(const IVServerManager&) = delete;
166};
167
Tomasz Wiszkowskie99c4112017-07-05 10:17:43 -0700168} // anonymous namespace
Romit Dasgupta61b572a2017-06-23 17:48:22 -0700169
Tomasz Wiszkowski64446de2017-08-15 15:40:37 -0700170int main(int argc, char** argv) {
Greg Hartman610c03f2017-10-31 17:44:11 -0700171 ::android::base::InitLogging(argv, android::base::StderrLogger);
Tomasz Wiszkowskie99c4112017-07-05 10:17:43 -0700172 google::ParseCommandLineFlags(&argc, &argv, true);
Romit Dasgupta61b572a2017-06-23 17:48:22 -0700173
Tomasz Wiszkowskibb6c1622017-09-05 14:03:11 -0700174 LOG_IF(FATAL, FLAGS_system_image_dir.empty())
175 << "--system_image_dir must be specified.";
176
177 // If user did not specify location of either of these files, expect them to
178 // be placed in --system_image_dir location.
Tomasz Wiszkowskibb6c1622017-09-05 14:03:11 -0700179 if (FLAGS_kernel.empty()) {
180 FLAGS_kernel = FLAGS_system_image_dir + "/kernel";
181 }
182
183 if (FLAGS_kernel_command_line.empty()) {
184 FLAGS_kernel_command_line = FLAGS_system_image_dir + "/cmdline";
185 }
186
Tomasz Wiszkowski283c3d32017-09-07 11:17:07 -0700187 if (FLAGS_initrd.empty()) {
188 FLAGS_initrd = FLAGS_system_image_dir + "/ramdisk.img";
189 }
190
191 if (FLAGS_cache_image.empty()) {
192 FLAGS_cache_image = FLAGS_system_image_dir + "/cache.img";
193 }
194
195 if (FLAGS_data_image.empty()) {
196 FLAGS_data_image = FLAGS_system_image_dir + "/userdata.img";
197 }
198
Tomasz Wiszkowskie54deb52017-09-19 12:56:04 -0700199 if (FLAGS_vendor_image.empty()) {
200 FLAGS_vendor_image = FLAGS_system_image_dir + "/vendor.img";
201 }
202
Tomasz Wiszkowskie99c4112017-07-05 10:17:43 -0700203 Json::Value json_root = LoadLayoutFile(FLAGS_layout);
Tomasz Wiszkowski64446de2017-08-15 15:40:37 -0700204
205 // Each of these calls is free to fail and terminate launch if file does not
206 // exist or could not be created.
Tomasz Wiszkowski6c0ce632017-08-15 15:58:19 -0700207 auto system_partition = config::FilePartition::ReuseExistingFile(
Tomasz Wiszkowski64446de2017-08-15 15:40:37 -0700208 FLAGS_system_image_dir + "/system.img");
Tomasz Wiszkowskie4c52f62017-10-02 14:06:21 -0700209 auto data_partition =
210 config::FilePartition::ReuseExistingFile(FLAGS_data_image);
211 auto cache_partition =
212 config::FilePartition::ReuseExistingFile(FLAGS_cache_image);
213 auto vendor_partition =
214 config::FilePartition::ReuseExistingFile(FLAGS_vendor_image);
Tomasz Wiszkowski64446de2017-08-15 15:40:37 -0700215
Greg Hartman76e1afb2017-08-25 21:13:10 -0700216 std::ifstream t(FLAGS_kernel_command_line);
217 if (!t) {
218 LOG(FATAL) << "Unable to open " << FLAGS_kernel_command_line;
219 }
220 t.seekg(0, std::ios::end);
221 size_t commandline_size = t.tellg();
222 if (commandline_size < 1) {
223 LOG(FATAL) << "no command line data found at " << FLAGS_kernel_command_line;
224 }
225 std::string cmdline;
226 cmdline.reserve(commandline_size);
227 t.seekg(0, std::ios::beg);
228 cmdline.assign((std::istreambuf_iterator<char>(t)),
Tomasz Wiszkowskie4c52f62017-10-02 14:06:21 -0700229 std::istreambuf_iterator<char>());
Greg Hartman76e1afb2017-08-25 21:13:10 -0700230 t.close();
Greg Hartman9be67ff2017-11-03 15:10:21 -0700231 cmdline += FLAGS_extra_kernel_command_line;
Tomasz Wiszkowski64446de2017-08-15 15:40:37 -0700232
Tomasz Wiszkowski64446de2017-08-15 15:40:37 -0700233 std::string entropy_source = "/dev/urandom";
Tomasz Wiszkowski64446de2017-08-15 15:40:37 -0700234
Tomasz Wiszkowski6c0ce632017-08-15 15:58:19 -0700235 config::GuestConfig cfg;
Tomasz Wiszkowski64446de2017-08-15 15:40:37 -0700236 cfg.SetID(FLAGS_instance)
237 .SetVCPUs(FLAGS_cpus)
238 .SetMemoryMB(FLAGS_memory_mb)
Greg Hartmanb5d93dd2017-08-17 15:54:46 -0700239 .SetKernelName(FLAGS_kernel)
240 .SetInitRDName(FLAGS_initrd)
Greg Hartman76e1afb2017-08-25 21:13:10 -0700241 .SetKernelArgs(cmdline)
Tomasz Wiszkowski64446de2017-08-15 15:40:37 -0700242 .SetIVShMemSocketPath(FLAGS_qemusocket)
243 .SetIVShMemVectorCount(json_root["vsoc_device_regions"].size())
Tomasz Wiszkowski64446de2017-08-15 15:40:37 -0700244 .SetSystemPartitionPath(system_partition->GetName())
245 .SetCachePartitionPath(cache_partition->GetName())
246 .SetDataPartitionPath(data_partition->GetName())
Tomasz Wiszkowskie54deb52017-09-19 12:56:04 -0700247 .SetVendorPartitionPath(vendor_partition->GetName())
Greg Hartman610c03f2017-10-31 17:44:11 -0700248 .SetMobileBridgeName(FLAGS_mobile_interface)
Greg Hartman9be67ff2017-11-03 15:10:21 -0700249 .SetDisableDACSecurity(FLAGS_disable_dac_security)
250 .SetDisableAppArmorSecurity(FLAGS_disable_app_armor_security)
251 .SetUUID(FLAGS_uuid);
Greg Hartmanefe487a2017-11-10 20:39:06 -0800252 cfg.SetUSBV1SocketName(std::string("/tmp/") + cfg.GetInstanceName() + "-usb");
Tomasz Wiszkowski64446de2017-08-15 15:40:37 -0700253
254 std::string xml = cfg.Build();
Greg Hartman610c03f2017-10-31 17:44:11 -0700255 if (FLAGS_log_xml) {
256 LOG(INFO) << "Using XML:\n" << xml;
257 }
Tomasz Wiszkowski64446de2017-08-15 15:40:37 -0700258
Greg Hartman610c03f2017-10-31 17:44:11 -0700259 VirtualUSBManager vadb(cfg.GetUSBV1SocketName());
Tomasz Wiszkowski64446de2017-08-15 15:40:37 -0700260 vadb.Start();
261 IVServerManager ivshmem(json_root);
262 ivshmem.Start();
263
264 sleep(1);
265
Greg Hartman610c03f2017-10-31 17:44:11 -0700266 FILE* launch = popen(FLAGS_launch_command.c_str(), "w");
267 if (!launch) {
268 LOG(FATAL) << "Unable to execute " << FLAGS_launch_command;
269 }
270 int rval = fputs(xml.c_str(), launch);
271 if (rval == EOF) {
272 LOG(FATAL) << "Launch command exited while accepting XML";
273 }
274 int exit_code = pclose(launch);
275 if (exit_code) {
276 LOG(FATAL) << "Launch command exited with status " << exit_code;
277 }
Tomasz Wiszkowski64446de2017-08-15 15:40:37 -0700278 pause();
Romit Dasgupta61b572a2017-06-23 17:48:22 -0700279}