• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
Create(const std::string & adb_unix_socket,int exit_notifier_fd)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 
~DeviceController()40 DeviceController::~DeviceController() {
41   DCHECK(construction_task_runner_->RunsTasksOnCurrentThread());
42 }
43 
Start()44 void DeviceController::Start() {
45   AcceptHostCommandSoon();
46 }
47 
DeviceController(scoped_ptr<Socket> host_socket,int exit_notifier_fd)48 DeviceController::DeviceController(scoped_ptr<Socket> host_socket,
49                                    int exit_notifier_fd)
50     : host_socket_(host_socket.Pass()),
51       exit_notifier_fd_(exit_notifier_fd),
52       construction_task_runner_(base::MessageLoopProxy::current()),
53       weak_ptr_factory_(this) {
54   host_socket_->AddEventFd(exit_notifier_fd);
55 }
56 
AcceptHostCommandSoon()57 void DeviceController::AcceptHostCommandSoon() {
58   base::MessageLoopProxy::current()->PostTask(
59       FROM_HERE,
60       base::Bind(&DeviceController::AcceptHostCommandInternal,
61                  base::Unretained(this)));
62 }
63 
AcceptHostCommandInternal()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
DeleteListenerOnError(const base::WeakPtr<DeviceController> & device_controller_ptr,scoped_ptr<DeviceListener> device_listener)141 void DeviceController::DeleteListenerOnError(
142       const base::WeakPtr<DeviceController>& device_controller_ptr,
143       scoped_ptr<DeviceListener> device_listener) {
144   DeviceController* const controller = device_controller_ptr.get();
145   if (!controller) {
146     // |device_listener| was already deleted by the controller that did have
147     // its ownership.
148     ignore_result(device_listener.release());
149     return;
150   }
151   DCHECK(controller->construction_task_runner_->RunsTasksOnCurrentThread());
152   bool listener_did_exist = DeleteRefCountedValueInMap(
153       device_listener->listener_port(), &controller->listeners_);
154   DCHECK(listener_did_exist);
155 }
156 
157 }  // namespace forwarder
158