Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / android / dev_tools_server.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 "chrome/browser/android/dev_tools_server.h"
6
7 #include <pwd.h>
8 #include <cstring>
9
10 #include "base/android/jni_string.h"
11 #include "base/basictypes.h"
12 #include "base/bind.h"
13 #include "base/callback.h"
14 #include "base/command_line.h"
15 #include "base/compiler_specific.h"
16 #include "base/files/file_path.h"
17 #include "base/logging.h"
18 #include "base/strings/string_number_conversions.h"
19 #include "base/strings/stringprintf.h"
20 #include "base/strings/utf_string_conversions.h"
21 #include "chrome/browser/android/tab_android.h"
22 #include "chrome/browser/browser_process.h"
23 #include "chrome/browser/history/top_sites.h"
24 #include "chrome/browser/profiles/profile_manager.h"
25 #include "chrome/browser/ui/android/tab_model/tab_model.h"
26 #include "chrome/browser/ui/android/tab_model/tab_model_list.h"
27 #include "content/public/browser/android/devtools_auth.h"
28 #include "content/public/browser/browser_thread.h"
29 #include "content/public/browser/devtools_agent_host.h"
30 #include "content/public/browser/devtools_http_handler.h"
31 #include "content/public/browser/devtools_http_handler_delegate.h"
32 #include "content/public/browser/devtools_target.h"
33 #include "content/public/browser/favicon_status.h"
34 #include "content/public/browser/navigation_entry.h"
35 #include "content/public/browser/render_view_host.h"
36 #include "content/public/browser/web_contents.h"
37 #include "content/public/browser/web_contents_delegate.h"
38 #include "content/public/common/content_switches.h"
39 #include "content/public/common/url_constants.h"
40 #include "content/public/common/user_agent.h"
41 #include "grit/browser_resources.h"
42 #include "jni/DevToolsServer_jni.h"
43 #include "net/base/net_errors.h"
44 #include "net/socket/unix_domain_listen_socket_posix.h"
45 #include "net/socket/unix_domain_server_socket_posix.h"
46 #include "net/url_request/url_request_context_getter.h"
47 #include "ui/base/resource/resource_bundle.h"
48
49 using content::DevToolsAgentHost;
50 using content::RenderViewHost;
51 using content::WebContents;
52
53 namespace {
54
55 // TL;DR: Do not change this string.
56 //
57 // Desktop Chrome relies on this format to identify debuggable apps on Android
58 // (see the code under chrome/browser/devtools/device).
59 // If this string ever changes it would not be sufficient to change the
60 // corresponding string on the client side. Since debugging an older version of
61 // Chrome for Android from a newer version of desktop Chrome is a very common
62 // scenario, the client code will have to be modified to recognize both the old
63 // and the new format.
64 const char kDevToolsChannelNameFormat[] = "%s_devtools_remote";
65
66 const char kFrontEndURL[] =
67     "http://chrome-devtools-frontend.appspot.com/serve_rev/%s/devtools.html";
68 const char kTetheringSocketName[] = "chrome_devtools_tethering_%d_%d";
69
70 bool AuthorizeSocketAccessWithDebugPermission(
71     const net::UnixDomainServerSocket::Credentials& credentials) {
72   JNIEnv* env = base::android::AttachCurrentThread();
73   return Java_DevToolsServer_checkDebugPermission(
74       env, base::android::GetApplicationContext(),
75       credentials.process_id, credentials.user_id) ||
76       content::CanUserConnectToDevTools(credentials);
77 }
78
79 // Delegate implementation for the devtools http handler on android. A new
80 // instance of this gets created each time devtools is enabled.
81 class DevToolsServerDelegate : public content::DevToolsHttpHandlerDelegate {
82  public:
83   explicit DevToolsServerDelegate(
84       const net::UnixDomainServerSocket::AuthCallback& auth_callback)
85       : last_tethering_socket_(0),
86         auth_callback_(auth_callback) {
87   }
88
89   virtual std::string GetDiscoveryPageHTML() override {
90     // TopSites updates itself after a delay. Ask TopSites to update itself
91     // when we're about to show the remote debugging landing page.
92     content::BrowserThread::PostTask(
93         content::BrowserThread::UI,
94         FROM_HERE,
95         base::Bind(&DevToolsServerDelegate::PopulatePageThumbnails));
96     return ResourceBundle::GetSharedInstance().GetRawDataResource(
97         IDR_DEVTOOLS_DISCOVERY_PAGE_HTML).as_string();
98   }
99
100   virtual bool BundlesFrontendResources() override {
101     return false;
102   }
103
104   virtual base::FilePath GetDebugFrontendDir() override {
105     return base::FilePath();
106   }
107
108   virtual scoped_ptr<net::StreamListenSocket> CreateSocketForTethering(
109       net::StreamListenSocket::Delegate* delegate,
110       std::string* name) override {
111     *name = base::StringPrintf(
112         kTetheringSocketName, getpid(), ++last_tethering_socket_);
113     return net::deprecated::UnixDomainListenSocket::
114         CreateAndListenWithAbstractNamespace(
115             *name, "", delegate, auth_callback_);
116   }
117
118  private:
119   static void PopulatePageThumbnails() {
120     Profile* profile =
121         ProfileManager::GetLastUsedProfile()->GetOriginalProfile();
122     history::TopSites* top_sites = profile->GetTopSites();
123     if (top_sites)
124       top_sites->SyncWithHistory();
125   }
126
127   int last_tethering_socket_;
128   const net::UnixDomainServerSocket::AuthCallback auth_callback_;
129
130   DISALLOW_COPY_AND_ASSIGN(DevToolsServerDelegate);
131 };
132
133 // Factory for UnixDomainServerSocket. It tries a fallback socket when
134 // original socket doesn't work.
135 class UnixDomainServerSocketFactory
136     : public content::DevToolsHttpHandler::ServerSocketFactory {
137  public:
138   UnixDomainServerSocketFactory(
139       const std::string& socket_name,
140       const net::UnixDomainServerSocket::AuthCallback& auth_callback)
141       : content::DevToolsHttpHandler::ServerSocketFactory(socket_name, 0, 1),
142         auth_callback_(auth_callback) {
143   }
144
145  private:
146   // content::DevToolsHttpHandler::ServerSocketFactory.
147   virtual scoped_ptr<net::ServerSocket> Create() const override {
148     return scoped_ptr<net::ServerSocket>(
149         new net::UnixDomainServerSocket(auth_callback_,
150                                         true /* use_abstract_namespace */));
151   }
152
153   virtual scoped_ptr<net::ServerSocket> CreateAndListen() const override {
154     scoped_ptr<net::ServerSocket> socket = Create();
155     if (!socket)
156       return scoped_ptr<net::ServerSocket>();
157
158     if (socket->ListenWithAddressAndPort(address_, port_, backlog_) == net::OK)
159       return socket.Pass();
160
161     // Try a fallback socket name.
162     const std::string fallback_address(
163         base::StringPrintf("%s_%d", address_.c_str(), getpid()));
164     if (socket->ListenWithAddressAndPort(fallback_address, port_, backlog_)
165         == net::OK)
166       return socket.Pass();
167
168     return scoped_ptr<net::ServerSocket>();
169   }
170
171   const net::UnixDomainServerSocket::AuthCallback auth_callback_;
172
173   DISALLOW_COPY_AND_ASSIGN(UnixDomainServerSocketFactory);
174 };
175
176 }  // namespace
177
178 DevToolsServer::DevToolsServer(const std::string& socket_name_prefix)
179     : socket_name_(base::StringPrintf(kDevToolsChannelNameFormat,
180                                       socket_name_prefix.c_str())),
181       protocol_handler_(NULL) {
182   // Override the socket name if one is specified on the command line.
183   const CommandLine& command_line = *CommandLine::ForCurrentProcess();
184   if (command_line.HasSwitch(switches::kRemoteDebuggingSocketName)) {
185     socket_name_ = command_line.GetSwitchValueASCII(
186         switches::kRemoteDebuggingSocketName);
187   }
188 }
189
190 DevToolsServer::~DevToolsServer() {
191   Stop();
192 }
193
194 void DevToolsServer::Start(bool allow_debug_permission) {
195   if (protocol_handler_)
196     return;
197
198   net::UnixDomainServerSocket::AuthCallback auth_callback =
199       allow_debug_permission ?
200           base::Bind(&AuthorizeSocketAccessWithDebugPermission) :
201           base::Bind(&content::CanUserConnectToDevTools);
202   scoped_ptr<content::DevToolsHttpHandler::ServerSocketFactory> factory(
203       new UnixDomainServerSocketFactory(socket_name_, auth_callback));
204   protocol_handler_ = content::DevToolsHttpHandler::Start(
205       factory.Pass(),
206       base::StringPrintf(kFrontEndURL, content::GetWebKitRevision().c_str()),
207       new DevToolsServerDelegate(auth_callback),
208       base::FilePath());
209 }
210
211 void DevToolsServer::Stop() {
212   if (!protocol_handler_)
213     return;
214   // Note that the call to Stop() below takes care of |protocol_handler_|
215   // deletion.
216   protocol_handler_->Stop();
217   protocol_handler_ = NULL;
218 }
219
220 bool DevToolsServer::IsStarted() const {
221   return protocol_handler_;
222 }
223
224 bool RegisterDevToolsServer(JNIEnv* env) {
225   return RegisterNativesImpl(env);
226 }
227
228 static jlong InitRemoteDebugging(JNIEnv* env,
229                                 jobject obj,
230                                 jstring socket_name_prefix) {
231   DevToolsServer* server = new DevToolsServer(
232       base::android::ConvertJavaStringToUTF8(env, socket_name_prefix));
233   return reinterpret_cast<intptr_t>(server);
234 }
235
236 static void DestroyRemoteDebugging(JNIEnv* env, jobject obj, jlong server) {
237   delete reinterpret_cast<DevToolsServer*>(server);
238 }
239
240 static jboolean IsRemoteDebuggingEnabled(JNIEnv* env,
241                                          jobject obj,
242                                          jlong server) {
243   return reinterpret_cast<DevToolsServer*>(server)->IsStarted();
244 }
245
246 static void SetRemoteDebuggingEnabled(JNIEnv* env,
247                                       jobject obj,
248                                       jlong server,
249                                       jboolean enabled,
250                                       jboolean allow_debug_permission) {
251   DevToolsServer* devtools_server = reinterpret_cast<DevToolsServer*>(server);
252   if (enabled) {
253     devtools_server->Start(allow_debug_permission);
254   } else {
255     devtools_server->Stop();
256   }
257 }