diff options
Diffstat (limited to 'tools/android')
-rw-r--r-- | tools/android/forwarder2/device_controller.cc | 120 | ||||
-rw-r--r-- | tools/android/forwarder2/device_controller.h | 45 | ||||
-rw-r--r-- | tools/android/forwarder2/device_forwarder_main.cc | 60 | ||||
-rw-r--r-- | tools/android/forwarder2/forwarder.gyp | 1 |
4 files changed, 224 insertions, 2 deletions
diff --git a/tools/android/forwarder2/device_controller.cc b/tools/android/forwarder2/device_controller.cc new file mode 100644 index 0000000..e0effb8 --- /dev/null +++ b/tools/android/forwarder2/device_controller.cc @@ -0,0 +1,120 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "tools/android/forwarder2/device_controller.h" + +#include <errno.h> +#include <stdlib.h> + +#include "base/logging.h" +#include "base/memory/scoped_ptr.h" +#include "base/safe_strerror_posix.h" +#include "tools/android/forwarder2/command.h" +#include "tools/android/forwarder2/device_listener.h" +#include "tools/android/forwarder2/socket.h" + +namespace forwarder2 { + +DeviceController::DeviceController(int exit_notifier_fd) + : exit_notifier_fd_(exit_notifier_fd) { + kickstart_adb_socket_.set_exit_notifier_fd(exit_notifier_fd); +} + +DeviceController::~DeviceController() { + KillAllListeners(); + CleanUpDeadListeners(); + CHECK_EQ(0, listeners_.size()); +} + +void DeviceController::CleanUpDeadListeners() { + // Clean up dead listeners. + for (ListenersMap::iterator it(&listeners_); !it.IsAtEnd(); it.Advance()) { + if (!it.GetCurrentValue()->is_alive()) + // Remove deletes the listener. + listeners_.Remove(it.GetCurrentKey()); + } +} + +void DeviceController::KillAllListeners() { + for (ListenersMap::iterator it(&listeners_); !it.IsAtEnd(); it.Advance()) + it.GetCurrentValue()->ForceExit(); + for (ListenersMap::iterator it(&listeners_); !it.IsAtEnd(); it.Advance()) { + it.GetCurrentValue()->Join(); + CHECK(!it.GetCurrentValue()->is_alive()); + } +} + +bool DeviceController::Start(const std::string& adb_unix_socket) { + if (!kickstart_adb_socket_.BindUnix(adb_unix_socket, + true /* abstract */)) { + LOG(ERROR) << "Could not BindAndListen DeviceController socket on port: " + << adb_unix_socket; + return false; + } + while (true) { + CleanUpDeadListeners(); + scoped_ptr<Socket> socket(new Socket); + if (!kickstart_adb_socket_.Accept(socket.get())) { + LOG(ERROR) << "Could not Accept DeviceController socket: " + << safe_strerror(errno); + break; + } + // So that |socket| doesn't block on read if it has notifications. + socket->set_exit_notifier_fd(exit_notifier_fd_); + int port; + command::Type command; + if (!ReadCommand(socket.get(), &port, &command)) { + LOG(ERROR) << "Invalid command received."; + socket->Close(); + continue; + } + DeviceListener* listener = listeners_.Lookup(port); + switch (command) { + case command::LISTEN: { + if (listener != NULL) { + LOG(WARNING) << "Already forwarding port " << port + << ". Attempting to restart the listener.\n"; + listener->ForceExit(); + listener->Join(); + CHECK(!listener->is_alive()); + // Remove deletes the listener object. + listeners_.Remove(port); + } + // Listener object will be deleted by the CleanUpDeadListeners method. + DeviceListener* new_listener = new DeviceListener(socket.Pass(), port); + listeners_.AddWithID(new_listener, port); + new_listener->Start(); + break; + } + case command::DATA_CONNECTION: + if (listener == NULL) { + LOG(ERROR) << "Data Connection command received, but " + << "listener has not been set up yet for port " << port; + // After this point it is assumed that, once we close our Adb Data + // socket, the Adb forwarder command will propagate the closing of + // sockets all the way to the host side. + socket->Close(); + continue; + } else if (!listener->SetAdbDataSocket(socket.Pass())) { + LOG(ERROR) << "Could not set Adb Data Socket for port: " << port; + // Same assumption as above, but in this case the socket is closed + // inside SetAdbDataSocket. + continue; + } + break; + default: + // TODO(felipeg): add a KillAllListeners command. + LOG(ERROR) << "Invalid command received. Port: " << port + << " Command: " << command; + socket->Close(); + continue; + break; + } + } + KillAllListeners(); + CleanUpDeadListeners(); + kickstart_adb_socket_.Close(); +} + +} // namespace forwarder diff --git a/tools/android/forwarder2/device_controller.h b/tools/android/forwarder2/device_controller.h new file mode 100644 index 0000000..213cb8a8 --- /dev/null +++ b/tools/android/forwarder2/device_controller.h @@ -0,0 +1,45 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef TOOLS_ANDROID_FORWARDER2_DEVICE_CONTROLLER_H_ +#define TOOLS_ANDROID_FORWARDER2_DEVICE_CONTROLLER_H_ + +#include <hash_map> +#include <string> + +#include "base/basictypes.h" +#include "base/id_map.h" +#include "base/memory/linked_ptr.h" +#include "tools/android/forwarder2/socket.h" + +namespace forwarder2 { + +class DeviceListener; + +class DeviceController { + public: + explicit DeviceController(int exit_notifier_fd); + ~DeviceController(); + + bool Start(const std::string& adb_unix_socket); + + private: + void KillAllListeners(); + void CleanUpDeadListeners(); + + // Map from Port to DeviceListener objects (owns the pointer). + typedef IDMap<DeviceListener, IDMapOwnPointer> ListenersMap; + + ListenersMap listeners_; + Socket kickstart_adb_socket_; + + // Used to notify the controller to exit. + const int exit_notifier_fd_; + + DISALLOW_COPY_AND_ASSIGN(DeviceController); +}; + +} // namespace forwarder + +#endif // TOOLS_ANDROID_FORWARDER2_DEVICE_CONTROLLER_H_ diff --git a/tools/android/forwarder2/device_forwarder_main.cc b/tools/android/forwarder2/device_forwarder_main.cc index f52450c..69faa29 100644 --- a/tools/android/forwarder2/device_forwarder_main.cc +++ b/tools/android/forwarder2/device_forwarder_main.cc @@ -2,9 +2,65 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> + +#include <string> + +#include "base/command_line.h" +#include "base/stringprintf.h" +#include "tools/android/common/daemon.h" +#include "tools/android/forwarder2/device_controller.h" +#include "tools/android/forwarder2/pipe_notifier.h" + +namespace { + +// Leaky global instance, accessed from the signal handler. +forwarder2::PipeNotifier* g_notifier = NULL; + +// Unix domain socket name for Device Controller. +const char kDefaultAdbSocket[] = "chrome_device_forwarder"; + +void KillHandler(int /* unused */) { + CHECK(g_notifier); + if (!g_notifier->Notify()) + exit(-1); +} + +} // namespace + int main(int argc, char** argv) { - // TODO(felipeg): To be implemented. - // BUG=146502 + printf("Device forwarder to forward connections to the Host machine.\n"); + printf("Like 'adb forward' but in the reverse direction\n"); + + CommandLine command_line(argc, argv); + std::string adb_socket_path = command_line.GetSwitchValueASCII("adb_sock"); + if (adb_socket_path.empty()) { + adb_socket_path = kDefaultAdbSocket; + } + if (tools::HasHelpSwitch(command_line)) { + tools::ShowHelp( + argv[0], + "[--adb_sock=<adb sock>]", + base::StringPrintf( + " <adb sock> is the Abstract Unix Domain Socket path " + " where Adb is configured to forward from." + " Default is %s\n", kDefaultAdbSocket).c_str()); + return 0; + } + if (!tools::HasNoSpawnDaemonSwitch(command_line)) { + tools::SpawnDaemon(0); + } + + g_notifier = new forwarder2::PipeNotifier(); + + signal(SIGTERM, KillHandler); + signal(SIGINT, KillHandler); + CHECK(g_notifier); + forwarder2::DeviceController controller(g_notifier->receiver_fd()); + printf("Starting Device Forwarder.\n"); + controller.Start(adb_socket_path); return 0; } diff --git a/tools/android/forwarder2/forwarder.gyp b/tools/android/forwarder2/forwarder.gyp index b2ab893..b18b4bd 100644 --- a/tools/android/forwarder2/forwarder.gyp +++ b/tools/android/forwarder2/forwarder.gyp @@ -38,6 +38,7 @@ ], 'sources': [ 'command.cc', + 'device_controller.cc', 'device_forwarder_main.cc', 'device_listener.cc', 'forwarder.cc', |