Tomasz Wiszkowski | e99c411 | 2017-07-05 10:17:43 -0700 | [diff] [blame] | 1 | #include <limits.h> |
Romit Dasgupta | 61b572a | 2017-06-23 17:48:22 -0700 | [diff] [blame] | 2 | #include <stdlib.h> |
| 3 | #include <unistd.h> |
Tomasz Wiszkowski | e99c411 | 2017-07-05 10:17:43 -0700 | [diff] [blame] | 4 | |
| 5 | #include <fstream> |
Romit Dasgupta | 61b572a | 2017-06-23 17:48:22 -0700 | [diff] [blame] | 6 | #include <memory> |
Tomasz Wiszkowski | 64446de | 2017-08-15 15:40:37 -0700 | [diff] [blame] | 7 | #include <sstream> |
Romit Dasgupta | 61b572a | 2017-06-23 17:48:22 -0700 | [diff] [blame] | 8 | |
Tomasz Wiszkowski | e99c411 | 2017-07-05 10:17:43 -0700 | [diff] [blame] | 9 | #include <gflags/gflags.h> |
Romit Dasgupta | 61b572a | 2017-06-23 17:48:22 -0700 | [diff] [blame] | 10 | #include <glog/logging.h> |
Tomasz Wiszkowski | 64446de | 2017-08-15 15:40:37 -0700 | [diff] [blame] | 11 | #include <libvirt/libvirt.h> |
Romit Dasgupta | 61b572a | 2017-06-23 17:48:22 -0700 | [diff] [blame] | 12 | |
Tomasz Wiszkowski | 525d02b | 2017-08-14 11:43:04 -0700 | [diff] [blame] | 13 | #include "common/libs/fs/shared_select.h" |
Tomasz Wiszkowski | 6c0ce63 | 2017-08-15 15:58:19 -0700 | [diff] [blame] | 14 | #include "host/config/file_partition.h" |
| 15 | #include "host/config/guest_config.h" |
Tomasz Wiszkowski | e99c411 | 2017-07-05 10:17:43 -0700 | [diff] [blame] | 16 | #include "host/ivserver/ivserver.h" |
| 17 | #include "host/ivserver/options.h" |
Tomasz Wiszkowski | 525d02b | 2017-08-14 11:43:04 -0700 | [diff] [blame] | 18 | #include "host/vadb/usbip/server.h" |
| 19 | #include "host/vadb/virtual_adb_server.h" |
Romit Dasgupta | 61b572a | 2017-06-23 17:48:22 -0700 | [diff] [blame] | 20 | |
Tomasz Wiszkowski | bb6c162 | 2017-09-05 14:03:11 -0700 | [diff] [blame] | 21 | namespace { |
Tomasz Wiszkowski | e4c52f6 | 2017-10-02 14:06:21 -0700 | [diff] [blame^] | 22 | std::string StringFromEnv(const char* varname, std::string defval) { |
Tomasz Wiszkowski | bb6c162 | 2017-09-05 14:03:11 -0700 | [diff] [blame] | 23 | const char* const valstr = getenv(varname); |
| 24 | if (!valstr) { |
| 25 | return defval; |
| 26 | } |
| 27 | return valstr; |
| 28 | } |
| 29 | } // namespace |
| 30 | |
Tomasz Wiszkowski | 64446de | 2017-08-15 15:40:37 -0700 | [diff] [blame] | 31 | DEFINE_int32(instance, 1, "Instance number. Must be unique."); |
Tomasz Wiszkowski | bb6c162 | 2017-09-05 14:03:11 -0700 | [diff] [blame] | 32 | DEFINE_int32(cpus, 2, "Virtual CPU count."); |
| 33 | DEFINE_int32(memory_mb, 2048, |
Tomasz Wiszkowski | 6c0ce63 | 2017-08-15 15:58:19 -0700 | [diff] [blame] | 34 | "Total amount of memory available for guest, MB."); |
| 35 | DEFINE_string(layout, "/usr/share/cuttlefish-common/vsoc_mem.json", |
| 36 | "Location of the vsoc_mem.json file."); |
Tomasz Wiszkowski | e99c411 | 2017-07-05 10:17:43 -0700 | [diff] [blame] | 37 | DEFINE_string(mempath, "/dev/shm/ivshmem", |
| 38 | "Target location for the shmem file."); |
Greg Hartman | 8fae86d | 2017-08-25 14:16:15 -0700 | [diff] [blame] | 39 | DEFINE_int32(shmsize, 0, "(ignored)"); |
Tomasz Wiszkowski | e99c411 | 2017-07-05 10:17:43 -0700 | [diff] [blame] | 40 | DEFINE_string(qemusocket, "/tmp/ivshmem_socket_qemu", "QEmu socket path"); |
| 41 | DEFINE_string(clientsocket, "/tmp/ivshmem_socket_client", "Client socket path"); |
Tomasz Wiszkowski | 283c3d3 | 2017-09-07 11:17:07 -0700 | [diff] [blame] | 42 | |
Tomasz Wiszkowski | e4c52f6 | 2017-10-02 14:06:21 -0700 | [diff] [blame^] | 43 | DEFINE_string(system_image_dir, |
| 44 | StringFromEnv("ANDROID_PRODUCT_OUT", StringFromEnv("HOME", ".")), |
Tomasz Wiszkowski | bb6c162 | 2017-09-05 14:03:11 -0700 | [diff] [blame] | 45 | "Location of the system partition images."); |
Tomasz Wiszkowski | 64446de | 2017-08-15 15:40:37 -0700 | [diff] [blame] | 46 | DEFINE_string(kernel, "", "Location of cuttlefish kernel file."); |
Tomasz Wiszkowski | 283c3d3 | 2017-09-07 11:17:07 -0700 | [diff] [blame] | 47 | DEFINE_string(kernel_command_line, "", |
| 48 | "Location of a text file with the kernel command line."); |
| 49 | DEFINE_string(initrd, "", "Location of cuttlefish initrd file."); |
| 50 | DEFINE_string(data_image, "", "Location of the data partition image."); |
| 51 | DEFINE_string(cache_image, "", "Location of the cache partition image."); |
Tomasz Wiszkowski | e54deb5 | 2017-09-19 12:56:04 -0700 | [diff] [blame] | 52 | DEFINE_string(vendor_image, "", "Location of the vendor partition image."); |
Romit Dasgupta | 61b572a | 2017-06-23 17:48:22 -0700 | [diff] [blame] | 53 | |
Tomasz Wiszkowski | 525d02b | 2017-08-14 11:43:04 -0700 | [diff] [blame] | 54 | DEFINE_string(usbipsocket, "android_usbip", "Name of the USB/IP socket."); |
| 55 | |
Tomasz Wiszkowski | e99c411 | 2017-07-05 10:17:43 -0700 | [diff] [blame] | 56 | namespace { |
Tomasz Wiszkowski | 64446de | 2017-08-15 15:40:37 -0700 | [diff] [blame] | 57 | constexpr char kLibVirtQemuTarget[] = "qemu:///system"; |
| 58 | |
| 59 | Json::Value LoadLayoutFile(const std::string& file) { |
Tomasz Wiszkowski | e99c411 | 2017-07-05 10:17:43 -0700 | [diff] [blame] | 60 | 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 Dasgupta | 61b572a | 2017-06-23 17:48:22 -0700 | [diff] [blame] | 64 | } |
| 65 | |
Tomasz Wiszkowski | e99c411 | 2017-07-05 10:17:43 -0700 | [diff] [blame] | 66 | 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 Dasgupta | 61b572a | 2017-06-23 17:48:22 -0700 | [diff] [blame] | 74 | } |
Tomasz Wiszkowski | 525d02b | 2017-08-14 11:43:04 -0700 | [diff] [blame] | 75 | |
Tomasz Wiszkowski | 64446de | 2017-08-15 15:40:37 -0700 | [diff] [blame] | 76 | // VirtualUSBManager manages virtual USB device presence for Cuttlefish. |
| 77 | class VirtualUSBManager { |
| 78 | public: |
| 79 | VirtualUSBManager(const std::string& usbsocket) |
| 80 | : adb_{usbsocket, FLAGS_usbipsocket}, |
| 81 | usbip_{FLAGS_usbipsocket, adb_.Pool()} {} |
Tomasz Wiszkowski | 525d02b | 2017-08-14 11:43:04 -0700 | [diff] [blame] | 82 | |
Tomasz Wiszkowski | 64446de | 2017-08-15 15:40:37 -0700 | [diff] [blame] | 83 | ~VirtualUSBManager() = default; |
Tomasz Wiszkowski | 525d02b | 2017-08-14 11:43:04 -0700 | [diff] [blame] | 84 | |
Tomasz Wiszkowski | 64446de | 2017-08-15 15:40:37 -0700 | [diff] [blame] | 85 | // 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 Wiszkowski | 525d02b | 2017-08-14 11:43:04 -0700 | [diff] [blame] | 90 | } |
Tomasz Wiszkowski | 64446de | 2017-08-15 15:40:37 -0700 | [diff] [blame] | 91 | |
| 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. |
| 119 | class IVServerManager { |
| 120 | public: |
| 121 | IVServerManager(const Json::Value& json_root) |
| 122 | : server_(ivserver::IVServerOptions(FLAGS_layout, FLAGS_mempath, |
Greg Hartman | 8fae86d | 2017-08-25 14:16:15 -0700 | [diff] [blame] | 123 | FLAGS_qemusocket, FLAGS_clientsocket), |
Tomasz Wiszkowski | 64446de | 2017-08-15 15:40:37 -0700 | [diff] [blame] | 124 | 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 Wiszkowski | e99c411 | 2017-07-05 10:17:43 -0700 | [diff] [blame] | 141 | } // anonymous namespace |
Romit Dasgupta | 61b572a | 2017-06-23 17:48:22 -0700 | [diff] [blame] | 142 | |
Tomasz Wiszkowski | 64446de | 2017-08-15 15:40:37 -0700 | [diff] [blame] | 143 | int main(int argc, char** argv) { |
Tomasz Wiszkowski | 525d02b | 2017-08-14 11:43:04 -0700 | [diff] [blame] | 144 | google::InitGoogleLogging(argv[0]); |
Tomasz Wiszkowski | a29455e | 2017-07-07 14:23:16 -0700 | [diff] [blame] | 145 | google::InstallFailureSignalHandler(); |
Tomasz Wiszkowski | e99c411 | 2017-07-05 10:17:43 -0700 | [diff] [blame] | 146 | google::ParseCommandLineFlags(&argc, &argv, true); |
Romit Dasgupta | 61b572a | 2017-06-23 17:48:22 -0700 | [diff] [blame] | 147 | |
Tomasz Wiszkowski | bb6c162 | 2017-09-05 14:03:11 -0700 | [diff] [blame] | 148 | // 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 Wiszkowski | bb6c162 | 2017-09-05 14:03:11 -0700 | [diff] [blame] | 156 | 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 Wiszkowski | 283c3d3 | 2017-09-07 11:17:07 -0700 | [diff] [blame] | 164 | 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 Wiszkowski | e54deb5 | 2017-09-19 12:56:04 -0700 | [diff] [blame] | 176 | if (FLAGS_vendor_image.empty()) { |
| 177 | FLAGS_vendor_image = FLAGS_system_image_dir + "/vendor.img"; |
| 178 | } |
| 179 | |
Tomasz Wiszkowski | 64446de | 2017-08-15 15:40:37 -0700 | [diff] [blame] | 180 | CHECK(virInitialize() == 0) << "Could not initialize libvirt."; |
Romit Dasgupta | 61b572a | 2017-06-23 17:48:22 -0700 | [diff] [blame] | 181 | |
Tomasz Wiszkowski | e99c411 | 2017-07-05 10:17:43 -0700 | [diff] [blame] | 182 | Json::Value json_root = LoadLayoutFile(FLAGS_layout); |
Tomasz Wiszkowski | 64446de | 2017-08-15 15:40:37 -0700 | [diff] [blame] | 183 | |
| 184 | // Each of these calls is free to fail and terminate launch if file does not |
| 185 | // exist or could not be created. |
Tomasz Wiszkowski | 6c0ce63 | 2017-08-15 15:58:19 -0700 | [diff] [blame] | 186 | auto system_partition = config::FilePartition::ReuseExistingFile( |
Tomasz Wiszkowski | 64446de | 2017-08-15 15:40:37 -0700 | [diff] [blame] | 187 | FLAGS_system_image_dir + "/system.img"); |
Tomasz Wiszkowski | e4c52f6 | 2017-10-02 14:06:21 -0700 | [diff] [blame^] | 188 | 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 Wiszkowski | 64446de | 2017-08-15 15:40:37 -0700 | [diff] [blame] | 194 | |
Greg Hartman | 76e1afb | 2017-08-25 21:13:10 -0700 | [diff] [blame] | 195 | 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 Wiszkowski | e4c52f6 | 2017-10-02 14:06:21 -0700 | [diff] [blame^] | 208 | std::istreambuf_iterator<char>()); |
Greg Hartman | 76e1afb | 2017-08-25 21:13:10 -0700 | [diff] [blame] | 209 | t.close(); |
Tomasz Wiszkowski | 64446de | 2017-08-15 15:40:37 -0700 | [diff] [blame] | 210 | |
| 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 Wiszkowski | 6c0ce63 | 2017-08-15 15:58:19 -0700 | [diff] [blame] | 225 | config::GuestConfig cfg; |
Tomasz Wiszkowski | 64446de | 2017-08-15 15:40:37 -0700 | [diff] [blame] | 226 | cfg.SetID(FLAGS_instance) |
| 227 | .SetVCPUs(FLAGS_cpus) |
| 228 | .SetMemoryMB(FLAGS_memory_mb) |
Greg Hartman | b5d93dd | 2017-08-17 15:54:46 -0700 | [diff] [blame] | 229 | .SetKernelName(FLAGS_kernel) |
| 230 | .SetInitRDName(FLAGS_initrd) |
Greg Hartman | 76e1afb | 2017-08-25 21:13:10 -0700 | [diff] [blame] | 231 | .SetKernelArgs(cmdline) |
Tomasz Wiszkowski | 64446de | 2017-08-15 15:40:37 -0700 | [diff] [blame] | 232 | .SetIVShMemSocketPath(FLAGS_qemusocket) |
| 233 | .SetIVShMemVectorCount(json_root["vsoc_device_regions"].size()) |
Tomasz Wiszkowski | 64446de | 2017-08-15 15:40:37 -0700 | [diff] [blame] | 234 | .SetSystemPartitionPath(system_partition->GetName()) |
| 235 | .SetCachePartitionPath(cache_partition->GetName()) |
| 236 | .SetDataPartitionPath(data_partition->GetName()) |
Tomasz Wiszkowski | e54deb5 | 2017-09-19 12:56:04 -0700 | [diff] [blame] | 237 | .SetVendorPartitionPath(vendor_partition->GetName()) |
Tomasz Wiszkowski | 64446de | 2017-08-15 15:40:37 -0700 | [diff] [blame] | 238 | .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 Wiszkowski | 6c0ce63 | 2017-08-15 15:58:19 -0700 | [diff] [blame] | 256 | auto domain = virDomainCreateXML( |
| 257 | libvirt_connection, xml.c_str(), |
| 258 | VIR_DOMAIN_START_PAUSED | VIR_DOMAIN_START_AUTODESTROY); |
Tomasz Wiszkowski | 64446de | 2017-08-15 15:40:37 -0700 | [diff] [blame] | 259 | CHECK(domain) << "Could not create libvirt domain."; |
| 260 | |
| 261 | CHECK(virDomainResume(domain) == 0) << "Could not start domain."; |
| 262 | pause(); |
Romit Dasgupta | 61b572a | 2017-06-23 17:48:22 -0700 | [diff] [blame] | 263 | } |