| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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/devtools/device/devtools_android_bridge.h" | 5 #include "chrome/browser/devtools/device/devtools_android_bridge.h" |
| 6 | 6 |
| 7 #include <map> | 7 #include <map> |
| 8 #include <set> |
| 8 #include <vector> | 9 #include <vector> |
| 9 | 10 |
| 10 #include "base/base64.h" | 11 #include "base/base64.h" |
| 11 #include "base/bind.h" | 12 #include "base/bind.h" |
| 12 #include "base/command_line.h" | 13 #include "base/command_line.h" |
| 13 #include "base/compiler_specific.h" | 14 #include "base/compiler_specific.h" |
| 14 #include "base/json/json_reader.h" | 15 #include "base/json/json_reader.h" |
| 15 #include "base/lazy_instance.h" | 16 #include "base/lazy_instance.h" |
| 16 #include "base/memory/singleton.h" | 17 #include "base/memory/singleton.h" |
| 17 #include "base/message_loop/message_loop.h" | 18 #include "base/message_loop/message_loop.h" |
| (...skipping 271 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 289 } | 290 } |
| 290 | 291 |
| 291 return new DevToolsAndroidBridge( | 292 return new DevToolsAndroidBridge( |
| 292 profile, signin_manager, token_service); | 293 profile, signin_manager, token_service); |
| 293 } | 294 } |
| 294 | 295 |
| 295 // AgentHostDelegate ---------------------------------------------------------- | 296 // AgentHostDelegate ---------------------------------------------------------- |
| 296 | 297 |
| 297 class DevToolsAndroidBridge::AgentHostDelegate | 298 class DevToolsAndroidBridge::AgentHostDelegate |
| 298 : public content::DevToolsExternalAgentProxyDelegate, | 299 : public content::DevToolsExternalAgentProxyDelegate, |
| 299 public AndroidDeviceManager::AndroidWebSocket::Delegate { | 300 public AndroidDeviceManager::AndroidWebSocket::Delegate, |
| 301 public DevToolsAndroidBridge::DeviceListListener { |
| 300 public: | 302 public: |
| 301 static scoped_refptr<content::DevToolsAgentHost> GetOrCreateAgentHost( | 303 static scoped_refptr<content::DevToolsAgentHost> GetOrCreateAgentHost( |
| 302 DevToolsAndroidBridge* bridge, | 304 DevToolsAndroidBridge* bridge, |
| 303 const std::string& id, | 305 const std::string& id, |
| 304 const BrowserId& browser_id, | 306 const BrowserId& browser_id, |
| 305 const std::string& debug_url); | 307 const std::string& debug_url); |
| 306 | 308 |
| 307 private: | 309 private: |
| 308 AgentHostDelegate( | 310 AgentHostDelegate( |
| 309 DevToolsAndroidBridge* bridge, | 311 DevToolsAndroidBridge* bridge, |
| 310 const std::string& id, | 312 const std::string& id, |
| 311 const BrowserId& browser_id, | 313 const BrowserId& browser_id, |
| 312 const std::string& debug_url); | 314 const std::string& debug_url); |
| 313 ~AgentHostDelegate() override; | 315 ~AgentHostDelegate() override; |
| 314 void Attach(content::DevToolsExternalAgentProxy* proxy) override; | 316 void Attach(content::DevToolsExternalAgentProxy* proxy) override; |
| 315 void Detach() override; | 317 void Detach() override; |
| 316 void SendMessageToBackend(const std::string& message) override; | 318 void SendMessageToBackend(const std::string& message) override; |
| 319 void OpenWorkerInspector(content::BrowserContext* context, |
| 320 const std::string& id) override; |
| 317 void OnSocketOpened() override; | 321 void OnSocketOpened() override; |
| 318 void OnFrameRead(const std::string& message) override; | 322 void OnFrameRead(const std::string& message) override; |
| 319 void OnSocketClosed() override; | 323 void OnSocketClosed() override; |
| 320 | 324 |
| 325 // DevToolsAndroidBridge::Listener overrides. |
| 326 void DeviceListChanged( |
| 327 const DevToolsAndroidBridge::RemoteDevices& devices) override; |
| 328 |
| 321 std::string id_; | 329 std::string id_; |
| 322 base::WeakPtr<DevToolsAndroidBridge> bridge_; | 330 base::WeakPtr<DevToolsAndroidBridge> bridge_; |
| 323 BrowserId browser_id_; | 331 BrowserId browser_id_; |
| 324 std::string debug_url_; | 332 std::string debug_url_; |
| 325 bool socket_opened_; | 333 bool socket_opened_; |
| 326 std::vector<std::string> pending_messages_; | 334 std::vector<std::string> pending_messages_; |
| 327 scoped_refptr<AndroidDeviceManager::Device> device_; | 335 scoped_refptr<AndroidDeviceManager::Device> device_; |
| 328 scoped_ptr<AndroidDeviceManager::AndroidWebSocket> web_socket_; | 336 scoped_ptr<AndroidDeviceManager::AndroidWebSocket> web_socket_; |
| 329 content::DevToolsAgentHost* agent_host_; | 337 content::DevToolsAgentHost* agent_host_; |
| 330 content::DevToolsExternalAgentProxy* proxy_; | 338 content::DevToolsExternalAgentProxy* proxy_; |
| 339 content::BrowserContext* context_; |
| 340 std::set<std::string> pending_workers_; |
| 341 base::WeakPtrFactory<DevToolsAndroidBridge::AgentHostDelegate> weak_factory_; |
| 342 |
| 331 DISALLOW_COPY_AND_ASSIGN(AgentHostDelegate); | 343 DISALLOW_COPY_AND_ASSIGN(AgentHostDelegate); |
| 332 }; | 344 }; |
| 333 | 345 |
| 334 // static | 346 // static |
| 335 scoped_refptr<content::DevToolsAgentHost> | 347 scoped_refptr<content::DevToolsAgentHost> |
| 336 DevToolsAndroidBridge::AgentHostDelegate::GetOrCreateAgentHost( | 348 DevToolsAndroidBridge::AgentHostDelegate::GetOrCreateAgentHost( |
| 337 DevToolsAndroidBridge* bridge, | 349 DevToolsAndroidBridge* bridge, |
| 338 const std::string& id, | 350 const std::string& id, |
| 339 const BrowserId& browser_id, | 351 const BrowserId& browser_id, |
| 340 const std::string& debug_url) { | 352 const std::string& debug_url) { |
| 341 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 353 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 342 AgentHostDelegates::iterator it = bridge->host_delegates_.find(id); | 354 AgentHostDelegates::iterator it = bridge->host_delegates_.find(id); |
| 343 if (it != bridge->host_delegates_.end()) | 355 if (it != bridge->host_delegates_.end()) { |
| 356 it->second->debug_url_ = debug_url; |
| 344 return it->second->agent_host_; | 357 return it->second->agent_host_; |
| 358 } |
| 345 | 359 |
| 346 AgentHostDelegate* delegate = | 360 AgentHostDelegate* delegate = |
| 347 new AgentHostDelegate(bridge, id, browser_id, debug_url); | 361 new AgentHostDelegate(bridge, id, browser_id, debug_url); |
| 348 scoped_refptr<content::DevToolsAgentHost> result = | 362 scoped_refptr<content::DevToolsAgentHost> result = |
| 349 content::DevToolsAgentHost::Create(delegate); | 363 content::DevToolsAgentHost::Create(delegate); |
| 350 delegate->agent_host_ = result.get(); | 364 delegate->agent_host_ = result.get(); |
| 351 return result; | 365 return result; |
| 352 } | 366 } |
| 353 | 367 |
| 354 DevToolsAndroidBridge::AgentHostDelegate::AgentHostDelegate( | 368 DevToolsAndroidBridge::AgentHostDelegate::AgentHostDelegate( |
| 355 DevToolsAndroidBridge* bridge, | 369 DevToolsAndroidBridge* bridge, |
| 356 const std::string& id, | 370 const std::string& id, |
| 357 const BrowserId& browser_id, | 371 const BrowserId& browser_id, |
| 358 const std::string& debug_url) | 372 const std::string& debug_url) |
| 359 : id_(id), | 373 : id_(id), |
| 360 bridge_(bridge->AsWeakPtr()), | 374 bridge_(bridge->AsWeakPtr()), |
| 361 browser_id_(browser_id), | 375 browser_id_(browser_id), |
| 362 debug_url_(debug_url), | 376 debug_url_(debug_url), |
| 363 socket_opened_(false), | 377 socket_opened_(false), |
| 364 agent_host_(NULL), | 378 agent_host_(NULL), |
| 365 proxy_(NULL) { | 379 proxy_(NULL), |
| 380 context_(NULL), |
| 381 weak_factory_(this) { |
| 366 bridge_->host_delegates_[id] = this; | 382 bridge_->host_delegates_[id] = this; |
| 367 } | 383 } |
| 368 | 384 |
| 369 DevToolsAndroidBridge::AgentHostDelegate::~AgentHostDelegate() { | 385 DevToolsAndroidBridge::AgentHostDelegate::~AgentHostDelegate() { |
| 370 if (bridge_) | 386 if (bridge_) { |
| 387 if (pending_workers_.size()) { |
| 388 bridge_->RemoveDeviceListListener(this); |
| 389 } |
| 371 bridge_->host_delegates_.erase(id_); | 390 bridge_->host_delegates_.erase(id_); |
| 391 } |
| 372 } | 392 } |
| 373 | 393 |
| 374 void DevToolsAndroidBridge::AgentHostDelegate::Attach( | 394 void DevToolsAndroidBridge::AgentHostDelegate::Attach( |
| 375 content::DevToolsExternalAgentProxy* proxy) { | 395 content::DevToolsExternalAgentProxy* proxy) { |
| 376 proxy_ = proxy; | 396 proxy_ = proxy; |
| 377 content::RecordAction(browser_id_.second.find(kWebViewSocketPrefix) == 0 ? | 397 content::RecordAction(browser_id_.second.find(kWebViewSocketPrefix) == 0 ? |
| 378 base::UserMetricsAction("DevTools_InspectAndroidWebView") : | 398 base::UserMetricsAction("DevTools_InspectAndroidWebView") : |
| 379 base::UserMetricsAction("DevTools_InspectAndroidPage")); | 399 base::UserMetricsAction("DevTools_InspectAndroidPage")); |
| 380 | 400 |
| 381 // Retain the device so it's not released until AgentHost is detached. | 401 // Retain the device so it's not released until AgentHost is detached. |
| 382 if (bridge_) | 402 if (bridge_) |
| 383 device_ = bridge_->FindDevice(browser_id_.first); | 403 device_ = bridge_->FindDevice(browser_id_.first); |
| 384 if (!device_.get()) | 404 if (!device_.get()) |
| 385 return; | 405 return; |
| 386 | |
| 387 web_socket_.reset( | 406 web_socket_.reset( |
| 388 device_->CreateWebSocket(browser_id_.second, debug_url_, this)); | 407 device_->CreateWebSocket(browser_id_.second, debug_url_, this)); |
| 389 } | 408 } |
| 390 | 409 |
| 391 void DevToolsAndroidBridge::AgentHostDelegate::Detach() { | 410 void DevToolsAndroidBridge::AgentHostDelegate::Detach() { |
| 392 web_socket_.reset(); | 411 web_socket_.reset(); |
| 393 device_ = nullptr; | 412 device_ = nullptr; |
| 394 } | 413 } |
| 395 | 414 |
| 396 void DevToolsAndroidBridge::AgentHostDelegate::SendMessageToBackend( | 415 void DevToolsAndroidBridge::AgentHostDelegate::SendMessageToBackend( |
| 397 const std::string& message) { | 416 const std::string& message) { |
| 398 if (socket_opened_) | 417 if (socket_opened_) |
| 399 web_socket_->SendFrame(message); | 418 web_socket_->SendFrame(message); |
| 400 else | 419 else |
| 401 pending_messages_.push_back(message); | 420 pending_messages_.push_back(message); |
| 402 } | 421 } |
| 403 | 422 |
| 423 void DevToolsAndroidBridge::AgentHostDelegate::OpenWorkerInspector( |
| 424 content::BrowserContext* context, |
| 425 const std::string& id) { |
| 426 if (!bridge_) |
| 427 return; |
| 428 const std::string full_id = |
| 429 base::StringPrintf("%s:%s:%s", browser_id_.first.c_str(), |
| 430 browser_id_.second.c_str(), id.c_str()); |
| 431 if (pending_workers_.size()) { |
| 432 pending_workers_.insert(full_id); |
| 433 } else { |
| 434 pending_workers_.insert(full_id); |
| 435 context_ = context; |
| 436 bridge_->AddDeviceListListener(this); |
| 437 } |
| 438 } |
| 439 |
| 440 static std::string GetStringProperty(const base::DictionaryValue& value, |
| 441 const std::string& name) { |
| 442 std::string result; |
| 443 value.GetString(name, &result); |
| 444 return result; |
| 445 } |
| 446 |
| 447 static std::string BuildUniqueTargetId( |
| 448 const DevToolsAndroidBridge::BrowserId& browser_id, |
| 449 const base::DictionaryValue& value) { |
| 450 return base::StringPrintf("%s:%s:%s", browser_id.first.c_str(), |
| 451 browser_id.second.c_str(), |
| 452 GetStringProperty(value, "id").c_str()); |
| 453 } |
| 454 |
| 455 static std::string GetDebugURL(const base::DictionaryValue& value) { |
| 456 std::string debug_url = GetStringProperty(value, "webSocketDebuggerUrl"); |
| 457 |
| 458 if (debug_url.find("ws://") == 0) |
| 459 debug_url = debug_url.substr(5); |
| 460 else |
| 461 debug_url = std::string(); |
| 462 return debug_url; |
| 463 } |
| 464 |
| 465 void DevToolsAndroidBridge::AgentHostDelegate::DeviceListChanged( |
| 466 const DevToolsAndroidBridge::RemoteDevices& devices) { |
| 467 if (!bridge_) { |
| 468 pending_workers_.clear(); |
| 469 return; |
| 470 } |
| 471 for (const auto& device : devices) { |
| 472 for (const auto& browser : device->browsers()) { |
| 473 for (const auto& page : browser->pages()) { |
| 474 scoped_ptr<DevToolsTargetImpl> target(bridge_->CreatePageTarget(page)); |
| 475 if (pending_workers_.count(target->GetId())) { |
| 476 if (GetDebugURL(*page->dict_).length()) { |
| 477 target->Inspect(Profile::FromBrowserContext(context_)); |
| 478 } |
| 479 } |
| 480 } |
| 481 } |
| 482 } |
| 483 pending_workers_.clear(); |
| 484 if (bridge_) |
| 485 bridge_->RemoveDeviceListListener(this); |
| 486 } |
| 487 |
| 404 void DevToolsAndroidBridge::AgentHostDelegate::OnSocketOpened() { | 488 void DevToolsAndroidBridge::AgentHostDelegate::OnSocketOpened() { |
| 405 socket_opened_ = true; | 489 socket_opened_ = true; |
| 406 for (std::vector<std::string>::iterator it = pending_messages_.begin(); | 490 for (std::vector<std::string>::iterator it = pending_messages_.begin(); |
| 407 it != pending_messages_.end(); ++it) { | 491 it != pending_messages_.end(); ++it) { |
| 408 SendMessageToBackend(*it); | 492 SendMessageToBackend(*it); |
| 409 } | 493 } |
| 410 pending_messages_.clear(); | 494 pending_messages_.clear(); |
| 411 } | 495 } |
| 412 | 496 |
| 413 void DevToolsAndroidBridge::AgentHostDelegate::OnFrameRead( | 497 void DevToolsAndroidBridge::AgentHostDelegate::OnFrameRead( |
| (...skipping 28 matching lines...) Expand all Loading... |
| 442 base::WeakPtr<DevToolsAndroidBridge> bridge_; | 526 base::WeakPtr<DevToolsAndroidBridge> bridge_; |
| 443 BrowserId browser_id_; | 527 BrowserId browser_id_; |
| 444 std::string debug_url_; | 528 std::string debug_url_; |
| 445 std::string frontend_url_; | 529 std::string frontend_url_; |
| 446 std::string remote_id_; | 530 std::string remote_id_; |
| 447 std::string remote_type_; | 531 std::string remote_type_; |
| 448 std::string local_id_; | 532 std::string local_id_; |
| 449 DISALLOW_COPY_AND_ASSIGN(RemotePageTarget); | 533 DISALLOW_COPY_AND_ASSIGN(RemotePageTarget); |
| 450 }; | 534 }; |
| 451 | 535 |
| 452 static std::string GetStringProperty(const base::DictionaryValue& value, | |
| 453 const std::string& name) { | |
| 454 std::string result; | |
| 455 value.GetString(name, &result); | |
| 456 return result; | |
| 457 } | |
| 458 | |
| 459 static std::string BuildUniqueTargetId( | |
| 460 const DevToolsAndroidBridge::BrowserId& browser_id, | |
| 461 const base::DictionaryValue& value) { | |
| 462 return base::StringPrintf("%s:%s:%s", browser_id.first.c_str(), | |
| 463 browser_id.second.c_str(), GetStringProperty(value, "id").c_str()); | |
| 464 } | |
| 465 | |
| 466 static std::string GetFrontendURL(const base::DictionaryValue& value) { | 536 static std::string GetFrontendURL(const base::DictionaryValue& value) { |
| 467 std::string frontend_url = GetStringProperty(value, "devtoolsFrontendUrl"); | 537 std::string frontend_url = GetStringProperty(value, "devtoolsFrontendUrl"); |
| 468 size_t ws_param = frontend_url.find("?ws"); | 538 size_t ws_param = frontend_url.find("?ws"); |
| 469 if (ws_param != std::string::npos) | 539 if (ws_param != std::string::npos) |
| 470 frontend_url = frontend_url.substr(0, ws_param); | 540 frontend_url = frontend_url.substr(0, ws_param); |
| 471 if (frontend_url.find("http:") == 0) | 541 if (frontend_url.find("http:") == 0) |
| 472 frontend_url = "https:" + frontend_url.substr(5); | 542 frontend_url = "https:" + frontend_url.substr(5); |
| 473 return frontend_url; | 543 return frontend_url; |
| 474 } | 544 } |
| 475 | 545 |
| 476 static std::string GetDebugURL(const base::DictionaryValue& value) { | |
| 477 std::string debug_url = GetStringProperty(value, "webSocketDebuggerUrl"); | |
| 478 | |
| 479 if (debug_url.find("ws://") == 0) | |
| 480 debug_url = debug_url.substr(5); | |
| 481 else | |
| 482 debug_url = std::string(); | |
| 483 return debug_url; | |
| 484 } | |
| 485 | 546 |
| 486 DevToolsAndroidBridge::RemotePageTarget::RemotePageTarget( | 547 DevToolsAndroidBridge::RemotePageTarget::RemotePageTarget( |
| 487 DevToolsAndroidBridge* bridge, | 548 DevToolsAndroidBridge* bridge, |
| 488 const BrowserId& browser_id, | 549 const BrowserId& browser_id, |
| 489 const base::DictionaryValue& value) | 550 const base::DictionaryValue& value) |
| 490 : DevToolsTargetImpl(AgentHostDelegate::GetOrCreateAgentHost( | 551 : DevToolsTargetImpl(AgentHostDelegate::GetOrCreateAgentHost( |
| 491 bridge, | 552 bridge, |
| 492 BuildUniqueTargetId(browser_id, value), | 553 BuildUniqueTargetId(browser_id, value), |
| 493 browser_id, | 554 browser_id, |
| 494 GetDebugURL(value))), | 555 GetDebugURL(value))), |
| (...skipping 432 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 927 device_providers.push_back( | 988 device_providers.push_back( |
| 928 new WebRTCDeviceProvider(profile_, signin_manager_, token_service_)); | 989 new WebRTCDeviceProvider(profile_, signin_manager_, token_service_)); |
| 929 } | 990 } |
| 930 | 991 |
| 931 device_manager_->SetDeviceProviders(device_providers); | 992 device_manager_->SetDeviceProviders(device_providers); |
| 932 if (NeedsDeviceListPolling()) { | 993 if (NeedsDeviceListPolling()) { |
| 933 StopDeviceListPolling(); | 994 StopDeviceListPolling(); |
| 934 StartDeviceListPolling(); | 995 StartDeviceListPolling(); |
| 935 } | 996 } |
| 936 } | 997 } |
| OLD | NEW |