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
);