Greg Hartman | 86b114a | 2017-11-03 21:04:14 -0700 | [diff] [blame] | 1 | /* |
| 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 Wiszkowski | e99c411 | 2017-07-05 10:17:43 -0700 | [diff] [blame] | 17 | #include <limits.h> |
Greg Hartman | 610c03f | 2017-10-31 17:44:11 -0700 | [diff] [blame] | 18 | #include <stdio.h> |
Romit Dasgupta | 61b572a | 2017-06-23 17:48:22 -0700 | [diff] [blame] | 19 | #include <stdlib.h> |
| 20 | #include <unistd.h> |
Tomasz Wiszkowski | e99c411 | 2017-07-05 10:17:43 -0700 | [diff] [blame] | 21 | |
| 22 | #include <fstream> |
Romit Dasgupta | 61b572a | 2017-06-23 17:48:22 -0700 | [diff] [blame] | 23 | #include <memory> |
Tomasz Wiszkowski | 64446de | 2017-08-15 15:40:37 -0700 | [diff] [blame] | 24 | #include <sstream> |
Romit Dasgupta | 61b572a | 2017-06-23 17:48:22 -0700 | [diff] [blame] | 25 | |
Tomasz Wiszkowski | e99c411 | 2017-07-05 10:17:43 -0700 | [diff] [blame] | 26 | #include <gflags/gflags.h> |
Romit Dasgupta | 61b572a | 2017-06-23 17:48:22 -0700 | [diff] [blame] | 27 | #include <glog/logging.h> |
| 28 | |
Tomasz Wiszkowski | 525d02b | 2017-08-14 11:43:04 -0700 | [diff] [blame] | 29 | #include "common/libs/fs/shared_select.h" |
Greg Hartman | 610c03f | 2017-10-31 17:44:11 -0700 | [diff] [blame] | 30 | #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 Hartman | 86b114a | 2017-11-03 21:04:14 -0700 | [diff] [blame] | 36 | #include "host/vsoc/lib/region_control.h" |
Romit Dasgupta | 61b572a | 2017-06-23 17:48:22 -0700 | [diff] [blame] | 37 | |
Tomasz Wiszkowski | bb6c162 | 2017-09-05 14:03:11 -0700 | [diff] [blame] | 38 | namespace { |
Tomasz Wiszkowski | e4c52f6 | 2017-10-02 14:06:21 -0700 | [diff] [blame] | 39 | std::string StringFromEnv(const char* varname, std::string defval) { |
Tomasz Wiszkowski | bb6c162 | 2017-09-05 14:03:11 -0700 | [diff] [blame] | 40 | const char* const valstr = getenv(varname); |
| 41 | if (!valstr) { |
| 42 | return defval; |
| 43 | } |
| 44 | return valstr; |
| 45 | } |
| 46 | } // namespace |
| 47 | |
Greg Hartman | 9be67ff | 2017-11-03 15:10:21 -0700 | [diff] [blame] | 48 | DEFINE_string(cache_image, "", "Location of the cache partition image."); |
Tomasz Wiszkowski | bb6c162 | 2017-09-05 14:03:11 -0700 | [diff] [blame] | 49 | DEFINE_int32(cpus, 2, "Virtual CPU count."); |
Greg Hartman | 9be67ff | 2017-11-03 15:10:21 -0700 | [diff] [blame] | 50 | DEFINE_string(data_image, "", "Location of the data partition image."); |
| 51 | DEFINE_bool(disable_app_armor_security, false, |
| 52 | "Disable AppArmor security in libvirt. For debug only."); |
| 53 | DEFINE_bool(disable_dac_security, false, |
| 54 | "Disable DAC security in libvirt. For debug only."); |
| 55 | DEFINE_string(extra_kernel_command_line, "", |
| 56 | "Additional flags to put on the kernel command line"); |
Greg Hartman | efe487a | 2017-11-10 20:39:06 -0800 | [diff] [blame^] | 57 | DECLARE_int32(instance); |
Greg Hartman | 9be67ff | 2017-11-03 15:10:21 -0700 | [diff] [blame] | 58 | DEFINE_string(initrd, "", "Location of cuttlefish initrd file."); |
Greg Hartman | 9be67ff | 2017-11-03 15:10:21 -0700 | [diff] [blame] | 59 | DEFINE_string(kernel, "", "Location of cuttlefish kernel file."); |
| 60 | DEFINE_string(kernel_command_line, "", |
| 61 | "Location of a text file with the kernel command line."); |
Greg Hartman | 610c03f | 2017-10-31 17:44:11 -0700 | [diff] [blame] | 62 | DEFINE_string(launch_command, "virsh create /dev/fd/0", |
| 63 | "Command to start an instance"); |
Greg Hartman | 610c03f | 2017-10-31 17:44:11 -0700 | [diff] [blame] | 64 | DEFINE_string(layout, |
| 65 | StringFromEnv("ANDROID_HOST_OUT", StringFromEnv("HOME", ".")) + |
Greg Hartman | baa4c91 | 2017-11-02 00:33:15 -0700 | [diff] [blame] | 66 | "/config/vsoc_mem.json", |
Tomasz Wiszkowski | 6c0ce63 | 2017-08-15 15:58:19 -0700 | [diff] [blame] | 67 | "Location of the vsoc_mem.json file."); |
Greg Hartman | 9be67ff | 2017-11-03 15:10:21 -0700 | [diff] [blame] | 68 | DEFINE_bool(log_xml, false, "Log the XML machine configuration"); |
| 69 | DEFINE_int32(memory_mb, 2048, |
| 70 | "Total amount of memory available for guest, MB."); |
Tomasz Wiszkowski | e99c411 | 2017-07-05 10:17:43 -0700 | [diff] [blame] | 71 | DEFINE_string(mempath, "/dev/shm/ivshmem", |
| 72 | "Target location for the shmem file."); |
Greg Hartman | 9be67ff | 2017-11-03 15:10:21 -0700 | [diff] [blame] | 73 | DEFINE_string(mobile_interface, "abr0", |
| 74 | "Network interface to use for mobile networking"); |
Tomasz Wiszkowski | e99c411 | 2017-07-05 10:17:43 -0700 | [diff] [blame] | 75 | DEFINE_string(qemusocket, "/tmp/ivshmem_socket_qemu", "QEmu socket path"); |
Tomasz Wiszkowski | e4c52f6 | 2017-10-02 14:06:21 -0700 | [diff] [blame] | 76 | DEFINE_string(system_image_dir, |
| 77 | StringFromEnv("ANDROID_PRODUCT_OUT", StringFromEnv("HOME", ".")), |
Tomasz Wiszkowski | bb6c162 | 2017-09-05 14:03:11 -0700 | [diff] [blame] | 78 | "Location of the system partition images."); |
Tomasz Wiszkowski | e54deb5 | 2017-09-19 12:56:04 -0700 | [diff] [blame] | 79 | DEFINE_string(vendor_image, "", "Location of the vendor partition image."); |
Romit Dasgupta | 61b572a | 2017-06-23 17:48:22 -0700 | [diff] [blame] | 80 | |
Tomasz Wiszkowski | 525d02b | 2017-08-14 11:43:04 -0700 | [diff] [blame] | 81 | DEFINE_string(usbipsocket, "android_usbip", "Name of the USB/IP socket."); |
Greg Hartman | 9be67ff | 2017-11-03 15:10:21 -0700 | [diff] [blame] | 82 | DEFINE_string(uuid, "", "UUID to use for the device. Random if not specified"); |
Tomasz Wiszkowski | 525d02b | 2017-08-14 11:43:04 -0700 | [diff] [blame] | 83 | |
Tomasz Wiszkowski | e99c411 | 2017-07-05 10:17:43 -0700 | [diff] [blame] | 84 | namespace { |
Tomasz Wiszkowski | 64446de | 2017-08-15 15:40:37 -0700 | [diff] [blame] | 85 | Json::Value LoadLayoutFile(const std::string& file) { |
Tomasz Wiszkowski | e99c411 | 2017-07-05 10:17:43 -0700 | [diff] [blame] | 86 | 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 Dasgupta | 61b572a | 2017-06-23 17:48:22 -0700 | [diff] [blame] | 90 | } |
| 91 | |
Tomasz Wiszkowski | e99c411 | 2017-07-05 10:17:43 -0700 | [diff] [blame] | 92 | 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 Dasgupta | 61b572a | 2017-06-23 17:48:22 -0700 | [diff] [blame] | 100 | } |
Tomasz Wiszkowski | 525d02b | 2017-08-14 11:43:04 -0700 | [diff] [blame] | 101 | |
Tomasz Wiszkowski | 64446de | 2017-08-15 15:40:37 -0700 | [diff] [blame] | 102 | // VirtualUSBManager manages virtual USB device presence for Cuttlefish. |
| 103 | class VirtualUSBManager { |
| 104 | public: |
| 105 | VirtualUSBManager(const std::string& usbsocket) |
| 106 | : adb_{usbsocket, FLAGS_usbipsocket}, |
| 107 | usbip_{FLAGS_usbipsocket, adb_.Pool()} {} |
Tomasz Wiszkowski | 525d02b | 2017-08-14 11:43:04 -0700 | [diff] [blame] | 108 | |
Tomasz Wiszkowski | 64446de | 2017-08-15 15:40:37 -0700 | [diff] [blame] | 109 | ~VirtualUSBManager() = default; |
Tomasz Wiszkowski | 525d02b | 2017-08-14 11:43:04 -0700 | [diff] [blame] | 110 | |
Tomasz Wiszkowski | 64446de | 2017-08-15 15:40:37 -0700 | [diff] [blame] | 111 | // 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 Wiszkowski | 525d02b | 2017-08-14 11:43:04 -0700 | [diff] [blame] | 116 | } |
Tomasz Wiszkowski | 64446de | 2017-08-15 15:40:37 -0700 | [diff] [blame] | 117 | |
| 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. |
| 145 | class IVServerManager { |
| 146 | public: |
| 147 | IVServerManager(const Json::Value& json_root) |
| 148 | : server_(ivserver::IVServerOptions(FLAGS_layout, FLAGS_mempath, |
Greg Hartman | efe487a | 2017-11-10 20:39:06 -0800 | [diff] [blame^] | 149 | FLAGS_qemusocket, |
| 150 | vsoc::GetShmClientSocketPath()), |
Tomasz Wiszkowski | 64446de | 2017-08-15 15:40:37 -0700 | [diff] [blame] | 151 | 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 Wiszkowski | e99c411 | 2017-07-05 10:17:43 -0700 | [diff] [blame] | 168 | } // anonymous namespace |
Romit Dasgupta | 61b572a | 2017-06-23 17:48:22 -0700 | [diff] [blame] | 169 | |
Tomasz Wiszkowski | 64446de | 2017-08-15 15:40:37 -0700 | [diff] [blame] | 170 | int main(int argc, char** argv) { |
Greg Hartman | 610c03f | 2017-10-31 17:44:11 -0700 | [diff] [blame] | 171 | ::android::base::InitLogging(argv, android::base::StderrLogger); |
Tomasz Wiszkowski | e99c411 | 2017-07-05 10:17:43 -0700 | [diff] [blame] | 172 | google::ParseCommandLineFlags(&argc, &argv, true); |
Romit Dasgupta | 61b572a | 2017-06-23 17:48:22 -0700 | [diff] [blame] | 173 | |
Tomasz Wiszkowski | bb6c162 | 2017-09-05 14:03:11 -0700 | [diff] [blame] | 174 | 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 Wiszkowski | bb6c162 | 2017-09-05 14:03:11 -0700 | [diff] [blame] | 179 | 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 Wiszkowski | 283c3d3 | 2017-09-07 11:17:07 -0700 | [diff] [blame] | 187 | 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 Wiszkowski | e54deb5 | 2017-09-19 12:56:04 -0700 | [diff] [blame] | 199 | if (FLAGS_vendor_image.empty()) { |
| 200 | FLAGS_vendor_image = FLAGS_system_image_dir + "/vendor.img"; |
| 201 | } |
| 202 | |
Tomasz Wiszkowski | e99c411 | 2017-07-05 10:17:43 -0700 | [diff] [blame] | 203 | Json::Value json_root = LoadLayoutFile(FLAGS_layout); |
Tomasz Wiszkowski | 64446de | 2017-08-15 15:40:37 -0700 | [diff] [blame] | 204 | |
| 205 | // Each of these calls is free to fail and terminate launch if file does not |
| 206 | // exist or could not be created. |
Tomasz Wiszkowski | 6c0ce63 | 2017-08-15 15:58:19 -0700 | [diff] [blame] | 207 | auto system_partition = config::FilePartition::ReuseExistingFile( |
Tomasz Wiszkowski | 64446de | 2017-08-15 15:40:37 -0700 | [diff] [blame] | 208 | FLAGS_system_image_dir + "/system.img"); |
Tomasz Wiszkowski | e4c52f6 | 2017-10-02 14:06:21 -0700 | [diff] [blame] | 209 | 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 Wiszkowski | 64446de | 2017-08-15 15:40:37 -0700 | [diff] [blame] | 215 | |
Greg Hartman | 76e1afb | 2017-08-25 21:13:10 -0700 | [diff] [blame] | 216 | 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 Wiszkowski | e4c52f6 | 2017-10-02 14:06:21 -0700 | [diff] [blame] | 229 | std::istreambuf_iterator<char>()); |
Greg Hartman | 76e1afb | 2017-08-25 21:13:10 -0700 | [diff] [blame] | 230 | t.close(); |
Greg Hartman | 9be67ff | 2017-11-03 15:10:21 -0700 | [diff] [blame] | 231 | cmdline += FLAGS_extra_kernel_command_line; |
Tomasz Wiszkowski | 64446de | 2017-08-15 15:40:37 -0700 | [diff] [blame] | 232 | |
Tomasz Wiszkowski | 64446de | 2017-08-15 15:40:37 -0700 | [diff] [blame] | 233 | std::string entropy_source = "/dev/urandom"; |
Tomasz Wiszkowski | 64446de | 2017-08-15 15:40:37 -0700 | [diff] [blame] | 234 | |
Tomasz Wiszkowski | 6c0ce63 | 2017-08-15 15:58:19 -0700 | [diff] [blame] | 235 | config::GuestConfig cfg; |
Tomasz Wiszkowski | 64446de | 2017-08-15 15:40:37 -0700 | [diff] [blame] | 236 | cfg.SetID(FLAGS_instance) |
| 237 | .SetVCPUs(FLAGS_cpus) |
| 238 | .SetMemoryMB(FLAGS_memory_mb) |
Greg Hartman | b5d93dd | 2017-08-17 15:54:46 -0700 | [diff] [blame] | 239 | .SetKernelName(FLAGS_kernel) |
| 240 | .SetInitRDName(FLAGS_initrd) |
Greg Hartman | 76e1afb | 2017-08-25 21:13:10 -0700 | [diff] [blame] | 241 | .SetKernelArgs(cmdline) |
Tomasz Wiszkowski | 64446de | 2017-08-15 15:40:37 -0700 | [diff] [blame] | 242 | .SetIVShMemSocketPath(FLAGS_qemusocket) |
| 243 | .SetIVShMemVectorCount(json_root["vsoc_device_regions"].size()) |
Tomasz Wiszkowski | 64446de | 2017-08-15 15:40:37 -0700 | [diff] [blame] | 244 | .SetSystemPartitionPath(system_partition->GetName()) |
| 245 | .SetCachePartitionPath(cache_partition->GetName()) |
| 246 | .SetDataPartitionPath(data_partition->GetName()) |
Tomasz Wiszkowski | e54deb5 | 2017-09-19 12:56:04 -0700 | [diff] [blame] | 247 | .SetVendorPartitionPath(vendor_partition->GetName()) |
Greg Hartman | 610c03f | 2017-10-31 17:44:11 -0700 | [diff] [blame] | 248 | .SetMobileBridgeName(FLAGS_mobile_interface) |
Greg Hartman | 9be67ff | 2017-11-03 15:10:21 -0700 | [diff] [blame] | 249 | .SetDisableDACSecurity(FLAGS_disable_dac_security) |
| 250 | .SetDisableAppArmorSecurity(FLAGS_disable_app_armor_security) |
| 251 | .SetUUID(FLAGS_uuid); |
Greg Hartman | efe487a | 2017-11-10 20:39:06 -0800 | [diff] [blame^] | 252 | cfg.SetUSBV1SocketName(std::string("/tmp/") + cfg.GetInstanceName() + "-usb"); |
Tomasz Wiszkowski | 64446de | 2017-08-15 15:40:37 -0700 | [diff] [blame] | 253 | |
| 254 | std::string xml = cfg.Build(); |
Greg Hartman | 610c03f | 2017-10-31 17:44:11 -0700 | [diff] [blame] | 255 | if (FLAGS_log_xml) { |
| 256 | LOG(INFO) << "Using XML:\n" << xml; |
| 257 | } |
Tomasz Wiszkowski | 64446de | 2017-08-15 15:40:37 -0700 | [diff] [blame] | 258 | |
Greg Hartman | 610c03f | 2017-10-31 17:44:11 -0700 | [diff] [blame] | 259 | VirtualUSBManager vadb(cfg.GetUSBV1SocketName()); |
Tomasz Wiszkowski | 64446de | 2017-08-15 15:40:37 -0700 | [diff] [blame] | 260 | vadb.Start(); |
| 261 | IVServerManager ivshmem(json_root); |
| 262 | ivshmem.Start(); |
| 263 | |
| 264 | sleep(1); |
| 265 | |
Greg Hartman | 610c03f | 2017-10-31 17:44:11 -0700 | [diff] [blame] | 266 | 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 Wiszkowski | 64446de | 2017-08-15 15:40:37 -0700 | [diff] [blame] | 278 | pause(); |
Romit Dasgupta | 61b572a | 2017-06-23 17:48:22 -0700 | [diff] [blame] | 279 | } |