Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <errno.h> | 5 #include <errno.h> |
| 6 #include <signal.h> | 6 #include <signal.h> |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 #include <stdint.h> | 8 #include <stdint.h> |
| 9 #include <sys/types.h> | 9 #include <sys/types.h> |
| 10 #include <sys/wait.h> | 10 #include <sys/wait.h> |
| 11 #include <unistd.h> | 11 #include <unistd.h> |
| 12 | 12 |
| 13 #include <cstdio> | 13 #include <cstdio> |
| 14 #include <iostream> | 14 #include <iostream> |
| 15 #include <limits> | 15 #include <limits> |
| 16 #include <memory> | |
| 16 #include <string> | 17 #include <string> |
| 17 #include <utility> | 18 #include <utility> |
| 18 #include <vector> | 19 #include <vector> |
| 19 | 20 |
| 20 #include "base/at_exit.h" | |
| 21 #include "base/bind.h" | 21 #include "base/bind.h" |
| 22 #include "base/command_line.h" | 22 #include "base/command_line.h" |
| 23 #include "base/compiler_specific.h" | 23 #include "base/compiler_specific.h" |
| 24 #include "base/containers/hash_tables.h" | |
| 25 #include "base/files/file_path.h" | 24 #include "base/files/file_path.h" |
| 26 #include "base/files/file_util.h" | 25 #include "base/files/file_util.h" |
| 27 #include "base/logging.h" | 26 #include "base/logging.h" |
| 28 #include "base/macros.h" | 27 #include "base/macros.h" |
| 29 #include "base/memory/linked_ptr.h" | |
| 30 #include "base/memory/weak_ptr.h" | |
| 31 #include "base/pickle.h" | 28 #include "base/pickle.h" |
| 32 #include "base/process/launch.h" | |
| 33 #include "base/strings/string_number_conversions.h" | 29 #include "base/strings/string_number_conversions.h" |
| 34 #include "base/strings/string_piece.h" | 30 #include "base/strings/string_piece.h" |
| 35 #include "base/strings/string_split.h" | |
| 36 #include "base/strings/string_util.h" | |
| 37 #include "base/strings/stringprintf.h" | |
| 38 #include "base/task_runner.h" | 31 #include "base/task_runner.h" |
| 39 #include "base/threading/thread.h" | 32 #include "base/threading/thread.h" |
| 40 #include "tools/android/forwarder2/common.h" | 33 #include "tools/android/forwarder2/common.h" |
| 41 #include "tools/android/forwarder2/daemon.h" | 34 #include "tools/android/forwarder2/daemon.h" |
| 42 #include "tools/android/forwarder2/host_controller.h" | 35 #include "tools/android/forwarder2/host_controllers_manager.h" |
| 43 #include "tools/android/forwarder2/pipe_notifier.h" | 36 #include "tools/android/forwarder2/pipe_notifier.h" |
| 44 #include "tools/android/forwarder2/socket.h" | |
| 45 #include "tools/android/forwarder2/util.h" | |
| 46 | 37 |
| 47 namespace forwarder2 { | 38 namespace forwarder2 { |
| 39 | |
| 40 // Needs to be global to be able to be accessed from the signal handler. | |
| 41 PipeNotifier* g_notifier = NULL; | |
| 42 | |
| 48 namespace { | 43 namespace { |
| 49 | 44 |
| 50 const char kLogFilePath[] = "/tmp/host_forwarder_log"; | 45 const char kLogFilePath[] = "/tmp/host_forwarder_log"; |
| 51 const char kDaemonIdentifier[] = "chrome_host_forwarder_daemon"; | 46 const char kDaemonIdentifier[] = "chrome_host_forwarder_daemon"; |
| 52 | 47 |
| 53 const int kBufSize = 256; | 48 const int kBufSize = 256; |
| 54 | 49 |
| 55 enum : int { | 50 enum : int { |
|
Ted C
2017/03/28 23:57:37
remove this now?
jbudorick
2017/03/29 01:55:42
ah, yep. purged a bunch of includes from this file
| |
| 56 MAP = 0, | 51 MAP = 0, |
| 57 UNMAP = 1, | 52 UNMAP = 1, |
| 58 UNMAP_ALL = 2, | 53 UNMAP_ALL = 2, |
| 59 }; | 54 }; |
| 60 | 55 |
| 61 // Needs to be global to be able to be accessed from the signal handler. | |
| 62 PipeNotifier* g_notifier = NULL; | |
| 63 | |
| 64 // Lets the daemon fetch the exit notifier file descriptor. | 56 // Lets the daemon fetch the exit notifier file descriptor. |
| 65 int GetExitNotifierFD() { | 57 int GetExitNotifierFD() { |
| 66 DCHECK(g_notifier); | 58 DCHECK(g_notifier); |
| 67 return g_notifier->receiver_fd(); | 59 return g_notifier->receiver_fd(); |
| 68 } | 60 } |
| 69 | 61 |
| 70 void KillHandler(int signal_number) { | 62 void KillHandler(int signal_number) { |
| 71 char buf[kBufSize]; | 63 char buf[kBufSize]; |
| 72 if (signal_number != SIGTERM && signal_number != SIGINT) { | 64 if (signal_number != SIGTERM && signal_number != SIGINT) { |
| 73 snprintf(buf, sizeof(buf), "Ignoring unexpected signal %d.", signal_number); | 65 snprintf(buf, sizeof(buf), "Ignoring unexpected signal %d.", signal_number); |
| 74 SIGNAL_SAFE_LOG(WARNING, buf); | 66 SIGNAL_SAFE_LOG(WARNING, buf); |
| 75 return; | 67 return; |
| 76 } | 68 } |
| 77 snprintf(buf, sizeof(buf), "Received signal %d.", signal_number); | 69 snprintf(buf, sizeof(buf), "Received signal %d.", signal_number); |
| 78 SIGNAL_SAFE_LOG(WARNING, buf); | 70 SIGNAL_SAFE_LOG(WARNING, buf); |
| 79 static int s_kill_handler_count = 0; | 71 static int s_kill_handler_count = 0; |
| 80 CHECK(g_notifier); | 72 CHECK(g_notifier); |
| 81 // If for some reason the forwarder get stuck in any socket waiting forever, | 73 // If for some reason the forwarder get stuck in any socket waiting forever, |
| 82 // we can send a SIGKILL or SIGINT three times to force it die | 74 // we can send a SIGKILL or SIGINT three times to force it die |
| 83 // (non-nicely). This is useful when debugging. | 75 // (non-nicely). This is useful when debugging. |
| 84 ++s_kill_handler_count; | 76 ++s_kill_handler_count; |
| 85 if (!g_notifier->Notify() || s_kill_handler_count > 2) | 77 if (!g_notifier->Notify() || s_kill_handler_count > 2) |
| 86 exit(1); | 78 exit(1); |
| 87 } | 79 } |
| 88 | 80 |
| 89 // Manages HostController instances. There is one HostController instance for | |
| 90 // each connection being forwarded. Note that forwarding can happen with many | |
| 91 // devices (identified with a serial id). | |
| 92 class HostControllersManager { | |
| 93 public: | |
| 94 HostControllersManager() | |
| 95 : controllers_(new HostControllerMap()), | |
| 96 has_failed_(false), | |
| 97 weak_ptr_factory_(this) { | |
| 98 } | |
| 99 | |
| 100 ~HostControllersManager() { | |
| 101 if (!thread_.get()) | |
| 102 return; | |
| 103 // Delete the controllers on the thread they were created on. | |
| 104 thread_->task_runner()->DeleteSoon( | |
| 105 FROM_HERE, controllers_.release()); | |
| 106 } | |
| 107 | |
| 108 void HandleRequest(const std::string& adb_path, | |
| 109 const std::string& device_serial, | |
| 110 int command, | |
| 111 int device_port, | |
| 112 int host_port, | |
| 113 std::unique_ptr<Socket> client_socket) { | |
| 114 // Lazy initialize so that the CLI process doesn't get this thread created. | |
| 115 InitOnce(); | |
| 116 thread_->task_runner()->PostTask( | |
| 117 FROM_HERE, | |
| 118 base::Bind(&HostControllersManager::HandleRequestOnInternalThread, | |
| 119 base::Unretained(this), adb_path, device_serial, command, | |
| 120 device_port, host_port, base::Passed(&client_socket))); | |
| 121 } | |
| 122 | |
| 123 bool has_failed() const { return has_failed_; } | |
| 124 | |
| 125 private: | |
| 126 typedef base::hash_map< | |
| 127 std::string, linked_ptr<HostController> > HostControllerMap; | |
| 128 | |
| 129 static std::string MakeHostControllerMapKey(int adb_port, int device_port) { | |
| 130 return base::StringPrintf("%d:%d", adb_port, device_port); | |
| 131 } | |
| 132 | |
| 133 void InitOnce() { | |
| 134 if (thread_.get()) | |
| 135 return; | |
| 136 at_exit_manager_.reset(new base::AtExitManager()); | |
| 137 thread_.reset(new base::Thread("HostControllersManagerThread")); | |
| 138 thread_->Start(); | |
| 139 } | |
| 140 | |
| 141 // Invoked when a HostController instance reports an error (e.g. due to a | |
| 142 // device connectivity issue). Note that this could be called after the | |
| 143 // controller manager was destroyed which is why a weak pointer is used. | |
| 144 static void DeleteHostController( | |
| 145 const base::WeakPtr<HostControllersManager>& manager_ptr, | |
| 146 std::unique_ptr<HostController> host_controller) { | |
| 147 HostController* const controller = host_controller.release(); | |
| 148 HostControllersManager* const manager = manager_ptr.get(); | |
| 149 if (!manager) { | |
| 150 // Note that |controller| is not leaked in this case since the host | |
| 151 // controllers manager owns the controllers. If the manager was deleted | |
| 152 // then all the controllers (including |controller|) were also deleted. | |
| 153 return; | |
| 154 } | |
| 155 DCHECK(manager->thread_->task_runner()->RunsTasksOnCurrentThread()); | |
| 156 // Note that this will delete |controller| which is owned by the map. | |
| 157 DeleteRefCountedValueInMap( | |
| 158 MakeHostControllerMapKey( | |
| 159 controller->adb_port(), controller->device_port()), | |
| 160 manager->controllers_.get()); | |
| 161 } | |
| 162 | |
| 163 void Map(const std::string& adb_path, | |
| 164 const std::string& device_serial, | |
| 165 int adb_port, | |
| 166 int device_port, | |
| 167 int host_port, | |
| 168 Socket* client_socket) { | |
| 169 if (host_port < 0) { | |
| 170 SendMessage("ERROR: missing host port\n", client_socket); | |
| 171 return; | |
| 172 } | |
| 173 const bool use_dynamic_port_allocation = device_port == 0; | |
| 174 if (!use_dynamic_port_allocation) { | |
| 175 const std::string controller_key = MakeHostControllerMapKey( | |
| 176 adb_port, device_port); | |
| 177 if (controllers_->find(controller_key) != controllers_->end()) { | |
| 178 LOG(INFO) << "Already forwarding device port " << device_port | |
| 179 << " to host port " << host_port; | |
| 180 SendMessage(base::StringPrintf("%d:%d", device_port, host_port), | |
| 181 client_socket); | |
| 182 return; | |
| 183 } | |
| 184 } | |
| 185 // Create a new host controller. | |
| 186 std::unique_ptr<HostController> host_controller(HostController::Create( | |
| 187 device_serial, device_port, host_port, adb_port, GetExitNotifierFD(), | |
| 188 base::Bind(&HostControllersManager::DeleteHostController, | |
| 189 weak_ptr_factory_.GetWeakPtr()))); | |
| 190 if (!host_controller.get()) { | |
| 191 has_failed_ = true; | |
| 192 SendMessage("ERROR: Connection to device failed.\n", client_socket); | |
| 193 LogExistingControllers(client_socket); | |
| 194 return; | |
| 195 } | |
| 196 // Get the current allocated port. | |
| 197 device_port = host_controller->device_port(); | |
| 198 LOG(INFO) << "Forwarding device port " << device_port << " to host port " | |
| 199 << host_port; | |
| 200 const std::string msg = base::StringPrintf("%d:%d", device_port, host_port); | |
| 201 if (!SendMessage(msg, client_socket)) | |
| 202 return; | |
| 203 host_controller->Start(); | |
| 204 controllers_->insert( | |
| 205 std::make_pair(MakeHostControllerMapKey(adb_port, device_port), | |
| 206 linked_ptr<HostController>(host_controller.release()))); | |
| 207 } | |
| 208 | |
| 209 void Unmap(const std::string& adb_path, | |
| 210 const std::string& device_serial, | |
| 211 int adb_port, | |
| 212 int device_port, | |
| 213 Socket* client_socket) { | |
| 214 // Remove the previously created host controller. | |
| 215 const std::string controller_key = | |
| 216 MakeHostControllerMapKey(adb_port, device_port); | |
| 217 const bool controller_did_exist = | |
| 218 DeleteRefCountedValueInMap(controller_key, controllers_.get()); | |
| 219 if (!controller_did_exist) { | |
| 220 SendMessage("ERROR: could not unmap port.\n", client_socket); | |
| 221 LogExistingControllers(client_socket); | |
| 222 } else { | |
| 223 SendMessage("OK", client_socket); | |
| 224 } | |
| 225 | |
| 226 RemoveAdbPortForDeviceIfNeeded(adb_path, device_serial); | |
| 227 } | |
| 228 | |
| 229 void UnmapAll(const std::string& adb_path, | |
| 230 const std::string& device_serial, | |
| 231 int adb_port, | |
| 232 Socket* client_socket) { | |
| 233 const std::string adb_port_str = base::StringPrintf("%d", adb_port); | |
| 234 for (HostControllerMap::const_iterator controller_key = | |
| 235 controllers_->cbegin(); | |
| 236 controller_key != controllers_->cend(); ++controller_key) { | |
| 237 std::vector<std::string> pieces = | |
| 238 base::SplitString(controller_key->first, ":", base::KEEP_WHITESPACE, | |
| 239 base::SPLIT_WANT_ALL); | |
| 240 if (pieces.size() == 2) { | |
| 241 if (pieces[0] == adb_port_str) { | |
| 242 DeleteRefCountedValueInMapFromIterator(controller_key, | |
| 243 controllers_.get()); | |
| 244 } | |
| 245 } else { | |
| 246 LOG(ERROR) << "Unexpected controller key: " << controller_key->first; | |
| 247 } | |
| 248 } | |
| 249 | |
| 250 RemoveAdbPortForDeviceIfNeeded(adb_path, device_serial); | |
| 251 SendMessage("OK", client_socket); | |
| 252 } | |
| 253 | |
| 254 void HandleRequestOnInternalThread(const std::string& adb_path, | |
| 255 const std::string& device_serial, | |
| 256 int command, | |
| 257 int device_port, | |
| 258 int host_port, | |
| 259 std::unique_ptr<Socket> client_socket) { | |
| 260 const int adb_port = GetAdbPortForDevice(adb_path, device_serial); | |
| 261 if (adb_port < 0) { | |
| 262 SendMessage( | |
| 263 "ERROR: could not get adb port for device. You might need to add " | |
| 264 "'adb' to your PATH or provide the device serial id.\n", | |
| 265 client_socket.get()); | |
| 266 return; | |
| 267 } | |
| 268 switch (command) { | |
| 269 case MAP: | |
| 270 Map(adb_path, device_serial, adb_port, device_port, host_port, | |
| 271 client_socket.get()); | |
| 272 break; | |
| 273 case UNMAP: | |
| 274 Unmap(adb_path, device_serial, adb_port, device_port, | |
| 275 client_socket.get()); | |
| 276 break; | |
| 277 case UNMAP_ALL: | |
| 278 UnmapAll(adb_path, device_serial, adb_port, client_socket.get()); | |
| 279 break; | |
| 280 default: | |
| 281 SendMessage( | |
| 282 base::StringPrintf("ERROR: unrecognized command %d\n", command), | |
| 283 client_socket.get()); | |
| 284 break; | |
| 285 } | |
| 286 } | |
| 287 | |
| 288 void LogExistingControllers(Socket* client_socket) { | |
| 289 SendMessage("ERROR: Existing controllers:\n", client_socket); | |
| 290 for (const auto& controller : *controllers_) { | |
| 291 SendMessage(base::StringPrintf("ERROR: %s\n", controller.first.c_str()), | |
| 292 client_socket); | |
| 293 } | |
| 294 } | |
| 295 | |
| 296 void RemoveAdbPortForDeviceIfNeeded(const std::string& adb_path, | |
| 297 const std::string& device_serial) { | |
| 298 base::hash_map<std::string, int>::const_iterator it = | |
| 299 device_serial_to_adb_port_map_.find(device_serial); | |
| 300 if (it == device_serial_to_adb_port_map_.end()) | |
| 301 return; | |
| 302 | |
| 303 int port = it->second; | |
| 304 const std::string prefix = base::StringPrintf("%d:", port); | |
| 305 for (HostControllerMap::const_iterator others = controllers_->begin(); | |
| 306 others != controllers_->end(); ++others) { | |
| 307 if (base::StartsWith(others->first, prefix, base::CompareCase::SENSITIVE)) | |
| 308 return; | |
| 309 } | |
| 310 // No other port is being forwarded to this device: | |
| 311 // - Remove it from our internal serial -> adb port map. | |
| 312 // - Remove from "adb forward" command. | |
| 313 LOG(INFO) << "Device " << device_serial << " has no more ports."; | |
| 314 device_serial_to_adb_port_map_.erase(device_serial); | |
| 315 const std::string serial_part = device_serial.empty() ? | |
| 316 std::string() : std::string("-s ") + device_serial; | |
| 317 const std::string command = base::StringPrintf( | |
| 318 "%s %s forward --remove tcp:%d", | |
| 319 adb_path.c_str(), | |
| 320 serial_part.c_str(), | |
| 321 port); | |
| 322 const base::CommandLine command_line(base::SplitString( | |
| 323 command, " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY)); | |
| 324 int ret; | |
| 325 std::string output; | |
| 326 base::GetAppOutputWithExitCode(command_line, &output, &ret); | |
| 327 LOG(INFO) << command << " ret: " << ret << " output: " << output; | |
| 328 // Wait for the socket to be fully unmapped. | |
| 329 const std::string port_mapped_cmd = base::StringPrintf( | |
| 330 "lsof -nPi:%d", | |
| 331 port); | |
| 332 const base::CommandLine port_mapped_cmd_line( | |
| 333 base::SplitString(port_mapped_cmd, " ", base::TRIM_WHITESPACE, | |
| 334 base::SPLIT_WANT_NONEMPTY)); | |
| 335 const int poll_interval_us = 500 * 1000; | |
| 336 int retries = 3; | |
| 337 while (retries) { | |
| 338 int port_unmapped; | |
| 339 base::GetAppOutputWithExitCode(port_mapped_cmd_line, &output, | |
| 340 &port_unmapped); | |
| 341 LOG(INFO) << "Device " << device_serial << " port " << port << " unmap " | |
| 342 << port_unmapped; | |
| 343 if (port_unmapped) | |
| 344 break; | |
| 345 --retries; | |
| 346 usleep(poll_interval_us); | |
| 347 } | |
| 348 } | |
| 349 | |
| 350 int GetAdbPortForDevice(const std::string adb_path, | |
| 351 const std::string& device_serial) { | |
| 352 base::hash_map<std::string, int>::const_iterator it = | |
| 353 device_serial_to_adb_port_map_.find(device_serial); | |
| 354 if (it != device_serial_to_adb_port_map_.end()) | |
| 355 return it->second; | |
| 356 Socket bind_socket; | |
| 357 CHECK(bind_socket.BindTcp("127.0.0.1", 0)); | |
| 358 const int port = bind_socket.GetPort(); | |
| 359 bind_socket.Close(); | |
| 360 const std::string serial_part = device_serial.empty() ? | |
| 361 std::string() : std::string("-s ") + device_serial; | |
| 362 const std::string command = base::StringPrintf( | |
| 363 "%s %s forward tcp:%d localabstract:chrome_device_forwarder", | |
| 364 adb_path.c_str(), | |
| 365 serial_part.c_str(), | |
| 366 port); | |
| 367 const base::CommandLine command_line(base::SplitString( | |
| 368 command, " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY)); | |
| 369 int ret; | |
| 370 std::string output; | |
| 371 base::GetAppOutputWithExitCode(command_line, &output, &ret); | |
| 372 LOG(INFO) << command << " ret: " << ret << " output: " << output; | |
| 373 if (ret < 0 || !WIFEXITED(ret) || WEXITSTATUS(ret) != 0) | |
| 374 return -1; | |
| 375 device_serial_to_adb_port_map_[device_serial] = port; | |
| 376 return port; | |
| 377 } | |
| 378 | |
| 379 bool SendMessage(const std::string& msg, Socket* client_socket) { | |
| 380 bool result = client_socket->WriteString(msg); | |
| 381 DCHECK(result); | |
| 382 if (!result) | |
| 383 has_failed_ = true; | |
| 384 return result; | |
| 385 } | |
| 386 | |
| 387 base::hash_map<std::string, int> device_serial_to_adb_port_map_; | |
| 388 std::unique_ptr<HostControllerMap> controllers_; | |
| 389 bool has_failed_; | |
| 390 std::unique_ptr<base::AtExitManager> | |
| 391 at_exit_manager_; // Needed by base::Thread. | |
| 392 std::unique_ptr<base::Thread> thread_; | |
| 393 base::WeakPtrFactory<HostControllersManager> weak_ptr_factory_; | |
| 394 }; | |
| 395 | |
| 396 class ServerDelegate : public Daemon::ServerDelegate { | 81 class ServerDelegate : public Daemon::ServerDelegate { |
| 397 public: | 82 public: |
| 398 explicit ServerDelegate(const std::string& adb_path) | 83 explicit ServerDelegate(const std::string& adb_path) |
| 399 : adb_path_(adb_path), has_failed_(false) {} | 84 : adb_path_(adb_path), |
| 85 has_failed_(false), | |
| 86 controllers_manager_(base::Bind(&GetExitNotifierFD)) {} | |
| 400 | 87 |
| 401 bool has_failed() const { | 88 bool has_failed() const { |
| 402 return has_failed_ || controllers_manager_.has_failed(); | 89 return has_failed_ || controllers_manager_.has_failed(); |
| 403 } | 90 } |
| 404 | 91 |
| 405 // Daemon::ServerDelegate: | 92 // Daemon::ServerDelegate: |
| 406 void Init() override { | 93 void Init() override { |
| 407 LOG(INFO) << "Starting host process daemon (pid=" << getpid() << ")"; | 94 LOG(INFO) << "Starting host process daemon (pid=" << getpid() << ")"; |
| 408 DCHECK(!g_notifier); | 95 DCHECK(!g_notifier); |
| 409 g_notifier = new PipeNotifier(); | 96 g_notifier = new PipeNotifier(); |
| (...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 560 | 247 |
| 561 return client_delegate.has_failed() || daemon_delegate.has_failed(); | 248 return client_delegate.has_failed() || daemon_delegate.has_failed(); |
| 562 } | 249 } |
| 563 | 250 |
| 564 } // namespace | 251 } // namespace |
| 565 } // namespace forwarder2 | 252 } // namespace forwarder2 |
| 566 | 253 |
| 567 int main(int argc, char** argv) { | 254 int main(int argc, char** argv) { |
| 568 return forwarder2::RunHostForwarder(argc, argv); | 255 return forwarder2::RunHostForwarder(argc, argv); |
| 569 } | 256 } |
| OLD | NEW |