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.
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"
24 namespace forwarder2 {
27 // Leaky global instance, accessed from the signal handler.
28 forwarder2::PipeNotifier* g_notifier = NULL;
30 const int kBufSize = 256;
32 const char kUnixDomainSocketPath[] = "chrome_device_forwarder";
33 const char kDaemonIdentifier[] = "chrome_device_forwarder_daemon";
35 void KillHandler(int /* unused */) {
37 if (!g_notifier->Notify())
41 // Lets the daemon fetch the exit notifier file descriptor.
42 int GetExitNotifierFD() {
44 return g_notifier->receiver_fd();
47 class ServerDelegate : public Daemon::ServerDelegate {
49 ServerDelegate() : initialized_(false) {}
51 virtual ~ServerDelegate() {
52 if (!controller_thread_.get())
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(
60 base::Bind(&ServerDelegate::DeleteControllerOnInternalThread,
61 base::Unretained(this)));
64 void DeleteControllerOnInternalThread() {
66 controller_thread_->message_loop_proxy()->RunsTasksOnCurrentThread());
70 // Daemon::ServerDelegate:
71 virtual void Init() override {
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();
80 virtual void OnClientConnected(scoped_ptr<Socket> client_socket) override {
82 client_socket->WriteString("OK");
85 controller_thread_->message_loop()->PostTask(
87 base::Bind(&ServerDelegate::StartController, base::Unretained(this),
88 GetExitNotifierFD(), base::Passed(&client_socket)));
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));
104 controller_.swap(controller);
105 controller_->Start();
106 client_socket->WriteString("OK");
107 client_socket->Close();
110 scoped_ptr<DeviceController> controller_;
111 scoped_ptr<base::Thread> controller_thread_;
115 class ClientDelegate : public Daemon::ClientDelegate {
117 ClientDelegate() : has_failed_(false) {}
119 bool has_failed() const { return has_failed_; }
121 // Daemon::ClientDelegate:
122 virtual void OnDaemonReady(Socket* daemon_socket) override {
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(static_cast<unsigned int>(bytes_read) < sizeof(buf));
129 base::StringPiece msg(buf, bytes_read);
130 if (msg.starts_with("ERROR")) {
141 int RunDeviceForwarder(int argc, char** argv) {
142 CommandLine::Init(argc, argv); // Needed by logging.
143 const bool kill_server = CommandLine::ForCurrentProcess()->HasSwitch(
145 if ((kill_server && argc != 2) || (!kill_server && argc != 1)) {
146 std::cerr << "Usage: device_forwarder [--kill-server]" << std::endl;
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);
157 return !daemon.Kill();
159 if (!daemon.SpawnIfNeeded())
161 return client_delegate.has_failed();
165 } // namespace forwarder2
167 int main(int argc, char** argv) {
168 return forwarder2::RunDeviceForwarder(argc, argv);