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