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