blob: 11bbaace468d83c06a209c7056daf703262bcb4c [file] [log] [blame]
Tomasz Wiszkowskie99c4112017-07-05 10:17:43 -07001#include <limits.h>
Romit Dasgupta61b572a2017-06-23 17:48:22 -07002#include <stdlib.h>
3#include <unistd.h>
Tomasz Wiszkowskie99c4112017-07-05 10:17:43 -07004
5#include <fstream>
Romit Dasgupta61b572a2017-06-23 17:48:22 -07006#include <memory>
Tomasz Wiszkowski64446de2017-08-15 15:40:37 -07007#include <sstream>
Romit Dasgupta61b572a2017-06-23 17:48:22 -07008
Tomasz Wiszkowskie99c4112017-07-05 10:17:43 -07009#include <gflags/gflags.h>
Romit Dasgupta61b572a2017-06-23 17:48:22 -070010#include <glog/logging.h>
Tomasz Wiszkowski64446de2017-08-15 15:40:37 -070011#include <libvirt/libvirt.h>
Romit Dasgupta61b572a2017-06-23 17:48:22 -070012
Tomasz Wiszkowski525d02b2017-08-14 11:43:04 -070013#include "common/libs/fs/shared_select.h"
Tomasz Wiszkowski6c0ce632017-08-15 15:58:19 -070014#include "host/config/file_partition.h"
15#include "host/config/guest_config.h"
Tomasz Wiszkowskie99c4112017-07-05 10:17:43 -070016#include "host/ivserver/ivserver.h"
17#include "host/ivserver/options.h"
Tomasz Wiszkowski525d02b2017-08-14 11:43:04 -070018#include "host/vadb/usbip/server.h"
19#include "host/vadb/virtual_adb_server.h"
Romit Dasgupta61b572a2017-06-23 17:48:22 -070020
Tomasz Wiszkowskibb6c1622017-09-05 14:03:11 -070021namespace {
Tomasz Wiszkowskie4c52f62017-10-02 14:06:21 -070022std::string StringFromEnv(const char* varname, std::string defval) {
Tomasz Wiszkowskibb6c1622017-09-05 14:03:11 -070023 const char* const valstr = getenv(varname);
24 if (!valstr) {
25 return defval;
26 }
27 return valstr;
28}
29} // namespace
30
Tomasz Wiszkowski64446de2017-08-15 15:40:37 -070031DEFINE_int32(instance, 1, "Instance number. Must be unique.");
Tomasz Wiszkowskibb6c1622017-09-05 14:03:11 -070032DEFINE_int32(cpus, 2, "Virtual CPU count.");
33DEFINE_int32(memory_mb, 2048,
Tomasz Wiszkowski6c0ce632017-08-15 15:58:19 -070034 "Total amount of memory available for guest, MB.");
35DEFINE_string(layout, "/usr/share/cuttlefish-common/vsoc_mem.json",
36 "Location of the vsoc_mem.json file.");
Tomasz Wiszkowskie99c4112017-07-05 10:17:43 -070037DEFINE_string(mempath, "/dev/shm/ivshmem",
38 "Target location for the shmem file.");
Greg Hartman8fae86d2017-08-25 14:16:15 -070039DEFINE_int32(shmsize, 0, "(ignored)");
Tomasz Wiszkowskie99c4112017-07-05 10:17:43 -070040DEFINE_string(qemusocket, "/tmp/ivshmem_socket_qemu", "QEmu socket path");
41DEFINE_string(clientsocket, "/tmp/ivshmem_socket_client", "Client socket path");
Tomasz Wiszkowski283c3d32017-09-07 11:17:07 -070042
Tomasz Wiszkowskie4c52f62017-10-02 14:06:21 -070043DEFINE_string(system_image_dir,
44 StringFromEnv("ANDROID_PRODUCT_OUT", StringFromEnv("HOME", ".")),
Tomasz Wiszkowskibb6c1622017-09-05 14:03:11 -070045 "Location of the system partition images.");
Tomasz Wiszkowski64446de2017-08-15 15:40:37 -070046DEFINE_string(kernel, "", "Location of cuttlefish kernel file.");
Tomasz Wiszkowski283c3d32017-09-07 11:17:07 -070047DEFINE_string(kernel_command_line, "",
48 "Location of a text file with the kernel command line.");
49DEFINE_string(initrd, "", "Location of cuttlefish initrd file.");
50DEFINE_string(data_image, "", "Location of the data partition image.");
51DEFINE_string(cache_image, "", "Location of the cache partition image.");
Tomasz Wiszkowskie54deb52017-09-19 12:56:04 -070052DEFINE_string(vendor_image, "", "Location of the vendor partition image.");
Romit Dasgupta61b572a2017-06-23 17:48:22 -070053
Tomasz Wiszkowski525d02b2017-08-14 11:43:04 -070054DEFINE_string(usbipsocket, "android_usbip", "Name of the USB/IP socket.");
55
Tomasz Wiszkowskie99c4112017-07-05 10:17:43 -070056namespace {
Tomasz Wiszkowski64446de2017-08-15 15:40:37 -070057constexpr char kLibVirtQemuTarget[] = "qemu:///system";
58
59Json::Value LoadLayoutFile(const std::string& file) {
Tomasz Wiszkowskie99c4112017-07-05 10:17:43 -070060 char real_file_path[PATH_MAX];
61 if (realpath(file.c_str(), real_file_path) == nullptr) {
62 LOG(FATAL) << "Could not get real path for file " << file << ": "
63 << strerror(errno);
Romit Dasgupta61b572a2017-06-23 17:48:22 -070064 }
65
Tomasz Wiszkowskie99c4112017-07-05 10:17:43 -070066 Json::Value result;
67 Json::Reader reader;
68 std::ifstream ifs(real_file_path);
69 if (!reader.parse(ifs, result)) {
70 LOG(FATAL) << "Could not read layout file " << file << ": "
71 << reader.getFormattedErrorMessages();
72 }
73 return result;
Romit Dasgupta61b572a2017-06-23 17:48:22 -070074}
Tomasz Wiszkowski525d02b2017-08-14 11:43:04 -070075
Tomasz Wiszkowski64446de2017-08-15 15:40:37 -070076// VirtualUSBManager manages virtual USB device presence for Cuttlefish.
77class VirtualUSBManager {
78 public:
79 VirtualUSBManager(const std::string& usbsocket)
80 : adb_{usbsocket, FLAGS_usbipsocket},
81 usbip_{FLAGS_usbipsocket, adb_.Pool()} {}
Tomasz Wiszkowski525d02b2017-08-14 11:43:04 -070082
Tomasz Wiszkowski64446de2017-08-15 15:40:37 -070083 ~VirtualUSBManager() = default;
Tomasz Wiszkowski525d02b2017-08-14 11:43:04 -070084
Tomasz Wiszkowski64446de2017-08-15 15:40:37 -070085 // Initialize Virtual USB and start USB management thread.
86 void Start() {
87 CHECK(adb_.Init()) << "Could not initialize Virtual ADB server";
88 CHECK(usbip_.Init()) << "Could not start USB/IP server";
89 thread_.reset(new std::thread([this]() { Thread(); }));
Tomasz Wiszkowski525d02b2017-08-14 11:43:04 -070090 }
Tomasz Wiszkowski64446de2017-08-15 15:40:37 -070091
92 private:
93 void Thread() {
94 for (;;) {
95 avd::SharedFDSet fd_read;
96 fd_read.Zero();
97
98 adb_.BeforeSelect(&fd_read);
99 usbip_.BeforeSelect(&fd_read);
100
101 int ret = avd::Select(&fd_read, nullptr, nullptr, nullptr);
102 if (ret <= 0) continue;
103
104 adb_.AfterSelect(fd_read);
105 usbip_.AfterSelect(fd_read);
106 }
107 }
108
109 vadb::VirtualADBServer adb_;
110 vadb::usbip::Server usbip_;
111 std::unique_ptr<std::thread> thread_;
112
113 VirtualUSBManager(const VirtualUSBManager&) = delete;
114 VirtualUSBManager& operator=(const VirtualUSBManager&) = delete;
115};
116
117// IVServerManager takes care of serving shared memory segments between
118// Cuttlefish and host-side daemons.
119class IVServerManager {
120 public:
121 IVServerManager(const Json::Value& json_root)
122 : server_(ivserver::IVServerOptions(FLAGS_layout, FLAGS_mempath,
Greg Hartman8fae86d2017-08-25 14:16:15 -0700123 FLAGS_qemusocket, FLAGS_clientsocket),
Tomasz Wiszkowski64446de2017-08-15 15:40:37 -0700124 json_root) {}
125
126 ~IVServerManager() = default;
127
128 // Start IVServer thread.
129 void Start() {
130 thread_.reset(new std::thread([this]() { server_.Serve(); }));
131 }
132
133 private:
134 ivserver::IVServer server_;
135 std::unique_ptr<std::thread> thread_;
136
137 IVServerManager(const IVServerManager&) = delete;
138 IVServerManager& operator=(const IVServerManager&) = delete;
139};
140
Tomasz Wiszkowskie99c4112017-07-05 10:17:43 -0700141} // anonymous namespace
Romit Dasgupta61b572a2017-06-23 17:48:22 -0700142
Tomasz Wiszkowski64446de2017-08-15 15:40:37 -0700143int main(int argc, char** argv) {
Tomasz Wiszkowski525d02b2017-08-14 11:43:04 -0700144 google::InitGoogleLogging(argv[0]);
Tomasz Wiszkowskia29455e2017-07-07 14:23:16 -0700145 google::InstallFailureSignalHandler();
Tomasz Wiszkowskie99c4112017-07-05 10:17:43 -0700146 google::ParseCommandLineFlags(&argc, &argv, true);
Romit Dasgupta61b572a2017-06-23 17:48:22 -0700147
Tomasz Wiszkowskibb6c1622017-09-05 14:03:11 -0700148 // Log all messages with level WARNING and above to stderr.
149 google::SetStderrLogging(google::GLOG_WARNING);
150
151 LOG_IF(FATAL, FLAGS_system_image_dir.empty())
152 << "--system_image_dir must be specified.";
153
154 // If user did not specify location of either of these files, expect them to
155 // be placed in --system_image_dir location.
Tomasz Wiszkowskibb6c1622017-09-05 14:03:11 -0700156 if (FLAGS_kernel.empty()) {
157 FLAGS_kernel = FLAGS_system_image_dir + "/kernel";
158 }
159
160 if (FLAGS_kernel_command_line.empty()) {
161 FLAGS_kernel_command_line = FLAGS_system_image_dir + "/cmdline";
162 }
163
Tomasz Wiszkowski283c3d32017-09-07 11:17:07 -0700164 if (FLAGS_initrd.empty()) {
165 FLAGS_initrd = FLAGS_system_image_dir + "/ramdisk.img";
166 }
167
168 if (FLAGS_cache_image.empty()) {
169 FLAGS_cache_image = FLAGS_system_image_dir + "/cache.img";
170 }
171
172 if (FLAGS_data_image.empty()) {
173 FLAGS_data_image = FLAGS_system_image_dir + "/userdata.img";
174 }
175
Tomasz Wiszkowskie54deb52017-09-19 12:56:04 -0700176 if (FLAGS_vendor_image.empty()) {
177 FLAGS_vendor_image = FLAGS_system_image_dir + "/vendor.img";
178 }
179
Tomasz Wiszkowski64446de2017-08-15 15:40:37 -0700180 CHECK(virInitialize() == 0) << "Could not initialize libvirt.";
Romit Dasgupta61b572a2017-06-23 17:48:22 -0700181
Tomasz Wiszkowskie99c4112017-07-05 10:17:43 -0700182 Json::Value json_root = LoadLayoutFile(FLAGS_layout);
Tomasz Wiszkowski64446de2017-08-15 15:40:37 -0700183
184 // Each of these calls is free to fail and terminate launch if file does not
185 // exist or could not be created.
Tomasz Wiszkowski6c0ce632017-08-15 15:58:19 -0700186 auto system_partition = config::FilePartition::ReuseExistingFile(
Tomasz Wiszkowski64446de2017-08-15 15:40:37 -0700187 FLAGS_system_image_dir + "/system.img");
Tomasz Wiszkowskie4c52f62017-10-02 14:06:21 -0700188 auto data_partition =
189 config::FilePartition::ReuseExistingFile(FLAGS_data_image);
190 auto cache_partition =
191 config::FilePartition::ReuseExistingFile(FLAGS_cache_image);
192 auto vendor_partition =
193 config::FilePartition::ReuseExistingFile(FLAGS_vendor_image);
Tomasz Wiszkowski64446de2017-08-15 15:40:37 -0700194
Greg Hartman76e1afb2017-08-25 21:13:10 -0700195 std::ifstream t(FLAGS_kernel_command_line);
196 if (!t) {
197 LOG(FATAL) << "Unable to open " << FLAGS_kernel_command_line;
198 }
199 t.seekg(0, std::ios::end);
200 size_t commandline_size = t.tellg();
201 if (commandline_size < 1) {
202 LOG(FATAL) << "no command line data found at " << FLAGS_kernel_command_line;
203 }
204 std::string cmdline;
205 cmdline.reserve(commandline_size);
206 t.seekg(0, std::ios::beg);
207 cmdline.assign((std::istreambuf_iterator<char>(t)),
Tomasz Wiszkowskie4c52f62017-10-02 14:06:21 -0700208 std::istreambuf_iterator<char>());
Greg Hartman76e1afb2017-08-25 21:13:10 -0700209 t.close();
Tomasz Wiszkowski64446de2017-08-15 15:40:37 -0700210
211 unsigned long libvirt_version;
212 CHECK(virGetVersion(&libvirt_version, nullptr, nullptr) == 0)
213 << "Could not query libvirt.";
214
215 std::string entropy_source = "/dev/urandom";
216 // There seems to be no macro turning major/minor/patch to a number, but
217 // headers explain this as major * 1'000'000 + minor * 1'000 + patch.
218 if (libvirt_version <= 1003003) {
219 entropy_source = "/dev/random";
220 LOG(WARNING) << "Your system supplies old version of libvirt, that is "
221 << "not able to use /dev/urandom as entropy source.";
222 LOG(WARNING) << "This may affect performance of your virtual instance.";
223 }
224
Tomasz Wiszkowski6c0ce632017-08-15 15:58:19 -0700225 config::GuestConfig cfg;
Tomasz Wiszkowski64446de2017-08-15 15:40:37 -0700226 cfg.SetID(FLAGS_instance)
227 .SetVCPUs(FLAGS_cpus)
228 .SetMemoryMB(FLAGS_memory_mb)
Greg Hartmanb5d93dd2017-08-17 15:54:46 -0700229 .SetKernelName(FLAGS_kernel)
230 .SetInitRDName(FLAGS_initrd)
Greg Hartman76e1afb2017-08-25 21:13:10 -0700231 .SetKernelArgs(cmdline)
Tomasz Wiszkowski64446de2017-08-15 15:40:37 -0700232 .SetIVShMemSocketPath(FLAGS_qemusocket)
233 .SetIVShMemVectorCount(json_root["vsoc_device_regions"].size())
Tomasz Wiszkowski64446de2017-08-15 15:40:37 -0700234 .SetSystemPartitionPath(system_partition->GetName())
235 .SetCachePartitionPath(cache_partition->GetName())
236 .SetDataPartitionPath(data_partition->GetName())
Tomasz Wiszkowskie54deb52017-09-19 12:56:04 -0700237 .SetVendorPartitionPath(vendor_partition->GetName())
Tomasz Wiszkowski64446de2017-08-15 15:40:37 -0700238 .SetMobileBridgeName("abr0")
239 .SetEntropySource(entropy_source)
240 .SetEmulator(json_root["guest"]["vmm_path"].asString());
241
242 std::string xml = cfg.Build();
243 VLOG(1) << "Using XML:\n" << xml;
244
245 auto libvirt_connection = virConnectOpen(kLibVirtQemuTarget);
246 CHECK(libvirt_connection)
247 << "Could not connect to libvirt backend: " << kLibVirtQemuTarget;
248
249 VirtualUSBManager vadb(cfg.GetUSBSocketName());
250 vadb.Start();
251 IVServerManager ivshmem(json_root);
252 ivshmem.Start();
253
254 sleep(1);
255
Tomasz Wiszkowski6c0ce632017-08-15 15:58:19 -0700256 auto domain = virDomainCreateXML(
257 libvirt_connection, xml.c_str(),
258 VIR_DOMAIN_START_PAUSED | VIR_DOMAIN_START_AUTODESTROY);
Tomasz Wiszkowski64446de2017-08-15 15:40:37 -0700259 CHECK(domain) << "Could not create libvirt domain.";
260
261 CHECK(virDomainResume(domain) == 0) << "Could not start domain.";
262 pause();
Romit Dasgupta61b572a2017-06-23 17:48:22 -0700263}