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.
5 #include "tools/android/forwarder2/device_controller.h"
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/single_thread_task_runner.h"
15 #include "base/thread_task_runner_handle.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"
21 namespace forwarder2
{
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();
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();
40 DeviceController::~DeviceController() {
41 DCHECK(construction_task_runner_
->RunsTasksOnCurrentThread());
44 void DeviceController::Start() {
45 AcceptHostCommandSoon();
48 DeviceController::DeviceController(scoped_ptr
<Socket
> host_socket
,
50 : host_socket_(host_socket
.Pass()),
51 exit_notifier_fd_(exit_notifier_fd
),
52 construction_task_runner_(base::ThreadTaskRunnerHandle::Get()),
53 weak_ptr_factory_(this) {
54 host_socket_
->AddEventFd(exit_notifier_fd
);
57 void DeviceController::AcceptHostCommandSoon() {
58 base::ThreadTaskRunnerHandle::Get()->PostTask(
59 FROM_HERE
, base::Bind(&DeviceController::AcceptHostCommandInternal
,
60 base::Unretained(this)));
63 void DeviceController::AcceptHostCommandInternal() {
64 scoped_ptr
<Socket
> socket(new Socket
);
65 if (!host_socket_
->Accept(socket
.get())) {
66 if (!host_socket_
->DidReceiveEvent())
67 PLOG(ERROR
) << "Could not Accept DeviceController socket";
69 LOG(INFO
) << "Received exit notification";
72 base::ScopedClosureRunner
accept_next_client(
73 base::Bind(&DeviceController::AcceptHostCommandSoon
,
74 base::Unretained(this)));
75 // So that |socket| doesn't block on read if it has notifications.
76 socket
->AddEventFd(exit_notifier_fd_
);
78 command::Type command
;
79 if (!ReadCommand(socket
.get(), &port
, &command
)) {
80 LOG(ERROR
) << "Invalid command received.";
83 const ListenersMap::iterator listener_it
= listeners_
.find(port
);
84 DeviceListener
* const listener
= listener_it
== listeners_
.end()
85 ? static_cast<DeviceListener
*>(NULL
) : listener_it
->second
.get();
87 case command::LISTEN
: {
88 if (listener
!= NULL
) {
89 LOG(WARNING
) << "Already forwarding port " << port
90 << ". Attempting to restart the listener.\n";
91 DeleteRefCountedValueInMapFromIterator(listener_it
, &listeners_
);
93 scoped_ptr
<DeviceListener
> new_listener(
94 DeviceListener::Create(
96 base::Bind(&DeviceController::DeleteListenerOnError
,
97 weak_ptr_factory_
.GetWeakPtr())));
100 new_listener
->Start();
101 // |port| can be zero, to allow dynamically allocated port, so instead, we
102 // call DeviceListener::listener_port() to retrieve the currently
103 // allocated port to this new listener.
104 const int listener_port
= new_listener
->listener_port();
106 std::make_pair(listener_port
,
107 linked_ptr
<DeviceListener
>(new_listener
.release())));
108 LOG(INFO
) << "Forwarding device port " << listener_port
<< " to host.";
111 case command::DATA_CONNECTION
:
112 if (listener
== NULL
) {
113 LOG(ERROR
) << "Data Connection command received, but "
114 << "listener has not been set up yet for port " << port
;
115 // After this point it is assumed that, once we close our Adb Data
116 // socket, the Adb forwarder command will propagate the closing of
117 // sockets all the way to the host side.
120 listener
->SetAdbDataSocket(socket
.Pass());
122 case command::UNLISTEN
:
123 LOG(INFO
) << "Unmapping port " << port
;
125 LOG(ERROR
) << "No listener found for port " << port
;
126 SendCommand(command::UNLISTEN_ERROR
, port
, socket
.get());
129 DeleteRefCountedValueInMapFromIterator(listener_it
, &listeners_
);
130 SendCommand(command::UNLISTEN_SUCCESS
, port
, socket
.get());
133 // TODO(felipeg): add a KillAllListeners command.
134 LOG(ERROR
) << "Invalid command received. Port: " << port
135 << " Command: " << command
;
140 void DeviceController::DeleteListenerOnError(
141 const base::WeakPtr
<DeviceController
>& device_controller_ptr
,
142 scoped_ptr
<DeviceListener
> device_listener
) {
143 DeviceListener
* const listener
= device_listener
.release();
144 DeviceController
* const controller
= device_controller_ptr
.get();
146 // |listener| was already deleted by the controller that did have its
150 DCHECK(controller
->construction_task_runner_
->RunsTasksOnCurrentThread());
151 bool listener_did_exist
= DeleteRefCountedValueInMap(
152 listener
->listener_port(), &controller
->listeners_
);
153 DCHECK(listener_did_exist
);
154 // Note that |listener| was deleted by DeleteRefCountedValueInMap().
157 } // namespace forwarder