Home | History | Annotate | Download | only in forwarder2
      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