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.
18 #include "base/at_exit.h"
19 #include "base/basictypes.h"
20 #include "base/bind.h"
21 #include "base/command_line.h"
22 #include "base/compiler_specific.h"
23 #include "base/containers/hash_tables.h"
24 #include "base/files/file_path.h"
25 #include "base/files/file_util.h"
26 #include "base/logging.h"
27 #include "base/memory/linked_ptr.h"
28 #include "base/memory/scoped_vector.h"
29 #include "base/memory/weak_ptr.h"
30 #include "base/pickle.h"
31 #include "base/safe_strerror_posix.h"
32 #include "base/strings/string_number_conversions.h"
33 #include "base/strings/string_piece.h"
34 #include "base/strings/string_split.h"
35 #include "base/strings/string_util.h"
36 #include "base/strings/stringprintf.h"
37 #include "base/task_runner.h"
38 #include "base/threading/thread.h"
39 #include "tools/android/forwarder2/common.h"
40 #include "tools/android/forwarder2/daemon.h"
41 #include "tools/android/forwarder2/host_controller.h"
42 #include "tools/android/forwarder2/pipe_notifier.h"
43 #include "tools/android/forwarder2/socket.h"
44 #include "tools/android/forwarder2/util.h"
46 namespace forwarder2 {
49 const char kLogFilePath[] = "/tmp/host_forwarder_log";
50 const char kDaemonIdentifier[] = "chrome_host_forwarder_daemon";
52 const char kKillServerCommand[] = "kill-server";
53 const char kForwardCommand[] = "forward";
55 const int kBufSize = 256;
57 // Needs to be global to be able to be accessed from the signal handler.
58 PipeNotifier* g_notifier = NULL;
60 // Lets the daemon fetch the exit notifier file descriptor.
61 int GetExitNotifierFD() {
63 return g_notifier->receiver_fd();
66 void KillHandler(int signal_number) {
68 if (signal_number != SIGTERM && signal_number != SIGINT) {
69 snprintf(buf, sizeof(buf), "Ignoring unexpected signal %d.", signal_number);
70 SIGNAL_SAFE_LOG(WARNING, buf);
73 snprintf(buf, sizeof(buf), "Received signal %d.", signal_number);
74 SIGNAL_SAFE_LOG(WARNING, buf);
75 static int s_kill_handler_count = 0;
77 // If for some reason the forwarder get stuck in any socket waiting forever,
78 // we can send a SIGKILL or SIGINT three times to force it die
79 // (non-nicely). This is useful when debugging.
80 ++s_kill_handler_count;
81 if (!g_notifier->Notify() || s_kill_handler_count > 2)
85 // Manages HostController instances. There is one HostController instance for
86 // each connection being forwarded. Note that forwarding can happen with many
87 // devices (identified with a serial id).
88 class HostControllersManager {
90 HostControllersManager()
91 : weak_ptr_factory_(this),
92 controllers_(new HostControllerMap()),
96 ~HostControllersManager() {
99 // Delete the controllers on the thread they were created on.
100 thread_->message_loop_proxy()->DeleteSoon(
101 FROM_HERE, controllers_.release());
104 void HandleRequest(const std::string& device_serial,
107 scoped_ptr<Socket> client_socket) {
108 // Lazy initialize so that the CLI process doesn't get this thread created.
110 thread_->message_loop_proxy()->PostTask(
113 &HostControllersManager::HandleRequestOnInternalThread,
114 base::Unretained(this), device_serial, device_port, host_port,
115 base::Passed(&client_socket)));
118 bool has_failed() const { return has_failed_; }
121 typedef base::hash_map<
122 std::string, linked_ptr<HostController> > HostControllerMap;
124 static std::string MakeHostControllerMapKey(int adb_port, int device_port) {
125 return base::StringPrintf("%d:%d", adb_port, device_port);
131 at_exit_manager_.reset(new base::AtExitManager());
132 thread_.reset(new base::Thread("HostControllersManagerThread"));
136 // Invoked when a HostController instance reports an error (e.g. due to a
137 // device connectivity issue). Note that this could be called after the
138 // controller manager was destroyed which is why a weak pointer is used.
139 static void DeleteHostController(
140 const base::WeakPtr<HostControllersManager>& manager_ptr,
141 scoped_ptr<HostController> host_controller) {
142 HostController* const controller = host_controller.release();
143 HostControllersManager* const manager = manager_ptr.get();
145 // Note that |controller| is not leaked in this case since the host
146 // controllers manager owns the controllers. If the manager was deleted
147 // then all the controllers (including |controller|) were also deleted.
150 DCHECK(manager->thread_->message_loop_proxy()->RunsTasksOnCurrentThread());
151 // Note that this will delete |controller| which is owned by the map.
152 DeleteRefCountedValueInMap(
153 MakeHostControllerMapKey(
154 controller->adb_port(), controller->device_port()),
155 manager->controllers_.get());
158 void HandleRequestOnInternalThread(const std::string& device_serial,
161 scoped_ptr<Socket> client_socket) {
162 const int adb_port = GetAdbPortForDevice(device_serial);
165 "ERROR: could not get adb port for device. You might need to add "
166 "'adb' to your PATH or provide the device serial id.",
167 client_socket.get());
170 if (device_port < 0) {
171 // Remove the previously created host controller.
172 const std::string controller_key = MakeHostControllerMapKey(
173 adb_port, -device_port);
174 const bool controller_did_exist = DeleteRefCountedValueInMap(
175 controller_key, controllers_.get());
177 !controller_did_exist ? "ERROR: could not unmap port" : "OK",
178 client_socket.get());
180 RemoveAdbPortForDeviceIfNeeded(device_serial);
184 SendMessage("ERROR: missing host port", client_socket.get());
187 const bool use_dynamic_port_allocation = device_port == 0;
188 if (!use_dynamic_port_allocation) {
189 const std::string controller_key = MakeHostControllerMapKey(
190 adb_port, device_port);
191 if (controllers_->find(controller_key) != controllers_->end()) {
192 LOG(INFO) << "Already forwarding device port " << device_port
193 << " to host port " << host_port;
194 SendMessage(base::StringPrintf("%d:%d", device_port, host_port),
195 client_socket.get());
199 // Create a new host controller.
200 scoped_ptr<HostController> host_controller(
201 HostController::Create(
202 device_port, host_port, adb_port, GetExitNotifierFD(),
203 base::Bind(&HostControllersManager::DeleteHostController,
204 weak_ptr_factory_.GetWeakPtr())));
205 if (!host_controller.get()) {
207 SendMessage("ERROR: Connection to device failed.", client_socket.get());
210 // Get the current allocated port.
211 device_port = host_controller->device_port();
212 LOG(INFO) << "Forwarding device port " << device_port << " to host port "
214 const std::string msg = base::StringPrintf("%d:%d", device_port, host_port);
215 if (!SendMessage(msg, client_socket.get()))
217 host_controller->Start();
218 controllers_->insert(
219 std::make_pair(MakeHostControllerMapKey(adb_port, device_port),
220 linked_ptr<HostController>(host_controller.release())));
223 void RemoveAdbPortForDeviceIfNeeded(const std::string& device_serial) {
224 base::hash_map<std::string, int>::const_iterator it =
225 device_serial_to_adb_port_map_.find(device_serial);
226 if (it == device_serial_to_adb_port_map_.end())
229 int port = it->second;
230 const std::string prefix = base::StringPrintf("%d:", port);
231 for (HostControllerMap::const_iterator others = controllers_->begin();
232 others != controllers_->end(); ++others) {
233 if (others->first.find(prefix) == 0U)
236 // No other port is being forwarded to this device:
237 // - Remove it from our internal serial -> adb port map.
238 // - Remove from "adb forward" command.
239 LOG(INFO) << "Device " << device_serial << " has no more ports.";
240 device_serial_to_adb_port_map_.erase(device_serial);
241 const std::string serial_part = device_serial.empty() ?
242 std::string() : std::string("-s ") + device_serial;
243 const std::string command = base::StringPrintf(
244 "adb %s forward --remove tcp:%d",
247 const int ret = system(command.c_str());
248 LOG(INFO) << command << " ret: " << ret;
249 // Wait for the socket to be fully unmapped.
250 const std::string port_mapped_cmd = base::StringPrintf(
253 const int poll_interval_us = 500 * 1000;
256 const int port_unmapped = system(port_mapped_cmd.c_str());
257 LOG(INFO) << "Device " << device_serial << " port " << port << " unmap "
262 usleep(poll_interval_us);
266 int GetAdbPortForDevice(const std::string& device_serial) {
267 base::hash_map<std::string, int>::const_iterator it =
268 device_serial_to_adb_port_map_.find(device_serial);
269 if (it != device_serial_to_adb_port_map_.end())
272 CHECK(bind_socket.BindTcp("127.0.0.1", 0));
273 const int port = bind_socket.GetPort();
275 const std::string serial_part = device_serial.empty() ?
276 std::string() : std::string("-s ") + device_serial;
277 const std::string command = base::StringPrintf(
278 "adb %s forward tcp:%d localabstract:chrome_device_forwarder",
281 LOG(INFO) << command;
282 const int ret = system(command.c_str());
283 if (ret < 0 || !WIFEXITED(ret) || WEXITSTATUS(ret) != 0)
285 device_serial_to_adb_port_map_[device_serial] = port;
289 bool SendMessage(const std::string& msg, Socket* client_socket) {
290 bool result = client_socket->WriteString(msg);
297 base::WeakPtrFactory<HostControllersManager> weak_ptr_factory_;
298 base::hash_map<std::string, int> device_serial_to_adb_port_map_;
299 scoped_ptr<HostControllerMap> controllers_;
301 scoped_ptr<base::AtExitManager> at_exit_manager_; // Needed by base::Thread.
302 scoped_ptr<base::Thread> thread_;
305 class ServerDelegate : public Daemon::ServerDelegate {
307 ServerDelegate() : has_failed_(false) {}
309 bool has_failed() const {
310 return has_failed_ || controllers_manager_.has_failed();
313 // Daemon::ServerDelegate:
314 virtual void Init() OVERRIDE {
315 LOG(INFO) << "Starting host process daemon (pid=" << getpid() << ")";
317 g_notifier = new PipeNotifier();
318 signal(SIGTERM, KillHandler);
319 signal(SIGINT, KillHandler);
322 virtual void OnClientConnected(scoped_ptr<Socket> client_socket) OVERRIDE {
324 const int bytes_read = client_socket->Read(buf, sizeof(buf));
325 if (bytes_read <= 0) {
326 if (client_socket->DidReceiveEvent())
332 const Pickle command_pickle(buf, bytes_read);
333 PickleIterator pickle_it(command_pickle);
334 std::string device_serial;
335 CHECK(pickle_it.ReadString(&device_serial));
337 if (!pickle_it.ReadInt(&device_port)) {
338 client_socket->WriteString("ERROR: missing device port");
342 if (!pickle_it.ReadInt(&host_port))
344 controllers_manager_.HandleRequest(
345 device_serial, device_port, host_port, client_socket.Pass());
350 HostControllersManager controllers_manager_;
352 DISALLOW_COPY_AND_ASSIGN(ServerDelegate);
355 class ClientDelegate : public Daemon::ClientDelegate {
357 ClientDelegate(const Pickle& command_pickle)
358 : command_pickle_(command_pickle),
362 bool has_failed() const { return has_failed_; }
364 // Daemon::ClientDelegate:
365 virtual void OnDaemonReady(Socket* daemon_socket) OVERRIDE {
366 // Send the forward command to the daemon.
367 CHECK_EQ(command_pickle_.size(),
368 daemon_socket->WriteNumBytes(command_pickle_.data(),
369 command_pickle_.size()));
371 const int bytes_read = daemon_socket->Read(
372 buf, sizeof(buf) - 1 /* leave space for null terminator */);
373 CHECK_GT(bytes_read, 0);
374 DCHECK(bytes_read < sizeof(buf));
376 base::StringPiece msg(buf, bytes_read);
377 if (msg.starts_with("ERROR")) {
386 const Pickle command_pickle_;
390 void ExitWithUsage() {
391 std::cerr << "Usage: host_forwarder [options]\n\n"
393 " --serial-id=[0-9A-Z]{16}]\n"
394 " --map DEVICE_PORT HOST_PORT\n"
395 " --unmap DEVICE_PORT\n"
400 int PortToInt(const std::string& s) {
402 // Note that 0 is a valid port (used for dynamic port allocation).
403 if (!base::StringToInt(s, &value) || value < 0 ||
404 value > std::numeric_limits<uint16>::max()) {
405 LOG(ERROR) << "Could not convert string " << s << " to port";
411 int RunHostForwarder(int argc, char** argv) {
412 CommandLine::Init(argc, argv);
413 const CommandLine& cmd_line = *CommandLine::ForCurrentProcess();
414 bool kill_server = false;
418 cmd_line.HasSwitch("serial-id") ?
419 cmd_line.GetSwitchValueASCII("serial-id") : std::string());
421 const std::vector<std::string> args = cmd_line.GetArgs();
422 if (cmd_line.HasSwitch("kill-server")) {
424 } else if (cmd_line.HasSwitch("unmap")) {
425 if (args.size() != 1)
427 // Note the minus sign below.
428 pickle.WriteInt(-PortToInt(args[0]));
429 } else if (cmd_line.HasSwitch("map")) {
430 if (args.size() != 2)
432 pickle.WriteInt(PortToInt(args[0]));
433 pickle.WriteInt(PortToInt(args[1]));
438 if (kill_server && args.size() > 0)
441 ClientDelegate client_delegate(pickle);
442 ServerDelegate daemon_delegate;
444 kLogFilePath, kDaemonIdentifier, &client_delegate, &daemon_delegate,
448 return !daemon.Kill();
449 if (!daemon.SpawnIfNeeded())
452 return client_delegate.has_failed() || daemon_delegate.has_failed();
456 } // namespace forwarder2
458 int main(int argc, char** argv) {
459 return forwarder2::RunHostForwarder(argc, argv);