| Index: tools/android/forwarder2/device_forwarder_main.cc
|
| diff --git a/tools/android/forwarder2/device_forwarder_main.cc b/tools/android/forwarder2/device_forwarder_main.cc
|
| index 4a731b20a796e754da7333ecc9fe5ff6601cded5..06c75ed8f4e467ea1fc6f32b536669d670675f8b 100644
|
| --- a/tools/android/forwarder2/device_forwarder_main.cc
|
| +++ b/tools/android/forwarder2/device_forwarder_main.cc
|
| @@ -8,20 +8,32 @@
|
|
|
| #include <string>
|
|
|
| +#include "base/at_exit.h"
|
| +#include "base/bind.h"
|
| #include "base/command_line.h"
|
| +#include "base/compiler_specific.h"
|
| #include "base/logging.h"
|
| +#include "base/string_piece.h"
|
| #include "base/stringprintf.h"
|
| -#include "tools/android/common/daemon.h"
|
| +#include "base/threading/thread.h"
|
| +#include "tools/android/forwarder2/common.h"
|
| +#include "tools/android/forwarder2/daemon.h"
|
| #include "tools/android/forwarder2/device_controller.h"
|
| #include "tools/android/forwarder2/pipe_notifier.h"
|
|
|
| +namespace forwarder2 {
|
| 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";
|
| +const int kBufSize = 256;
|
| +
|
| +const char kPIDFilePath[] = "/data/local/tmp/chrome_device_forwarder_pid";
|
| +const char kDaemonIdentifier[] = "chrome_device_forwarder_daemon";
|
| +
|
| +const char kKillServerCommand[] = "kill-server";
|
| +const char kStartCommand[] = "start";
|
|
|
| void KillHandler(int /* unused */) {
|
| CHECK(g_notifier);
|
| @@ -29,38 +41,141 @@ void KillHandler(int /* unused */) {
|
| exit(1);
|
| }
|
|
|
| -} // namespace
|
| +// Lets the daemon fetch the exit notifier file descriptor.
|
| +int GetExitNotifierFD() {
|
| + DCHECK(g_notifier);
|
| + return g_notifier->receiver_fd();
|
| +}
|
|
|
| -int main(int argc, char** argv) {
|
| - 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;
|
| +class ServerDelegate : public Daemon::ServerDelegate {
|
| + public:
|
| + // Daemon::ServerDelegate:
|
| + virtual void Init() OVERRIDE {
|
| + DCHECK(!g_notifier);
|
| + g_notifier = new forwarder2::PipeNotifier();
|
| + signal(SIGTERM, KillHandler);
|
| + signal(SIGINT, KillHandler);
|
| + controller_thread_.reset(new base::Thread("controller_thread"));
|
| + controller_thread_->Start();
|
| }
|
| - if (!tools::HasNoSpawnDaemonSwitch(command_line))
|
| - tools::SpawnDaemon(0);
|
|
|
| - g_notifier = new forwarder2::PipeNotifier();
|
| + virtual void OnClientConnected(scoped_ptr<Socket> client_socket) OVERRIDE {
|
| + char buf[kBufSize];
|
| + const int bytes_read = client_socket->Read(buf, sizeof(buf));
|
| + if (bytes_read <= 0) {
|
| + if (client_socket->exited())
|
| + return;
|
| + PError("Read()");
|
| + return;
|
| + }
|
| + const std::string adb_socket_path(buf, bytes_read);
|
| + if (adb_socket_path == adb_socket_path_) {
|
| + client_socket->WriteString("OK");
|
| + return;
|
| + }
|
| + if (!adb_socket_path_.empty()) {
|
| + client_socket->WriteString(
|
| + base::StringPrintf(
|
| + "ERROR: Device controller already running (adb_socket_path=%s)",
|
| + adb_socket_path_.c_str()));
|
| + return;
|
| + }
|
| + adb_socket_path_ = adb_socket_path;
|
| + controller_thread_->message_loop()->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&ServerDelegate::StartController, adb_socket_path,
|
| + g_notifier->receiver_fd(), base::Passed(&client_socket)));
|
| + }
|
|
|
| - signal(SIGTERM, KillHandler);
|
| - signal(SIGINT, KillHandler);
|
| - CHECK(g_notifier);
|
| - forwarder2::DeviceController controller(g_notifier->receiver_fd());
|
| - if (!controller.Init(adb_socket_path))
|
| + virtual void OnServerExited() OVERRIDE {}
|
| +
|
| + private:
|
| + static void StartController(const std::string& adb_socket_path,
|
| + int exit_notifier_fd,
|
| + scoped_ptr<Socket> client_socket) {
|
| + forwarder2::DeviceController controller(exit_notifier_fd);
|
| + if (!controller.Init(adb_socket_path)) {
|
| + client_socket->WriteString(
|
| + base::StringPrintf("ERROR: Could not initialize device controller "
|
| + "with ADB socket path: %s",
|
| + adb_socket_path.c_str()));
|
| + return;
|
| + }
|
| + client_socket->WriteString("OK");
|
| + client_socket->Close();
|
| + // Note that the following call is blocking which explains why the device
|
| + // controller has to live on a separate thread (so that the daemon command
|
| + // server is not blocked).
|
| + controller.Start();
|
| + }
|
| +
|
| + base::AtExitManager at_exit_manager_; // Used by base::Thread.
|
| + scoped_ptr<base::Thread> controller_thread_;
|
| + std::string adb_socket_path_;
|
| +};
|
| +
|
| +class ClientDelegate : public Daemon::ClientDelegate {
|
| + public:
|
| + ClientDelegate(const std::string& adb_socket)
|
| + : adb_socket_(adb_socket),
|
| + has_failed_(false) {
|
| + }
|
| +
|
| + bool has_failed() const { return has_failed_; }
|
| +
|
| + // Daemon::ClientDelegate:
|
| + virtual void OnDaemonReady(Socket* daemon_socket) OVERRIDE {
|
| + // Send the adb socket path to the daemon.
|
| + CHECK(daemon_socket->Write(adb_socket_.c_str(),
|
| + adb_socket_.length()));
|
| + char buf[kBufSize];
|
| + const int bytes_read = daemon_socket->Read(
|
| + buf, sizeof(buf) - 1 /* leave space for null terminator */);
|
| + CHECK_GT(bytes_read, 0);
|
| + DCHECK(bytes_read < sizeof(buf));
|
| + buf[bytes_read] = 0;
|
| + base::StringPiece msg(buf, bytes_read);
|
| + if (msg.starts_with("ERROR")) {
|
| + LOG(ERROR) << msg;
|
| + has_failed_ = true;
|
| + return;
|
| + }
|
| + }
|
| +
|
| + private:
|
| + const std::string adb_socket_;
|
| + bool has_failed_;
|
| +};
|
| +
|
| +int RunDeviceForwarder(int argc, char** argv) {
|
| + if (argc != 2) {
|
| + fprintf(stderr,
|
| + "Usage: %s kill-server|<adb_socket>\n"
|
| + " <adb_socket> is the abstract Unix Domain Socket path "
|
| + "where Adb is configured to forward from.\n", argv[0]);
|
| return 1;
|
| - printf("Starting Device Forwarder.\n");
|
| - controller.Start();
|
| - return 0;
|
| + }
|
| + CommandLine::Init(argc, argv); // Needed by logging.
|
| + const char* const command =
|
| + !strcmp(argv[1], kKillServerCommand) ? kKillServerCommand : kStartCommand;
|
| + ClientDelegate client_delegate(argv[1]);
|
| + ServerDelegate daemon_delegate;
|
| + const char kLogFilePath[] = ""; // Log to logcat.
|
| + Daemon daemon(kLogFilePath, kPIDFilePath, kDaemonIdentifier, &client_delegate,
|
| + &daemon_delegate, &GetExitNotifierFD);
|
| +
|
| + if (command == kKillServerCommand)
|
| + return !daemon.Kill();
|
| +
|
| + DCHECK(command == kStartCommand);
|
| + if (!daemon.SpawnIfNeeded())
|
| + return 1;
|
| + return client_delegate.has_failed();
|
| +}
|
| +
|
| +} // namespace
|
| +} // namespace forwarder2
|
| +
|
| +int main(int argc, char** argv) {
|
| + return forwarder2::RunDeviceForwarder(argc, argv);
|
| }
|
|
|