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