Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / tools / android / forwarder2 / device_forwarder_main.cc
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(static_cast<unsigned int>(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 }