f979b2db8b568aa809243e00c8ac19276d7b52a6
[platform/framework/web/crosswalk.git] / src / xwalk / runtime / browser / android / xwalk_dev_tools_server.cc
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Copyright 2013 The Chromium Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5
6 #include "xwalk/runtime/browser/android/xwalk_dev_tools_server.h"
7
8 #include <sys/types.h>
9 #include <unistd.h>
10 #include <vector>
11
12 #include "base/android/jni_string.h"
13 #include "base/basictypes.h"
14 #include "base/bind.h"
15 #include "base/callback.h"
16 #include "base/compiler_specific.h"
17 #include "base/logging.h"
18 #include "base/strings/stringprintf.h"
19 #include "base/strings/utf_string_conversions.h"
20 #include "content/public/browser/android/devtools_auth.h"
21 #include "content/public/browser/devtools_agent_host.h"
22 #include "content/public/browser/devtools_http_handler.h"
23 #include "content/public/browser/devtools_http_handler_delegate.h"
24 #include "content/public/browser/devtools_manager_delegate.h"
25 #include "content/public/browser/devtools_target.h"
26 #include "content/public/browser/favicon_status.h"
27 #include "content/public/browser/navigation_entry.h"
28 #include "content/public/browser/render_view_host.h"
29 #include "content/public/browser/web_contents.h"
30 #include "content/public/browser/web_contents_delegate.h"
31 #include "content/public/common/user_agent.h"
32 #include "grit/xwalk_resources.h"
33 #include "jni/XWalkDevToolsServer_jni.h"
34 #include "net/socket/unix_domain_listen_socket_posix.h"
35 #include "ui/base/resource/resource_bundle.h"
36
37 using content::DevToolsAgentHost;
38 using content::RenderViewHost;
39 using content::WebContents;
40
41 namespace {
42
43 // FIXME(girish): The frontend URL needs to be served from the domain below
44 // for remote debugging to work in chrome (see chrome's devtools_ui.cc).
45 // Currently, the chrome version is hardcoded because of this dependancy.
46 const char kFrontEndURL[] =
47     "http://chrome-devtools-frontend.appspot.com/serve_rev/%s/devtools.html";
48 const char kTargetTypePage[] = "page";
49 const char kTargetTypeServiceWorker[] = "service_worker";
50 const char kTargetTypeOther[] = "other";
51
52 bool AuthorizeSocketAccessWithDebugPermission(
53      const net::UnixDomainServerSocket::Credentials& credentials) {
54   JNIEnv* env = base::android::AttachCurrentThread();
55   return xwalk::Java_XWalkDevToolsServer_checkDebugPermission(
56       env, base::android::GetApplicationContext(),
57       credentials.process_id, credentials.user_id) ||
58       content::CanUserConnectToDevTools(credentials);
59 }
60
61 class Target : public content::DevToolsTarget {
62  public:
63   explicit Target(scoped_refptr<content::DevToolsAgentHost> agent_host);
64
65   virtual std::string GetId() const OVERRIDE { return agent_host_->GetId(); }
66   virtual std::string GetType() const OVERRIDE {
67       switch (agent_host_->GetType()) {
68         case content::DevToolsAgentHost::TYPE_WEB_CONTENTS:
69            return kTargetTypePage;
70          case content::DevToolsAgentHost::TYPE_SERVICE_WORKER:
71            return kTargetTypeServiceWorker;
72          default:
73            break;
74        }
75        return kTargetTypeOther;
76      }
77   virtual std::string GetTitle() const OVERRIDE {
78     return agent_host_->GetTitle();
79   }
80
81   // TODO(hmin): Get the description about web contents view.
82   virtual std::string GetDescription() const OVERRIDE { return std::string(); }
83   virtual GURL GetURL() const OVERRIDE { return url_; }
84   virtual GURL GetFaviconURL() const OVERRIDE { return GURL(); }
85   virtual base::TimeTicks GetLastActivityTime() const OVERRIDE {
86     return last_activity_time_;
87   }
88   virtual std::string GetParentId() const OVERRIDE { return std::string(); }
89   virtual bool IsAttached() const OVERRIDE {
90     return agent_host_->IsAttached();
91   }
92   virtual scoped_refptr<DevToolsAgentHost> GetAgentHost() const OVERRIDE {
93     return agent_host_;
94   }
95
96   virtual bool Activate() const OVERRIDE {
97     WebContents* web_contents = agent_host_->GetWebContents();
98     if (!web_contents)
99       return false;
100     web_contents->GetDelegate()->ActivateContents(web_contents);
101     return true;
102   }
103
104   virtual bool Close() const OVERRIDE { return false; }
105
106  private:
107   scoped_refptr<DevToolsAgentHost> agent_host_;
108   std::string id_;
109   std::string title_;
110   GURL url_;
111   GURL favicon_url_;
112   base::TimeTicks last_activity_time_;
113 };
114
115 Target::Target(scoped_refptr<content::DevToolsAgentHost> agent_host)
116     : agent_host_(agent_host) {
117   if (content::WebContents* web_contents = agent_host_->GetWebContents()) {
118     content::NavigationController& controller = web_contents->GetController();
119     content::NavigationEntry* entry = controller.GetActiveEntry();
120     if (entry != NULL && entry->GetURL().is_valid())
121       favicon_url_ = entry->GetFavicon().url;
122     last_activity_time_ = web_contents->GetLastActiveTime();
123   }
124 }
125
126 // Delegate implementation for the devtools http handler on android. A new
127 // instance of this gets created each time devtools is enabled.
128 class XWalkDevToolsHttpHandlerDelegate
129   : public content::DevToolsHttpHandlerDelegate {
130  public:
131   explicit XWalkDevToolsHttpHandlerDelegate(
132     const net::UnixDomainServerSocket::AuthCallback& auth_callback)
133     : auth_callback_(auth_callback) {
134   }
135
136   virtual std::string GetDiscoveryPageHTML() OVERRIDE {
137     return ResourceBundle::GetSharedInstance().GetRawDataResource(
138         IDR_DEVTOOLS_FRONTEND_PAGE_HTML).as_string();
139   }
140
141   virtual bool BundlesFrontendResources() OVERRIDE {
142     return false;
143   }
144
145   virtual base::FilePath GetDebugFrontendDir() OVERRIDE {
146     return base::FilePath();
147   }
148
149   virtual scoped_ptr<net::StreamListenSocket> CreateSocketForTethering(
150       net::StreamListenSocket::Delegate* delegate,
151       std::string* name) OVERRIDE {
152     return scoped_ptr<net::StreamListenSocket>();
153   }
154  private:
155   const net::UnixDomainServerSocket::AuthCallback auth_callback_;
156   DISALLOW_COPY_AND_ASSIGN(XWalkDevToolsHttpHandlerDelegate);
157 };
158
159 class XWalkDevToolsDelegate
160   : public content::DevToolsManagerDelegate {
161  public:
162   virtual std::string GetPageThumbnailData(const GURL& url) OVERRIDE {
163     return std::string();
164   }
165
166   virtual scoped_ptr<content::DevToolsTarget> CreateNewTarget(
167       const GURL&) OVERRIDE {
168     return scoped_ptr<content::DevToolsTarget>();
169   }
170   virtual void EnumerateTargets(TargetCallback callback) OVERRIDE {
171     TargetList targets;
172     content::DevToolsAgentHost::List agents =
173         content::DevToolsAgentHost::GetOrCreateAll();
174     for (content::DevToolsAgentHost::List::iterator it = agents.begin();
175          it != agents.end(); ++it) {
176       targets.push_back(new Target(*it));
177     }
178     callback.Run(targets);
179   }
180 };
181
182 // Factory for UnixDomainServerSocket.
183 class UnixDomainServerSocketFactory
184     : public content::DevToolsHttpHandler::ServerSocketFactory {
185  public:
186   explicit UnixDomainServerSocketFactory(const std::string& socket_name)
187       : content::DevToolsHttpHandler::ServerSocketFactory(socket_name, 0, 1) {}
188
189  private:
190   // content::DevToolsHttpHandler::ServerSocketFactory.
191   virtual scoped_ptr<net::ServerSocket> Create() const OVERRIDE {
192     return scoped_ptr<net::ServerSocket>(
193         new net::UnixDomainServerSocket(
194             base::Bind(&content::CanUserConnectToDevTools),
195             true /* use_abstract_namespace */));
196   }
197
198   DISALLOW_COPY_AND_ASSIGN(UnixDomainServerSocketFactory);
199 };
200
201 }  // namespace
202
203 namespace xwalk {
204
205 XWalkDevToolsServer::XWalkDevToolsServer(const std::string& socket_name)
206     : socket_name_(socket_name),
207       protocol_handler_(NULL),
208       allowed_uid_(0) {
209 }
210
211 XWalkDevToolsServer::~XWalkDevToolsServer() {
212   Stop();
213 }
214
215 // Allow connection from uid specified using AllowConnectionFromUid to devtools
216 // server. This supports the XDK usage: debug bridge wrapper runs in a separate
217 // process and connects to the devtools server.
218 bool XWalkDevToolsServer::CanUserConnectToDevTools(
219     const net::UnixDomainServerSocket::Credentials& credentials) {
220   if (credentials.user_id == allowed_uid_)
221     return true;
222   return content::CanUserConnectToDevTools(credentials);
223 }
224
225 void XWalkDevToolsServer::Start(bool allow_debug_permission) {
226   if (protocol_handler_)
227     return;
228
229   net::UnixDomainServerSocket::AuthCallback auth_callback =
230       allow_debug_permission ?
231           base::Bind(&AuthorizeSocketAccessWithDebugPermission) :
232           base::Bind(&XWalkDevToolsServer::CanUserConnectToDevTools,
233               base::Unretained(this));
234
235   scoped_ptr<content::DevToolsHttpHandler::ServerSocketFactory> factory(
236       new UnixDomainServerSocketFactory(socket_name_));
237   protocol_handler_ = content::DevToolsHttpHandler::Start(
238       factory.Pass(),
239       base::StringPrintf(kFrontEndURL, content::GetWebKitRevision().c_str()),
240       new XWalkDevToolsHttpHandlerDelegate(auth_callback), base::FilePath());
241 }
242
243 void XWalkDevToolsServer::Stop() {
244   if (!protocol_handler_)
245     return;
246   // Note that the call to Stop() below takes care of |protocol_handler_|
247   // deletion.
248   protocol_handler_->Stop();
249   protocol_handler_ = NULL;
250 }
251
252 bool XWalkDevToolsServer::IsStarted() const {
253   return protocol_handler_;
254 }
255
256 void XWalkDevToolsServer::AllowConnectionFromUid(uid_t uid) {
257   allowed_uid_ = uid;
258 }
259
260 bool RegisterXWalkDevToolsServer(JNIEnv* env) {
261   return RegisterNativesImpl(env);
262 }
263
264 static jlong InitRemoteDebugging(JNIEnv* env,
265                                 jobject obj,
266                                 jstring socketName) {
267   XWalkDevToolsServer* server = new XWalkDevToolsServer(
268       base::android::ConvertJavaStringToUTF8(env, socketName));
269   return reinterpret_cast<intptr_t>(server);
270 }
271
272 static void DestroyRemoteDebugging(JNIEnv* env, jobject obj, jlong server) {
273   delete reinterpret_cast<XWalkDevToolsServer*>(server);
274 }
275
276 static jboolean IsRemoteDebuggingEnabled(JNIEnv* env,
277                                          jobject obj,
278                                          jlong server) {
279   return reinterpret_cast<XWalkDevToolsServer*>(server)->IsStarted();
280 }
281
282 static void SetRemoteDebuggingEnabled(JNIEnv* env,
283                                       jobject obj,
284                                       jlong server,
285                                       jboolean enabled,
286                                       jboolean allow_debug_permission) {
287   XWalkDevToolsServer* devtools_server =
288       reinterpret_cast<XWalkDevToolsServer*>(server);
289   if (enabled) {
290     devtools_server->Start(allow_debug_permission);
291   } else {
292     devtools_server->Stop();
293   }
294 }
295
296 static void AllowConnectionFromUid(JNIEnv* env,
297                                     jobject obj,
298                                     jlong server,
299                                     jint uid) {
300   XWalkDevToolsServer* devtools_server =
301       reinterpret_cast<XWalkDevToolsServer*>(server);
302   devtools_server->AllowConnectionFromUid((uid_t) uid);
303 }
304
305 }  // namespace xwalk