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
24namespace forwarder2 {
25namespace {
26
27// Leaky global instance, accessed from the signal handler.
28forwarder2::PipeNotifier* g_notifier = NULL;
29
30const int kBufSize = 256;
31
32const char kUnixDomainSocketPath[] = "chrome_device_forwarder";
33const char kDaemonIdentifier[] = "chrome_device_forwarder_daemon";
34
35void 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.
42int GetExitNotifierFD() {
43  DCHECK(g_notifier);
44  return g_notifier->receiver_fd();
45}
46
47class 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
115class 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
141int 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
167int main(int argc, char** argv) {
168  return forwarder2::RunDeviceForwarder(argc, argv);
169}
170