Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3)

Side by Side Diff: tools/android/forwarder2/device_controller.cc

Issue 19478003: Remove Thread wrapper class in forwarder2. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Address Digit's comments Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "tools/android/forwarder2/device_controller.h" 5 #include "tools/android/forwarder2/device_controller.h"
6 6
7 #include <errno.h> 7 #include <utility>
8 #include <stdlib.h>
9 8
9 #include "base/bind.h"
10 #include "base/bind_helpers.h"
10 #include "base/logging.h" 11 #include "base/logging.h"
11 #include "base/memory/scoped_ptr.h" 12 #include "base/memory/scoped_ptr.h"
12 #include "base/safe_strerror_posix.h" 13 #include "base/message_loop/message_loop_proxy.h"
14 #include "base/single_thread_task_runner.h"
13 #include "tools/android/forwarder2/command.h" 15 #include "tools/android/forwarder2/command.h"
14 #include "tools/android/forwarder2/device_listener.h" 16 #include "tools/android/forwarder2/device_listener.h"
15 #include "tools/android/forwarder2/socket.h" 17 #include "tools/android/forwarder2/socket.h"
16 18
17 namespace forwarder2 { 19 namespace forwarder2 {
18 20
19 DeviceController::DeviceController(int exit_notifier_fd) 21 // static
20 : exit_notifier_fd_(exit_notifier_fd) { 22 scoped_ptr<DeviceController> DeviceController::Create(
21 kickstart_adb_socket_.AddEventFd(exit_notifier_fd); 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();
22 } 36 }
23 37
24 DeviceController::~DeviceController() { 38 DeviceController::~DeviceController() {
25 KillAllListeners(); 39 DCHECK(construction_task_runner_->RunsTasksOnCurrentThread());
26 CleanUpDeadListeners();
27 CHECK_EQ(0, listeners_.size());
28 } 40 }
29 41
30 void DeviceController::CleanUpDeadListeners() { 42 void DeviceController::Start() {
31 // Clean up dead listeners. 43 AcceptHostCommandSoon();
32 for (ListenersMap::iterator it(&listeners_); !it.IsAtEnd(); it.Advance()) { 44 }
33 if (!it.GetCurrentValue()->is_alive()) 45
34 // Remove deletes the listener. 46 DeviceController::DeviceController(scoped_ptr<Socket> host_socket,
35 listeners_.Remove(it.GetCurrentKey()); 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;
36 } 133 }
37 } 134 }
38 135
39 void DeviceController::KillAllListeners() { 136 // static
40 for (ListenersMap::iterator it(&listeners_); !it.IsAtEnd(); it.Advance()) 137 void DeviceController::DeleteListener(
41 it.GetCurrentValue()->ForceExit(); 138 const base::WeakPtr<DeviceController>& device_controller_ptr,
42 for (ListenersMap::iterator it(&listeners_); !it.IsAtEnd(); it.Advance()) { 139 int listener_port) {
43 it.GetCurrentValue()->Join(); 140 DeviceController* const controller = device_controller_ptr.get();
44 CHECK(!it.GetCurrentValue()->is_alive()); 141 if (!controller)
45 } 142 return;
46 } 143 DCHECK(controller->construction_task_runner_->RunsTasksOnCurrentThread());
47 144 const ListenersMap::iterator listener_it = controller->listeners_.find(
48 bool DeviceController::Init(const std::string& adb_unix_socket) { 145 listener_port);
49 if (!kickstart_adb_socket_.BindUnix(adb_unix_socket)) { 146 if (listener_it == controller->listeners_.end())
50 LOG(ERROR) << "Could not BindAndListen DeviceController socket on port " 147 return;
51 << adb_unix_socket << ": " << safe_strerror(errno); 148 const linked_ptr<DeviceListener> listener = listener_it->second;
52 return false; 149 // Note that the listener is removed from the map before it gets destroyed in
53 } 150 // case its destructor would access the map.
54 LOG(INFO) << "Listening on Unix Domain Socket " << adb_unix_socket; 151 controller->listeners_.erase(listener_it);
55 return true;
56 }
57
58 void DeviceController::Start() {
59 while (true) {
60 CleanUpDeadListeners();
61 scoped_ptr<Socket> socket(new Socket);
62 if (!kickstart_adb_socket_.Accept(socket.get())) {
63 if (!kickstart_adb_socket_.DidReceiveEvent()) {
64 LOG(ERROR) << "Could not Accept DeviceController socket: "
65 << safe_strerror(errno);
66 } else {
67 LOG(INFO) << "Received exit notification";
68 }
69 break;
70 }
71 // So that |socket| doesn't block on read if it has notifications.
72 socket->AddEventFd(exit_notifier_fd_);
73 int port;
74 command::Type command;
75 if (!ReadCommand(socket.get(), &port, &command)) {
76 LOG(ERROR) << "Invalid command received.";
77 continue;
78 }
79 DeviceListener* listener = listeners_.Lookup(port);
80 switch (command) {
81 case command::LISTEN: {
82 if (listener != NULL) {
83 LOG(WARNING) << "Already forwarding port " << port
84 << ". Attempting to restart the listener.\n";
85 listener->ForceExit();
86 listener->Join();
87 CHECK(!listener->is_alive());
88 // Remove deletes the listener object.
89 listeners_.Remove(port);
90 }
91 scoped_ptr<DeviceListener> new_listener(
92 new DeviceListener(socket.Pass(), port));
93 if (!new_listener->BindListenerSocket())
94 continue;
95 new_listener->Start();
96 // |port| can be zero, to allow dynamically allocated port, so instead,
97 // we call DeviceListener::listener_port() to retrieve the currently
98 // allocated port to this new listener, which has been set by the
99 // BindListenerSocket() method in case of success.
100 const int listener_port = new_listener->listener_port();
101 // |new_listener| is now owned by listeners_ map.
102 listeners_.AddWithID(new_listener.release(), listener_port);
103 LOG(INFO) << "Forwarding device port " << listener_port << " to host.";
104 break;
105 }
106 case command::DATA_CONNECTION:
107 if (listener == NULL) {
108 LOG(ERROR) << "Data Connection command received, but "
109 << "listener has not been set up yet for port " << port;
110 // After this point it is assumed that, once we close our Adb Data
111 // socket, the Adb forwarder command will propagate the closing of
112 // sockets all the way to the host side.
113 continue;
114 } else if (!listener->SetAdbDataSocket(socket.Pass())) {
115 LOG(ERROR) << "Could not set Adb Data Socket for port: " << port;
116 // Same assumption as above, but in this case the socket is closed
117 // inside SetAdbDataSocket.
118 continue;
119 }
120 break;
121 case command::UNMAP_PORT:
122 if (!listener) {
123 SendCommand(command::UNMAP_PORT_ERROR, port, socket.get());
124 break;
125 }
126 listener->ForceExit();
127 listener->Join();
128 CHECK(!listener->is_alive());
129 listeners_.Remove(port);
130 SendCommand(command::UNMAP_PORT_SUCCESS, port, socket.get());
131 break;
132 default:
133 // TODO(felipeg): add a KillAllListeners command.
134 LOG(ERROR) << "Invalid command received. Port: " << port
135 << " Command: " << command;
136 }
137 }
138 KillAllListeners();
139 CleanUpDeadListeners();
140 } 152 }
141 153
142 } // namespace forwarder 154 } // namespace forwarder
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698