| 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..c6f044291a893936b69f015f3dcaa5959ff011e2 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, | 
| +                   GetExitNotifierFD(), 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); | 
| } | 
|  |