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 3 // found in the LICENSE file. 4 5 #include "tools/android/forwarder2/device_controller.h" 6 7 #include <utility> 8 9 #include "base/bind.h" 10 #include "base/bind_helpers.h" 11 #include "base/logging.h" 12 #include "base/memory/scoped_ptr.h" 13 #include "base/message_loop/message_loop_proxy.h" 14 #include "base/single_thread_task_runner.h" 15 #include "tools/android/forwarder2/command.h" 16 #include "tools/android/forwarder2/device_listener.h" 17 #include "tools/android/forwarder2/socket.h" 18 19 namespace forwarder2 { 20 21 // static 22 scoped_ptr<DeviceController> DeviceController::Create( 23 const std::string& adb_unix_socket, 24 int exit_notifier_fd) { 25 scoped_ptr<DeviceController> device_controller; 26 scoped_ptr<Socket> host_socket(new Socket()); 27 if (!host_socket->BindUnix(adb_unix_socket)) { 28 PLOG(ERROR) << "Could not BindAndListen DeviceController socket on port " 29 << adb_unix_socket << ": "; 30 return device_controller.Pass(); 31 } 32 LOG(INFO) << "Listening on Unix Domain Socket " << adb_unix_socket; 33 device_controller.reset( 34 new DeviceController(host_socket.Pass(), exit_notifier_fd)); 35 return device_controller.Pass(); 36 } 37 38 DeviceController::~DeviceController() { 39 DCHECK(construction_task_runner_->RunsTasksOnCurrentThread()); 40 } 41 42 void DeviceController::Start() { 43 AcceptHostCommandSoon(); 44 } 45 46 DeviceController::DeviceController(scoped_ptr<Socket> host_socket, 47 int exit_notifier_fd) 48 : host_socket_(host_socket.Pass()), 49 exit_notifier_fd_(exit_notifier_fd), 50 construction_task_runner_(base::MessageLoopProxy::current()), 51 weak_ptr_factory_(this) { 52 host_socket_->AddEventFd(exit_notifier_fd); 53 } 54 55 void DeviceController::AcceptHostCommandSoon() { 56 base::MessageLoopProxy::current()->PostTask( 57 FROM_HERE, 58 base::Bind(&DeviceController::AcceptHostCommandInternal, 59 base::Unretained(this))); 60 } 61 62 void DeviceController::AcceptHostCommandInternal() { 63 scoped_ptr<Socket> socket(new Socket); 64 if (!host_socket_->Accept(socket.get())) { 65 if (!host_socket_->DidReceiveEvent()) 66 PLOG(ERROR) << "Could not Accept DeviceController socket"; 67 else 68 LOG(INFO) << "Received exit notification"; 69 return; 70 } 71 base::ScopedClosureRunner accept_next_client( 72 base::Bind(&DeviceController::AcceptHostCommandSoon, 73 base::Unretained(this))); 74 // So that |socket| doesn't block on read if it has notifications. 75 socket->AddEventFd(exit_notifier_fd_); 76 int port; 77 command::Type command; 78 if (!ReadCommand(socket.get(), &port, &command)) { 79 LOG(ERROR) << "Invalid command received."; 80 return; 81 } 82 const ListenersMap::iterator listener_it = listeners_.find(port); 83 DeviceListener* const listener = listener_it == listeners_.end() 84 ? static_cast<DeviceListener*>(NULL) : listener_it->second.get(); 85 switch (command) { 86 case command::LISTEN: { 87 if (listener != NULL) { 88 LOG(WARNING) << "Already forwarding port " << port 89 << ". Attempting to restart the listener.\n"; 90 // Note that this deletes the listener object. 91 listeners_.erase(listener_it); 92 } 93 scoped_ptr<DeviceListener> new_listener( 94 DeviceListener::Create( 95 socket.Pass(), port, base::Bind(&DeviceController::DeleteListener, 96 weak_ptr_factory_.GetWeakPtr()))); 97 if (!new_listener) 98 return; 99 new_listener->Start(); 100 // |port| can be zero, to allow dynamically allocated port, so instead, we 101 // call DeviceListener::listener_port() to retrieve the currently 102 // allocated port to this new listener. 103 const int listener_port = new_listener->listener_port(); 104 listeners_.insert( 105 std::make_pair(listener_port, 106 linked_ptr<DeviceListener>(new_listener.release()))); 107 LOG(INFO) << "Forwarding device port " << listener_port << " to host."; 108 break; 109 } 110 case command::DATA_CONNECTION: 111 if (listener == NULL) { 112 LOG(ERROR) << "Data Connection command received, but " 113 << "listener has not been set up yet for port " << port; 114 // After this point it is assumed that, once we close our Adb Data 115 // socket, the Adb forwarder command will propagate the closing of 116 // sockets all the way to the host side. 117 break; 118 } 119 listener->SetAdbDataSocket(socket.Pass()); 120 break; 121 case command::UNLISTEN: 122 if (!listener) { 123 SendCommand(command::UNLISTEN_ERROR, port, socket.get()); 124 break; 125 } 126 listeners_.erase(listener_it); 127 SendCommand(command::UNLISTEN_SUCCESS, port, socket.get()); 128 break; 129 default: 130 // TODO(felipeg): add a KillAllListeners command. 131 LOG(ERROR) << "Invalid command received. Port: " << port 132 << " Command: " << command; 133 } 134 } 135 136 // static 137 void DeviceController::DeleteListener( 138 const base::WeakPtr<DeviceController>& device_controller_ptr, 139 int listener_port) { 140 DeviceController* const controller = device_controller_ptr.get(); 141 if (!controller) 142 return; 143 DCHECK(controller->construction_task_runner_->RunsTasksOnCurrentThread()); 144 const ListenersMap::iterator listener_it = controller->listeners_.find( 145 listener_port); 146 if (listener_it == controller->listeners_.end()) 147 return; 148 const linked_ptr<DeviceListener> listener = listener_it->second; 149 // Note that the listener is removed from the map before it gets destroyed in 150 // case its destructor would access the map. 151 controller->listeners_.erase(listener_it); 152 } 153 154 } // namespace forwarder 155