| Index: tools/android/forwarder2/device_controller.cc
|
| diff --git a/tools/android/forwarder2/device_controller.cc b/tools/android/forwarder2/device_controller.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..ca54e2e7f0f7f9b0b1811a786a15cfe19e483b74
|
| --- /dev/null
|
| +++ b/tools/android/forwarder2/device_controller.cc
|
| @@ -0,0 +1,124 @@
|
| +// 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 forwarder {
|
| +
|
| +DeviceController::DeviceController(int notifier_fd)
|
| + : exit_notifier_fd_(notifier_fd) {
|
| + kickstart_adb_socket_.set_notifier_fd(notifier_fd);
|
| +}
|
| +
|
| +DeviceController::~DeviceController() {
|
| + KillAllListeners();
|
| + CleanUpDeadListeners();
|
| + CHECK_EQ(0, listeners_.size());
|
| +}
|
| +
|
| +void DeviceController::CleanUpDeadListeners() {
|
| + // Clean up dead listeners.
|
| + for (ListenersMap::iterator it = listeners_.begin();
|
| + it != listeners_.end();) {
|
| + if (!it->second->is_alive()) {
|
| + ListenersMap::iterator to_erase(it);
|
| + to_erase->second.reset();
|
| + ++it;
|
| + listeners_.erase(to_erase);
|
| + } else {
|
| + ++it;
|
| + }
|
| + }
|
| +}
|
| +
|
| +void DeviceController::KillAllListeners() {
|
| + ListenersMap::iterator it;
|
| + for (it = listeners_.begin(); it != listeners_.end(); ++it) {
|
| + it->second->ForceExit();
|
| + }
|
| + for (it = listeners_.begin(); it != listeners_.end(); ++it) {
|
| + it->second->Join();
|
| + CHECK(!it->second->is_alive());
|
| + }
|
| +}
|
| +
|
| +bool DeviceController::Start(const string& adb_unix_socket) {
|
| + if (!kickstart_adb_socket_.BindUnix(adb_unix_socket,
|
| + /* abstract = */ true)) {
|
| + 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_notifier_fd(exit_notifier_fd_);
|
| + int port;
|
| + command::Type command;
|
| + if (!ReadCommand(socket.get(), &port, &command)) {
|
| + LOG(ERROR) << "Invalid command received.";
|
| + socket->Close();
|
| + continue;
|
| + }
|
| + ListenersMap::iterator listener_it(listeners_.find(port));
|
| + switch (command) {
|
| + case command::LISTEN:
|
| + if (listener_it != listeners_.end()) {
|
| + LOG(WARNING) << "Already forwarding port " << port
|
| + << ". Attempting to restart the listener.\n";
|
| + listener_it->second->ForceExit();
|
| + listener_it->second->Join();
|
| + CHECK(!listener_it->second->is_alive());
|
| + } else {
|
| + // Listener object will be deleted by the CleanUpDeadListeners method.
|
| + DeviceListener* listener = new DeviceListener(socket.Pass(), port);
|
| + listeners_[port].reset(listener);
|
| + listener->Start();
|
| + }
|
| + break;
|
| + case command::DATA_CONNECTION:
|
| + if (listener_it == listeners_.end()) {
|
| + 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_it->second->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.";
|
| + socket->Close();
|
| + continue;
|
| + }
|
| + }
|
| + KillAllListeners();
|
| + CleanUpDeadListeners();
|
| + kickstart_adb_socket_.Close();
|
| +}
|
| +
|
| +} // namespace forwarder
|
|
|