Home | History | Annotate | Download | only in forwarder2
      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.
      4 
      5 #include <signal.h>
      6 #include <stdlib.h>
      7 
      8 #include <iostream>
      9 #include <string>
     10 
     11 #include "base/at_exit.h"
     12 #include "base/bind.h"
     13 #include "base/command_line.h"
     14 #include "base/compiler_specific.h"
     15 #include "base/logging.h"
     16 #include "base/strings/string_piece.h"
     17 #include "base/strings/stringprintf.h"
     18 #include "base/threading/thread.h"
     19 #include "tools/android/forwarder2/common.h"
     20 #include "tools/android/forwarder2/daemon.h"
     21 #include "tools/android/forwarder2/device_controller.h"
     22 #include "tools/android/forwarder2/pipe_notifier.h"
     23 
     24 namespace forwarder2 {
     25 namespace {
     26 
     27 // Leaky global instance, accessed from the signal handler.
     28 forwarder2::PipeNotifier* g_notifier = NULL;
     29 
     30 const int kBufSize = 256;
     31 
     32 const char kUnixDomainSocketPath[] = "chrome_device_forwarder";
     33 const char kDaemonIdentifier[] = "chrome_device_forwarder_daemon";
     34 
     35 void KillHandler(int /* unused */) {
     36   CHECK(g_notifier);
     37   if (!g_notifier->Notify())
     38     exit(1);
     39 }
     40 
     41 // Lets the daemon fetch the exit notifier file descriptor.
     42 int GetExitNotifierFD() {
     43   DCHECK(g_notifier);
     44   return g_notifier->receiver_fd();
     45 }
     46 
     47 class ServerDelegate : public Daemon::ServerDelegate {
     48  public:
     49   ServerDelegate() : initialized_(false) {}
     50 
     51   virtual ~ServerDelegate() {
     52     if (!controller_thread_.get())
     53       return;
     54     // The DeviceController instance, if any, is constructed on the controller
     55     // thread. Make sure that it gets deleted on that same thread. Note that
     56     // DeleteSoon() is not used here since it would imply reading |controller_|
     57     // from the main thread while it's set on the internal thread.
     58     controller_thread_->message_loop_proxy()->PostTask(
     59         FROM_HERE,
     60         base::Bind(&ServerDelegate::DeleteControllerOnInternalThread,
     61                    base::Unretained(this)));
     62   }
     63 
     64   void DeleteControllerOnInternalThread() {
     65     DCHECK(
     66         controller_thread_->message_loop_proxy()->RunsTasksOnCurrentThread());
     67     controller_.reset();
     68   }
     69 
     70   // Daemon::ServerDelegate:
     71   virtual void Init() OVERRIDE {
     72     DCHECK(!g_notifier);
     73     g_notifier = new forwarder2::PipeNotifier();
     74     signal(SIGTERM, KillHandler);
     75     signal(SIGINT, KillHandler);
     76     controller_thread_.reset(new base::Thread("controller_thread"));
     77     controller_thread_->Start();
     78   }
     79 
     80   virtual void OnClientConnected(scoped_ptr<Socket> client_socket) OVERRIDE {
     81     if (initialized_) {
     82       client_socket->WriteString("OK");
     83       return;
     84     }
     85     controller_thread_->message_loop()->PostTask(
     86         FROM_HERE,
     87         base::Bind(&ServerDelegate::StartController, base::Unretained(this),
     88                    GetExitNotifierFD(), base::Passed(&client_socket)));
     89     initialized_ = true;
     90   }
     91 
     92  private:
     93   void StartController(int exit_notifier_fd, scoped_ptr<Socket> client_socket) {
     94     DCHECK(!controller_.get());
     95     scoped_ptr<DeviceController> controller(
     96         DeviceController::Create(kUnixDomainSocketPath, exit_notifier_fd));
     97     if (!controller.get()) {
     98       client_socket->WriteString(
     99           base::StringPrintf("ERROR: Could not initialize device controller "
    100                              "with ADB socket path: %s",
    101                              kUnixDomainSocketPath));
    102       return;
    103     }
    104     controller_.swap(controller);
    105     controller_->Start();
    106     client_socket->WriteString("OK");
    107     client_socket->Close();
    108   }
    109 
    110   scoped_ptr<DeviceController> controller_;
    111   scoped_ptr<base::Thread> controller_thread_;
    112   bool initialized_;
    113 };
    114 
    115 class ClientDelegate : public Daemon::ClientDelegate {
    116  public:
    117   ClientDelegate() : has_failed_(false) {}
    118 
    119   bool has_failed() const { return has_failed_; }
    120 
    121   // Daemon::ClientDelegate:
    122   virtual void OnDaemonReady(Socket* daemon_socket) OVERRIDE {
    123     char buf[kBufSize];
    124     const int bytes_read = daemon_socket->Read(
    125         buf, sizeof(buf) - 1 /* leave space for null terminator */);
    126     CHECK_GT(bytes_read, 0);
    127     DCHECK(bytes_read < sizeof(buf));
    128     buf[bytes_read] = 0;
    129     base::StringPiece msg(buf, bytes_read);
    130     if (msg.starts_with("ERROR")) {
    131       LOG(ERROR) << msg;
    132       has_failed_ = true;
    133       return;
    134     }
    135   }
    136 
    137  private:
    138   bool has_failed_;
    139 };
    140 
    141 int RunDeviceForwarder(int argc, char** argv) {
    142   CommandLine::Init(argc, argv);  // Needed by logging.
    143   const bool kill_server = CommandLine::ForCurrentProcess()->HasSwitch(
    144       "kill-server");
    145   if ((kill_server && argc != 2) || (!kill_server && argc != 1)) {
    146     std::cerr << "Usage: device_forwarder [--kill-server]" << std::endl;
    147     return 1;
    148   }
    149   base::AtExitManager at_exit_manager;  // Used by base::Thread.
    150   ClientDelegate client_delegate;
    151   ServerDelegate daemon_delegate;
    152   const char kLogFilePath[] = "";  // Log to logcat.
    153   Daemon daemon(kLogFilePath, kDaemonIdentifier, &client_delegate,
    154                 &daemon_delegate, &GetExitNotifierFD);
    155 
    156   if (kill_server)
    157     return !daemon.Kill();
    158 
    159   if (!daemon.SpawnIfNeeded())
    160     return 1;
    161   return client_delegate.has_failed();
    162 }
    163 
    164 }  // namespace
    165 }  // namespace forwarder2
    166 
    167 int main(int argc, char** argv) {
    168   return forwarder2::RunDeviceForwarder(argc, argv);
    169 }
    170