| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/android/dev_tools_server.h" | 5 #include "chrome/browser/android/dev_tools_server.h" |
| 6 | 6 |
| 7 #include <pwd.h> | 7 #include <pwd.h> |
| 8 #include <cstring> | 8 #include <cstring> |
| 9 | 9 |
| 10 #include "base/android/jni_string.h" | 10 #include "base/android/jni_string.h" |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 60 // corresponding string on the client side. Since debugging an older version of | 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 | 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 | 62 // scenario, the client code will have to be modified to recognize both the old |
| 63 // and the new format. | 63 // and the new format. |
| 64 const char kDevToolsChannelNameFormat[] = "%s_devtools_remote"; | 64 const char kDevToolsChannelNameFormat[] = "%s_devtools_remote"; |
| 65 | 65 |
| 66 const char kFrontEndURL[] = | 66 const char kFrontEndURL[] = |
| 67 "http://chrome-devtools-frontend.appspot.com/serve_rev/%s/devtools.html"; | 67 "http://chrome-devtools-frontend.appspot.com/serve_rev/%s/devtools.html"; |
| 68 const char kTetheringSocketName[] = "chrome_devtools_tethering_%d_%d"; | 68 const char kTetheringSocketName[] = "chrome_devtools_tethering_%d_%d"; |
| 69 | 69 |
| 70 const char kTargetTypePage[] = "page"; | |
| 71 const char kTargetTypeServiceWorker[] = "service_worker"; | |
| 72 const char kTargetTypeOther[] = "other"; | |
| 73 | |
| 74 static GURL GetFaviconURLForContents(WebContents* web_contents) { | |
| 75 content::NavigationController& controller = web_contents->GetController(); | |
| 76 content::NavigationEntry* entry = controller.GetActiveEntry(); | |
| 77 if (entry != NULL && entry->GetURL().is_valid()) | |
| 78 return entry->GetFavicon().url; | |
| 79 return GURL(); | |
| 80 } | |
| 81 | |
| 82 static GURL GetFaviconURLForAgentHost( | |
| 83 scoped_refptr<DevToolsAgentHost> agent_host) { | |
| 84 if (WebContents* web_contents = agent_host->GetWebContents()) | |
| 85 return GetFaviconURLForContents(web_contents); | |
| 86 return GURL(); | |
| 87 } | |
| 88 | |
| 89 static base::TimeTicks GetLastActiveTimeForAgentHost( | |
| 90 scoped_refptr<DevToolsAgentHost> agent_host) { | |
| 91 if (WebContents* web_contents = agent_host->GetWebContents()) | |
| 92 return web_contents->GetLastActiveTime(); | |
| 93 return base::TimeTicks(); | |
| 94 } | |
| 95 | |
| 96 bool AuthorizeSocketAccessWithDebugPermission( | 70 bool AuthorizeSocketAccessWithDebugPermission( |
| 97 const net::UnixDomainServerSocket::Credentials& credentials) { | 71 const net::UnixDomainServerSocket::Credentials& credentials) { |
| 98 JNIEnv* env = base::android::AttachCurrentThread(); | 72 JNIEnv* env = base::android::AttachCurrentThread(); |
| 99 return Java_DevToolsServer_checkDebugPermission( | 73 return Java_DevToolsServer_checkDebugPermission( |
| 100 env, base::android::GetApplicationContext(), | 74 env, base::android::GetApplicationContext(), |
| 101 credentials.process_id, credentials.user_id) || | 75 credentials.process_id, credentials.user_id) || |
| 102 content::CanUserConnectToDevTools(credentials); | 76 content::CanUserConnectToDevTools(credentials); |
| 103 } | 77 } |
| 104 | 78 |
| 105 class TargetBase : public content::DevToolsTarget { | |
| 106 public: | |
| 107 // content::DevToolsTarget implementation: | |
| 108 virtual std::string GetParentId() const OVERRIDE { return std::string(); } | |
| 109 | |
| 110 virtual std::string GetTitle() const OVERRIDE { return title_; } | |
| 111 | |
| 112 virtual std::string GetDescription() const OVERRIDE { return std::string(); } | |
| 113 | |
| 114 virtual GURL GetURL() const OVERRIDE { return url_; } | |
| 115 | |
| 116 virtual GURL GetFaviconURL() const OVERRIDE { return favicon_url_; } | |
| 117 | |
| 118 virtual base::TimeTicks GetLastActivityTime() const OVERRIDE { | |
| 119 return last_activity_time_; | |
| 120 } | |
| 121 | |
| 122 protected: | |
| 123 explicit TargetBase(WebContents* web_contents) | |
| 124 : title_(base::UTF16ToUTF8(web_contents->GetTitle())), | |
| 125 url_(web_contents->GetURL()), | |
| 126 favicon_url_(GetFaviconURLForContents(web_contents)), | |
| 127 last_activity_time_(web_contents->GetLastActiveTime()) { | |
| 128 } | |
| 129 | |
| 130 explicit TargetBase(scoped_refptr<DevToolsAgentHost> agent_host) | |
| 131 : title_(agent_host->GetTitle()), | |
| 132 url_(agent_host->GetURL()), | |
| 133 favicon_url_(GetFaviconURLForAgentHost(agent_host)), | |
| 134 last_activity_time_(GetLastActiveTimeForAgentHost(agent_host)) { | |
| 135 } | |
| 136 | |
| 137 TargetBase(const std::string& title, const GURL& url) | |
| 138 : title_(title), | |
| 139 url_(url) { | |
| 140 } | |
| 141 | |
| 142 private: | |
| 143 const std::string title_; | |
| 144 const GURL url_; | |
| 145 const GURL favicon_url_; | |
| 146 const base::TimeTicks last_activity_time_; | |
| 147 }; | |
| 148 | |
| 149 class TabTarget : public TargetBase { | |
| 150 public: | |
| 151 static TabTarget* CreateForWebContents(int tab_id, | |
| 152 WebContents* web_contents) { | |
| 153 return new TabTarget(tab_id, web_contents); | |
| 154 } | |
| 155 | |
| 156 static TabTarget* CreateForUnloadedTab(int tab_id, | |
| 157 const base::string16& title, | |
| 158 const GURL& url) { | |
| 159 return new TabTarget(tab_id, title, url); | |
| 160 } | |
| 161 | |
| 162 // content::DevToolsTarget implementation: | |
| 163 virtual std::string GetId() const OVERRIDE { | |
| 164 return base::IntToString(tab_id_); | |
| 165 } | |
| 166 | |
| 167 virtual std::string GetType() const OVERRIDE { | |
| 168 return kTargetTypePage; | |
| 169 } | |
| 170 | |
| 171 virtual bool IsAttached() const OVERRIDE { | |
| 172 TabModel* model; | |
| 173 int index; | |
| 174 if (!FindTab(&model, &index)) | |
| 175 return false; | |
| 176 WebContents* web_contents = model->GetWebContentsAt(index); | |
| 177 if (!web_contents) | |
| 178 return false; | |
| 179 return DevToolsAgentHost::IsDebuggerAttached(web_contents); | |
| 180 } | |
| 181 | |
| 182 virtual scoped_refptr<DevToolsAgentHost> GetAgentHost() const OVERRIDE { | |
| 183 TabModel* model; | |
| 184 int index; | |
| 185 if (!FindTab(&model, &index)) | |
| 186 return NULL; | |
| 187 WebContents* web_contents = model->GetWebContentsAt(index); | |
| 188 if (!web_contents) { | |
| 189 // The tab has been pushed out of memory, pull it back. | |
| 190 TabAndroid* tab = model->GetTabAt(index); | |
| 191 if (!tab) | |
| 192 return NULL; | |
| 193 | |
| 194 tab->LoadIfNeeded(); | |
| 195 web_contents = model->GetWebContentsAt(index); | |
| 196 if (!web_contents) | |
| 197 return NULL; | |
| 198 } | |
| 199 return DevToolsAgentHost::GetOrCreateFor(web_contents); | |
| 200 } | |
| 201 | |
| 202 virtual bool Activate() const OVERRIDE { | |
| 203 TabModel* model; | |
| 204 int index; | |
| 205 if (!FindTab(&model, &index)) | |
| 206 return false; | |
| 207 model->SetActiveIndex(index); | |
| 208 return true; | |
| 209 } | |
| 210 | |
| 211 virtual bool Close() const OVERRIDE { | |
| 212 TabModel* model; | |
| 213 int index; | |
| 214 if (!FindTab(&model, &index)) | |
| 215 return false; | |
| 216 model->CloseTabAt(index); | |
| 217 return true; | |
| 218 } | |
| 219 | |
| 220 private: | |
| 221 TabTarget(int tab_id, WebContents* web_contents) | |
| 222 : TargetBase(web_contents), | |
| 223 tab_id_(tab_id) { | |
| 224 } | |
| 225 | |
| 226 TabTarget(int tab_id, const base::string16& title, const GURL& url) | |
| 227 : TargetBase(base::UTF16ToUTF8(title), url), | |
| 228 tab_id_(tab_id) { | |
| 229 } | |
| 230 | |
| 231 bool FindTab(TabModel** model_result, int* index_result) const { | |
| 232 for (TabModelList::const_iterator iter = TabModelList::begin(); | |
| 233 iter != TabModelList::end(); ++iter) { | |
| 234 TabModel* model = *iter; | |
| 235 for (int i = 0; i < model->GetTabCount(); ++i) { | |
| 236 TabAndroid* tab = model->GetTabAt(i); | |
| 237 if (tab && tab->GetAndroidId() == tab_id_) { | |
| 238 *model_result = model; | |
| 239 *index_result = i; | |
| 240 return true; | |
| 241 } | |
| 242 } | |
| 243 } | |
| 244 return false; | |
| 245 } | |
| 246 | |
| 247 const int tab_id_; | |
| 248 }; | |
| 249 | |
| 250 class NonTabTarget : public TargetBase { | |
| 251 public: | |
| 252 explicit NonTabTarget(scoped_refptr<DevToolsAgentHost> agent_host) | |
| 253 : TargetBase(agent_host), | |
| 254 agent_host_(agent_host) { | |
| 255 } | |
| 256 | |
| 257 // content::DevToolsTarget implementation: | |
| 258 virtual std::string GetId() const OVERRIDE { | |
| 259 return agent_host_->GetId(); | |
| 260 } | |
| 261 | |
| 262 virtual std::string GetType() const OVERRIDE { | |
| 263 switch (agent_host_->GetType()) { | |
| 264 case DevToolsAgentHost::TYPE_WEB_CONTENTS: | |
| 265 if (TabModelList::begin() == TabModelList::end()) { | |
| 266 // If there are no tab models we must be running in ChromeShell. | |
| 267 // Return the 'page' target type for backwards compatibility. | |
| 268 return kTargetTypePage; | |
| 269 } | |
| 270 break; | |
| 271 case DevToolsAgentHost::TYPE_SERVICE_WORKER: | |
| 272 return kTargetTypeServiceWorker; | |
| 273 default: | |
| 274 break; | |
| 275 } | |
| 276 return kTargetTypeOther; | |
| 277 } | |
| 278 | |
| 279 virtual bool IsAttached() const OVERRIDE { | |
| 280 return agent_host_->IsAttached(); | |
| 281 } | |
| 282 | |
| 283 virtual scoped_refptr<DevToolsAgentHost> GetAgentHost() const OVERRIDE { | |
| 284 return agent_host_; | |
| 285 } | |
| 286 | |
| 287 virtual bool Activate() const OVERRIDE { | |
| 288 return agent_host_->Activate(); | |
| 289 } | |
| 290 | |
| 291 virtual bool Close() const OVERRIDE { | |
| 292 return agent_host_->Close(); | |
| 293 } | |
| 294 | |
| 295 private: | |
| 296 scoped_refptr<DevToolsAgentHost> agent_host_; | |
| 297 }; | |
| 298 | |
| 299 // Delegate implementation for the devtools http handler on android. A new | 79 // Delegate implementation for the devtools http handler on android. A new |
| 300 // instance of this gets created each time devtools is enabled. | 80 // instance of this gets created each time devtools is enabled. |
| 301 class DevToolsServerDelegate : public content::DevToolsHttpHandlerDelegate { | 81 class DevToolsServerDelegate : public content::DevToolsHttpHandlerDelegate { |
| 302 public: | 82 public: |
| 303 explicit DevToolsServerDelegate( | 83 explicit DevToolsServerDelegate( |
| 304 const net::UnixDomainServerSocket::AuthCallback& auth_callback) | 84 const net::UnixDomainServerSocket::AuthCallback& auth_callback) |
| 305 : last_tethering_socket_(0), | 85 : last_tethering_socket_(0), |
| 306 auth_callback_(auth_callback) { | 86 auth_callback_(auth_callback) { |
| 307 } | 87 } |
| 308 | 88 |
| 309 virtual std::string GetDiscoveryPageHTML() OVERRIDE { | 89 virtual std::string GetDiscoveryPageHTML() OVERRIDE { |
| 310 // TopSites updates itself after a delay. Ask TopSites to update itself | 90 // TopSites updates itself after a delay. Ask TopSites to update itself |
| 311 // when we're about to show the remote debugging landing page. | 91 // when we're about to show the remote debugging landing page. |
| 312 content::BrowserThread::PostTask( | 92 content::BrowserThread::PostTask( |
| 313 content::BrowserThread::UI, | 93 content::BrowserThread::UI, |
| 314 FROM_HERE, | 94 FROM_HERE, |
| 315 base::Bind(&DevToolsServerDelegate::PopulatePageThumbnails)); | 95 base::Bind(&DevToolsServerDelegate::PopulatePageThumbnails)); |
| 316 return ResourceBundle::GetSharedInstance().GetRawDataResource( | 96 return ResourceBundle::GetSharedInstance().GetRawDataResource( |
| 317 IDR_DEVTOOLS_DISCOVERY_PAGE_HTML).as_string(); | 97 IDR_DEVTOOLS_DISCOVERY_PAGE_HTML).as_string(); |
| 318 } | 98 } |
| 319 | 99 |
| 320 virtual bool BundlesFrontendResources() OVERRIDE { | 100 virtual bool BundlesFrontendResources() OVERRIDE { |
| 321 return false; | 101 return false; |
| 322 } | 102 } |
| 323 | 103 |
| 324 virtual base::FilePath GetDebugFrontendDir() OVERRIDE { | 104 virtual base::FilePath GetDebugFrontendDir() OVERRIDE { |
| 325 return base::FilePath(); | 105 return base::FilePath(); |
| 326 } | 106 } |
| 327 | 107 |
| 328 virtual std::string GetPageThumbnailData(const GURL& url) OVERRIDE { | |
| 329 Profile* profile = | |
| 330 ProfileManager::GetLastUsedProfile()->GetOriginalProfile(); | |
| 331 history::TopSites* top_sites = profile->GetTopSites(); | |
| 332 if (top_sites) { | |
| 333 scoped_refptr<base::RefCountedMemory> data; | |
| 334 if (top_sites->GetPageThumbnail(url, false, &data)) | |
| 335 return std::string(data->front_as<char>(), data->size()); | |
| 336 } | |
| 337 return ""; | |
| 338 } | |
| 339 | |
| 340 virtual scoped_ptr<content::DevToolsTarget> CreateNewTarget( | |
| 341 const GURL& url) OVERRIDE { | |
| 342 if (TabModelList::empty()) | |
| 343 return scoped_ptr<content::DevToolsTarget>(); | |
| 344 TabModel* tab_model = TabModelList::get(0); | |
| 345 if (!tab_model) | |
| 346 return scoped_ptr<content::DevToolsTarget>(); | |
| 347 WebContents* web_contents = tab_model->CreateNewTabForDevTools(url); | |
| 348 if (!web_contents) | |
| 349 return scoped_ptr<content::DevToolsTarget>(); | |
| 350 | |
| 351 TabAndroid* tab = TabAndroid::FromWebContents(web_contents); | |
| 352 if (!tab) | |
| 353 return scoped_ptr<content::DevToolsTarget>(); | |
| 354 | |
| 355 return scoped_ptr<content::DevToolsTarget>( | |
| 356 TabTarget::CreateForWebContents(tab->GetAndroidId(), web_contents)); | |
| 357 } | |
| 358 | |
| 359 virtual void EnumerateTargets(TargetCallback callback) OVERRIDE { | |
| 360 TargetList targets; | |
| 361 | |
| 362 // Enumerate existing tabs, including the ones with no WebContents. | |
| 363 std::set<WebContents*> tab_web_contents; | |
| 364 for (TabModelList::const_iterator iter = TabModelList::begin(); | |
| 365 iter != TabModelList::end(); ++iter) { | |
| 366 TabModel* model = *iter; | |
| 367 for (int i = 0; i < model->GetTabCount(); ++i) { | |
| 368 TabAndroid* tab = model->GetTabAt(i); | |
| 369 if (!tab) | |
| 370 continue; | |
| 371 | |
| 372 WebContents* web_contents = model->GetWebContentsAt(i); | |
| 373 if (web_contents) { | |
| 374 tab_web_contents.insert(web_contents); | |
| 375 targets.push_back(TabTarget::CreateForWebContents(tab->GetAndroidId(), | |
| 376 web_contents)); | |
| 377 } else { | |
| 378 targets.push_back(TabTarget::CreateForUnloadedTab(tab->GetAndroidId(), | |
| 379 tab->GetTitle(), | |
| 380 tab->GetURL())); | |
| 381 } | |
| 382 } | |
| 383 } | |
| 384 | |
| 385 // Add targets for WebContents not associated with any tabs. | |
| 386 DevToolsAgentHost::List agents = | |
| 387 DevToolsAgentHost::GetOrCreateAll(); | |
| 388 for (DevToolsAgentHost::List::iterator it = agents.begin(); | |
| 389 it != agents.end(); ++it) { | |
| 390 if (WebContents* web_contents = (*it)->GetWebContents()) { | |
| 391 if (tab_web_contents.find(web_contents) != tab_web_contents.end()) | |
| 392 continue; | |
| 393 } | |
| 394 targets.push_back(new NonTabTarget(*it)); | |
| 395 } | |
| 396 | |
| 397 callback.Run(targets); | |
| 398 } | |
| 399 | |
| 400 virtual scoped_ptr<net::StreamListenSocket> CreateSocketForTethering( | 108 virtual scoped_ptr<net::StreamListenSocket> CreateSocketForTethering( |
| 401 net::StreamListenSocket::Delegate* delegate, | 109 net::StreamListenSocket::Delegate* delegate, |
| 402 std::string* name) OVERRIDE { | 110 std::string* name) OVERRIDE { |
| 403 *name = base::StringPrintf( | 111 *name = base::StringPrintf( |
| 404 kTetheringSocketName, getpid(), ++last_tethering_socket_); | 112 kTetheringSocketName, getpid(), ++last_tethering_socket_); |
| 405 return net::deprecated::UnixDomainListenSocket:: | 113 return net::deprecated::UnixDomainListenSocket:: |
| 406 CreateAndListenWithAbstractNamespace( | 114 CreateAndListenWithAbstractNamespace( |
| 407 *name, | 115 *name, |
| 408 "", | 116 "", |
| 409 delegate, | 117 delegate, |
| (...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 544 jlong server, | 252 jlong server, |
| 545 jboolean enabled, | 253 jboolean enabled, |
| 546 jboolean allow_debug_permission) { | 254 jboolean allow_debug_permission) { |
| 547 DevToolsServer* devtools_server = reinterpret_cast<DevToolsServer*>(server); | 255 DevToolsServer* devtools_server = reinterpret_cast<DevToolsServer*>(server); |
| 548 if (enabled) { | 256 if (enabled) { |
| 549 devtools_server->Start(allow_debug_permission); | 257 devtools_server->Start(allow_debug_permission); |
| 550 } else { | 258 } else { |
| 551 devtools_server->Stop(); | 259 devtools_server->Stop(); |
| 552 } | 260 } |
| 553 } | 261 } |
| OLD | NEW |