| OLD | NEW |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 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/devtools_adb_bridge.h" | 5 #include "chrome/browser/devtools/devtools_adb_bridge.h" |
| 6 | 6 |
| 7 #include <map> | 7 #include <map> |
| 8 #include <vector> | 8 #include <vector> |
| 9 | 9 |
| 10 #include "base/base64.h" | 10 #include "base/base64.h" |
| 11 #include "base/bind.h" | 11 #include "base/bind.h" |
| 12 #include "base/command_line.h" | 12 #include "base/command_line.h" |
| 13 #include "base/compiler_specific.h" | 13 #include "base/compiler_specific.h" |
| 14 #include "base/json/json_reader.h" | 14 #include "base/json/json_reader.h" |
| 15 #include "base/lazy_instance.h" | 15 #include "base/lazy_instance.h" |
| 16 #include "base/logging.h" | 16 #include "base/logging.h" |
| 17 #include "base/memory/singleton.h" | 17 #include "base/memory/singleton.h" |
| 18 #include "base/message_loop/message_loop.h" | 18 #include "base/message_loop/message_loop.h" |
| 19 #include "base/strings/string_number_conversions.h" | 19 #include "base/strings/string_number_conversions.h" |
| 20 #include "base/strings/string_util.h" | 20 #include "base/strings/string_util.h" |
| 21 #include "base/strings/stringprintf.h" | 21 #include "base/strings/stringprintf.h" |
| 22 #include "base/strings/utf_string_conversions.h" | |
| 23 #include "base/threading/thread.h" | 22 #include "base/threading/thread.h" |
| 24 #include "base/values.h" | 23 #include "base/values.h" |
| 25 #include "chrome/browser/devtools/adb/android_rsa.h" | 24 #include "chrome/browser/devtools/adb/android_rsa.h" |
| 26 #include "chrome/browser/devtools/adb_client_socket.h" | 25 #include "chrome/browser/devtools/adb_client_socket.h" |
| 27 #include "chrome/browser/devtools/adb_web_socket.h" | 26 #include "chrome/browser/devtools/adb_web_socket.h" |
| 28 #include "chrome/browser/devtools/devtools_protocol.h" | 27 #include "chrome/browser/devtools/devtools_protocol.h" |
| 29 #include "chrome/browser/devtools/devtools_target_impl.h" | |
| 30 #include "chrome/browser/devtools/devtools_window.h" | 28 #include "chrome/browser/devtools/devtools_window.h" |
| 31 #include "chrome/browser/profiles/profile.h" | 29 #include "chrome/browser/profiles/profile.h" |
| 32 #include "components/browser_context_keyed_service/browser_context_dependency_ma
nager.h" | 30 #include "components/browser_context_keyed_service/browser_context_dependency_ma
nager.h" |
| 33 #include "content/public/browser/devtools_agent_host.h" | 31 #include "content/public/browser/devtools_agent_host.h" |
| 34 #include "content/public/browser/devtools_client_host.h" | 32 #include "content/public/browser/devtools_client_host.h" |
| 35 #include "content/public/browser/devtools_external_agent_proxy.h" | 33 #include "content/public/browser/devtools_external_agent_proxy.h" |
| 36 #include "content/public/browser/devtools_external_agent_proxy_delegate.h" | 34 #include "content/public/browser/devtools_external_agent_proxy_delegate.h" |
| 37 #include "content/public/browser/devtools_manager.h" | 35 #include "content/public/browser/devtools_manager.h" |
| 38 #include "crypto/rsa_private_key.h" | 36 #include "crypto/rsa_private_key.h" |
| 39 #include "net/base/escape.h" | |
| 40 #include "net/base/net_errors.h" | 37 #include "net/base/net_errors.h" |
| 41 | 38 |
| 42 using content::BrowserThread; | 39 using content::BrowserThread; |
| 43 | 40 |
| 44 namespace { | 41 namespace { |
| 45 | 42 |
| 46 const char kDeviceModelCommand[] = "shell:getprop ro.product.model"; | 43 const char kDeviceModelCommand[] = "shell:getprop ro.product.model"; |
| 47 const char kOpenedUnixSocketsCommand[] = "shell:cat /proc/net/unix"; | 44 const char kOpenedUnixSocketsCommand[] = "shell:cat /proc/net/unix"; |
| 48 const char kListProcessesCommand[] = "shell:ps"; | 45 const char kListProcessesCommand[] = "shell:ps"; |
| 49 const char kDumpsysCommand[] = "shell:dumpsys window policy"; | 46 const char kDumpsysCommand[] = "shell:dumpsys window policy"; |
| 50 const char kDumpsysScreenSizePrefix[] = "mStable="; | 47 const char kDumpsysScreenSizePrefix[] = "mStable="; |
| 51 | 48 |
| 52 const char kUnknownModel[] = "Offline"; | 49 const char kUnknownModel[] = "Offline"; |
| 53 | 50 |
| 54 const char kPageListRequest[] = "GET /json HTTP/1.1\r\n\r\n"; | 51 const char kPageListRequest[] = "GET /json HTTP/1.1\r\n\r\n"; |
| 55 const char kVersionRequest[] = "GET /json/version HTTP/1.1\r\n\r\n"; | 52 const char kVersionRequest[] = "GET /json/version HTTP/1.1\r\n\r\n"; |
| 56 const char kClosePageRequest[] = "GET /json/close/%s HTTP/1.1\r\n\r\n"; | 53 const char kClosePageRequest[] = "GET /json/close/%s HTTP/1.1\r\n\r\n"; |
| 57 const char kNewPageRequest[] = "GET /json/new HTTP/1.1\r\n\r\n"; | 54 const char kNewPageRequest[] = "GET /json/new HTTP/1.1\r\n\r\n"; |
| 58 const char kNewPageRequestWithURL[] = "GET /json/new?%s HTTP/1.1\r\n\r\n"; | |
| 59 const char kActivatePageRequest[] = | 55 const char kActivatePageRequest[] = |
| 60 "GET /json/activate/%s HTTP/1.1\r\n\r\n"; | 56 "GET /json/activate/%s HTTP/1.1\r\n\r\n"; |
| 61 const int kAdbPollingIntervalMs = 1000; | 57 const int kAdbPollingIntervalMs = 1000; |
| 62 | 58 |
| 63 const char kUrlParam[] = "url"; | 59 const char kUrlParam[] = "url"; |
| 64 const char kPageReloadCommand[] = "Page.reload"; | 60 const char kPageReloadCommand[] = "Page.reload"; |
| 65 const char kPageNavigateCommand[] = "Page.navigate"; | 61 const char kPageNavigateCommand[] = "Page.navigate"; |
| 66 | 62 |
| 67 const char kChromeProductName[] = "Chrome"; | |
| 68 const int kMinVersionNewWithURL = 32; | |
| 69 const int kNewPageNavigateDelayMs = 500; | |
| 70 | |
| 71 #if defined(DEBUG_DEVTOOLS) | 63 #if defined(DEBUG_DEVTOOLS) |
| 64 const char kChrome[] = "Chrome"; |
| 72 const char kLocalChrome[] = "Local Chrome"; | 65 const char kLocalChrome[] = "Local Chrome"; |
| 73 #endif // defined(DEBUG_DEVTOOLS) | 66 #endif // defined(DEBUG_DEVTOOLS) |
| 74 | 67 |
| 75 typedef DevToolsAdbBridge::Callback Callback; | 68 typedef DevToolsAdbBridge::Callback Callback; |
| 76 typedef std::vector<scoped_refptr<AndroidDevice> > | 69 typedef std::vector<scoped_refptr<AndroidDevice> > |
| 77 AndroidDevices; | 70 AndroidDevices; |
| 78 typedef base::Callback<void(const AndroidDevices&)> AndroidDevicesCallback; | 71 typedef base::Callback<void(const AndroidDevices&)> AndroidDevicesCallback; |
| 79 | 72 |
| 80 // AdbPagesCommand ------------------------------------------------------------ | 73 // AdbPagesCommand ------------------------------------------------------------ |
| 81 | 74 |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 180 // For desktop remote debugging. | 173 // For desktop remote debugging. |
| 181 if (devices_.back()->serial().empty()) { | 174 if (devices_.back()->serial().empty()) { |
| 182 scoped_refptr<AndroidDevice> device = | 175 scoped_refptr<AndroidDevice> device = |
| 183 devices_.back(); | 176 devices_.back(); |
| 184 device->set_model(kLocalChrome); | 177 device->set_model(kLocalChrome); |
| 185 remote_devices_->push_back( | 178 remote_devices_->push_back( |
| 186 new DevToolsAdbBridge::RemoteDevice(device)); | 179 new DevToolsAdbBridge::RemoteDevice(device)); |
| 187 scoped_refptr<DevToolsAdbBridge::RemoteBrowser> remote_browser = | 180 scoped_refptr<DevToolsAdbBridge::RemoteBrowser> remote_browser = |
| 188 new DevToolsAdbBridge::RemoteBrowser( | 181 new DevToolsAdbBridge::RemoteBrowser( |
| 189 adb_thread_, device, std::string()); | 182 adb_thread_, device, std::string()); |
| 190 remote_browser->set_product(kChromeProductName); | 183 remote_browser->set_product(kChrome); |
| 191 remote_devices_->back()->AddBrowser(remote_browser); | 184 remote_devices_->back()->AddBrowser(remote_browser); |
| 192 browsers_.push_back(remote_browser); | 185 browsers_.push_back(remote_browser); |
| 193 device->HttpQuery( | 186 device->HttpQuery( |
| 194 std::string(), kVersionRequest, | 187 std::string(), kVersionRequest, |
| 195 base::Bind(&AdbPagesCommand::ReceivedVersion, this)); | 188 base::Bind(&AdbPagesCommand::ReceivedVersion, this)); |
| 196 return; | 189 return; |
| 197 } | 190 } |
| 198 #endif // defined(DEBUG_DEVTOOLS) | 191 #endif // defined(DEBUG_DEVTOOLS) |
| 199 | 192 |
| 200 scoped_refptr<AndroidDevice> device = devices_.back(); | 193 scoped_refptr<AndroidDevice> device = devices_.back(); |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 312 DCHECK_EQ(adb_thread_->message_loop(), base::MessageLoop::current()); | 305 DCHECK_EQ(adb_thread_->message_loop(), base::MessageLoop::current()); |
| 313 scoped_refptr<DevToolsAdbBridge::RemoteBrowser> browser = browsers_.back(); | 306 scoped_refptr<DevToolsAdbBridge::RemoteBrowser> browser = browsers_.back(); |
| 314 browsers_.pop_back(); | 307 browsers_.pop_back(); |
| 315 if (result < 0) { | 308 if (result < 0) { |
| 316 ProcessSockets(); | 309 ProcessSockets(); |
| 317 return; | 310 return; |
| 318 } | 311 } |
| 319 | 312 |
| 320 scoped_ptr<base::Value> value(base::JSONReader::Read(response)); | 313 scoped_ptr<base::Value> value(base::JSONReader::Read(response)); |
| 321 base::ListValue* list_value; | 314 base::ListValue* list_value; |
| 322 if (value && value->GetAsList(&list_value)) { | 315 if (!value || !value->GetAsList(&list_value)) { |
| 323 browser->SetPageDescriptors(*list_value); | 316 ProcessSockets(); |
| 317 return; |
| 318 } |
| 319 |
| 320 base::Value* item; |
| 321 |
| 322 for (size_t i = 0; i < list_value->GetSize(); ++i) { |
| 323 list_value->Get(i, &item); |
| 324 base::DictionaryValue* dict; |
| 325 if (!item || !item->GetAsDictionary(&dict)) |
| 326 continue; |
| 327 browser->AddPage(new DevToolsAdbBridge::RemotePage( |
| 328 adb_thread_, browser->device(), browser->socket(), *dict)); |
| 324 } | 329 } |
| 325 ProcessSockets(); | 330 ProcessSockets(); |
| 326 } | 331 } |
| 327 | 332 |
| 328 void AdbPagesCommand::Respond() { | 333 void AdbPagesCommand::Respond() { |
| 329 callback_.Run(remote_devices_.release()); | 334 callback_.Run(remote_devices_.release()); |
| 330 } | 335 } |
| 331 | 336 |
| 332 void AdbPagesCommand::ParseSocketsList(const std::string& response) { | 337 void AdbPagesCommand::ParseSocketsList(const std::string& response) { |
| 333 // On Android, '/proc/net/unix' looks like this: | 338 // On Android, '/proc/net/unix' looks like this: |
| (...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 537 content::BrowserContext* context) const { | 542 content::BrowserContext* context) const { |
| 538 return new DevToolsAdbBridge::Wrapper(); | 543 return new DevToolsAdbBridge::Wrapper(); |
| 539 } | 544 } |
| 540 | 545 |
| 541 | 546 |
| 542 // AgentHostDelegate ---------------------------------------------------------- | 547 // AgentHostDelegate ---------------------------------------------------------- |
| 543 | 548 |
| 544 class AgentHostDelegate : public content::DevToolsExternalAgentProxyDelegate, | 549 class AgentHostDelegate : public content::DevToolsExternalAgentProxyDelegate, |
| 545 public AdbWebSocket::Delegate { | 550 public AdbWebSocket::Delegate { |
| 546 public: | 551 public: |
| 547 static void Create(const std::string& id, | |
| 548 scoped_refptr<DevToolsAdbBridge::RemoteBrowser> browser, | |
| 549 const std::string& debug_url, | |
| 550 const std::string& frontend_url, | |
| 551 Profile* profile) { | |
| 552 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 553 AgentHostDelegates::iterator it = | |
| 554 g_host_delegates.Get().find(id); | |
| 555 if (it != g_host_delegates.Get().end()) { | |
| 556 it->second->OpenFrontend(); | |
| 557 } else if (!frontend_url.empty()) { | |
| 558 new AgentHostDelegate( | |
| 559 id, browser->device(), browser->socket(), debug_url, | |
| 560 frontend_url, browser->adb_thread()->message_loop(), profile); | |
| 561 } | |
| 562 } | |
| 563 | |
| 564 private: | |
| 565 AgentHostDelegate( | 552 AgentHostDelegate( |
| 566 const std::string& id, | 553 const std::string& id, |
| 567 scoped_refptr<AndroidDevice> device, | 554 scoped_refptr<AndroidDevice> device, |
| 568 const std::string& socket_name, | 555 const std::string& socket_name, |
| 569 const std::string& debug_url, | 556 const std::string& debug_url, |
| 570 const std::string& frontend_url, | 557 const std::string& frontend_url, |
| 571 base::MessageLoop* adb_message_loop, | 558 base::MessageLoop* adb_message_loop, |
| 572 Profile* profile) | 559 Profile* profile) |
| 573 : id_(id), | 560 : id_(id), |
| 561 serial_(device->serial()), |
| 574 frontend_url_(frontend_url), | 562 frontend_url_(frontend_url), |
| 575 adb_message_loop_(adb_message_loop), | 563 adb_message_loop_(adb_message_loop), |
| 576 profile_(profile) { | 564 profile_(profile) { |
| 577 web_socket_ = new AdbWebSocket( | 565 web_socket_ = new AdbWebSocket( |
| 578 device, socket_name, debug_url, adb_message_loop, this); | 566 device, socket_name, debug_url, adb_message_loop, this); |
| 579 g_host_delegates.Get()[id] = this; | 567 g_host_delegates.Get()[id] = this; |
| 580 } | 568 } |
| 581 | 569 |
| 582 void OpenFrontend() { | 570 void OpenFrontend() { |
| 583 if (!proxy_) | 571 if (!proxy_) |
| 584 return; | 572 return; |
| 585 DevToolsWindow::OpenExternalFrontend( | 573 DevToolsWindow::OpenExternalFrontend( |
| 586 profile_, frontend_url_, proxy_->GetAgentHost().get()); | 574 profile_, frontend_url_, proxy_->GetAgentHost().get()); |
| 587 } | 575 } |
| 588 | 576 |
| 577 private: |
| 589 virtual ~AgentHostDelegate() { | 578 virtual ~AgentHostDelegate() { |
| 590 g_host_delegates.Get().erase(id_); | 579 g_host_delegates.Get().erase(id_); |
| 591 } | 580 } |
| 592 | 581 |
| 593 virtual void Attach() OVERRIDE {} | 582 virtual void Attach() OVERRIDE {} |
| 594 | 583 |
| 595 virtual void Detach() OVERRIDE { | 584 virtual void Detach() OVERRIDE { |
| 596 web_socket_->Disconnect(); | 585 web_socket_->Disconnect(); |
| 597 } | 586 } |
| 598 | 587 |
| (...skipping 14 matching lines...) Expand all Loading... |
| 613 if (proxy_ && closed_by_device) | 602 if (proxy_ && closed_by_device) |
| 614 proxy_->ConnectionClosed(); | 603 proxy_->ConnectionClosed(); |
| 615 delete this; | 604 delete this; |
| 616 } | 605 } |
| 617 | 606 |
| 618 virtual bool ProcessIncomingMessage(const std::string& message) OVERRIDE { | 607 virtual bool ProcessIncomingMessage(const std::string& message) OVERRIDE { |
| 619 return false; | 608 return false; |
| 620 } | 609 } |
| 621 | 610 |
| 622 const std::string id_; | 611 const std::string id_; |
| 612 const std::string serial_; |
| 623 const std::string frontend_url_; | 613 const std::string frontend_url_; |
| 624 base::MessageLoop* adb_message_loop_; | 614 base::MessageLoop* adb_message_loop_; |
| 625 Profile* profile_; | 615 Profile* profile_; |
| 626 | 616 |
| 627 scoped_ptr<content::DevToolsExternalAgentProxy> proxy_; | 617 scoped_ptr<content::DevToolsExternalAgentProxy> proxy_; |
| 628 scoped_refptr<AdbWebSocket> web_socket_; | 618 scoped_refptr<AdbWebSocket> web_socket_; |
| 629 DISALLOW_COPY_AND_ASSIGN(AgentHostDelegate); | 619 DISALLOW_COPY_AND_ASSIGN(AgentHostDelegate); |
| 630 }; | 620 }; |
| 631 | 621 |
| 632 //// RemotePageTarget ---------------------------------------------- | |
| 633 | 622 |
| 634 class RemotePageTarget : public DevToolsTargetImpl { | 623 // DevToolsAdbBridge::RemotePage ---------------------------------------------- |
| 635 public: | |
| 636 RemotePageTarget(scoped_refptr<DevToolsAdbBridge::RemoteBrowser> browser, | |
| 637 const base::DictionaryValue& value); | |
| 638 virtual ~RemotePageTarget(); | |
| 639 | 624 |
| 640 // content::DevToolsTarget overrides: | 625 DevToolsAdbBridge::RemotePage::RemotePage( |
| 641 virtual bool IsAttached() const OVERRIDE; | 626 scoped_refptr<RefCountedAdbThread> adb_thread, |
| 642 virtual bool Activate() const OVERRIDE; | 627 scoped_refptr<AndroidDevice> device, |
| 643 virtual bool Close() const OVERRIDE; | 628 const std::string& socket, |
| 644 | |
| 645 // DevToolsTargetImpl overrides: | |
| 646 virtual void Inspect(Profile* profile) const OVERRIDE; | |
| 647 virtual void Reload() const OVERRIDE; | |
| 648 | |
| 649 void Navigate(const std::string& url) const; | |
| 650 | |
| 651 private: | |
| 652 scoped_refptr<DevToolsAdbBridge::RemoteBrowser> browser_; | |
| 653 std::string debug_url_; | |
| 654 std::string frontend_url_; | |
| 655 std::string agent_id_; | |
| 656 DISALLOW_COPY_AND_ASSIGN(RemotePageTarget); | |
| 657 }; | |
| 658 | |
| 659 RemotePageTarget::RemotePageTarget( | |
| 660 scoped_refptr<DevToolsAdbBridge::RemoteBrowser> browser, | |
| 661 const base::DictionaryValue& value) | 629 const base::DictionaryValue& value) |
| 662 : browser_(browser) { | 630 : adb_thread_(adb_thread), |
| 663 type_ = "adb_page"; | 631 device_(device), |
| 632 socket_(socket) { |
| 664 value.GetString("id", &id_); | 633 value.GetString("id", &id_); |
| 665 std::string url; | 634 value.GetString("url", &url_); |
| 666 value.GetString("url", &url); | |
| 667 url_ = GURL(url); | |
| 668 value.GetString("title", &title_); | 635 value.GetString("title", &title_); |
| 669 title_ = UTF16ToUTF8(net::UnescapeForHTML(UTF8ToUTF16(title_))); | |
| 670 value.GetString("description", &description_); | 636 value.GetString("description", &description_); |
| 671 std::string favicon_url; | 637 value.GetString("faviconUrl", &favicon_url_); |
| 672 value.GetString("faviconUrl", &favicon_url); | |
| 673 favicon_url_ = GURL(favicon_url); | |
| 674 value.GetString("webSocketDebuggerUrl", &debug_url_); | 638 value.GetString("webSocketDebuggerUrl", &debug_url_); |
| 675 value.GetString("devtoolsFrontendUrl", &frontend_url_); | 639 value.GetString("devtoolsFrontendUrl", &frontend_url_); |
| 676 | 640 |
| 677 if (id_.empty() && !debug_url_.empty()) { | 641 if (id_.empty() && !debug_url_.empty()) { |
| 678 // Target id is not available until Chrome 26. Use page id at the end of | 642 // Target id is not available until Chrome 26. Use page id at the end of |
| 679 // debug_url_ instead. For attached targets the id will remain empty. | 643 // debug_url_ instead. For attached targets the id will remain empty. |
| 680 std::vector<std::string> parts; | 644 std::vector<std::string> parts; |
| 681 Tokenize(debug_url_, "/", &parts); | 645 Tokenize(debug_url_, "/", &parts); |
| 682 id_ = parts[parts.size()-1]; | 646 id_ = parts[parts.size()-1]; |
| 683 } | 647 } |
| 684 | 648 |
| 685 if (debug_url_.find("ws://") == 0) | 649 if (debug_url_.find("ws://") == 0) |
| 686 debug_url_ = debug_url_.substr(5); | 650 debug_url_ = debug_url_.substr(5); |
| 687 else | 651 else |
| 688 debug_url_ = ""; | 652 debug_url_ = ""; |
| 689 | 653 |
| 690 size_t ws_param = frontend_url_.find("?ws"); | 654 size_t ws_param = frontend_url_.find("?ws"); |
| 691 if (ws_param != std::string::npos) | 655 if (ws_param != std::string::npos) |
| 692 frontend_url_ = frontend_url_.substr(0, ws_param); | 656 frontend_url_ = frontend_url_.substr(0, ws_param); |
| 693 if (frontend_url_.find("http:") == 0) | 657 if (frontend_url_.find("http:") == 0) |
| 694 frontend_url_ = "https:" + frontend_url_.substr(5); | 658 frontend_url_ = "https:" + frontend_url_.substr(5); |
| 695 | 659 |
| 696 agent_id_ = base::StringPrintf("%s:%s:%s", | 660 agent_id_ = base::StringPrintf("%s:%s:%s", |
| 697 browser_->device()->serial().c_str(), | 661 device_->serial().c_str(), socket_.c_str(), id_.c_str()); |
| 698 browser_->socket().c_str(), | |
| 699 id_.c_str()); | |
| 700 } | 662 } |
| 701 | 663 |
| 702 RemotePageTarget::~RemotePageTarget() { | 664 bool DevToolsAdbBridge::RemotePage::HasDevToolsWindow() { |
| 665 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 666 return g_host_delegates.Get().find(agent_id_) != g_host_delegates.Get().end(); |
| 703 } | 667 } |
| 704 | 668 |
| 705 bool RemotePageTarget::IsAttached() const { | 669 void DevToolsAdbBridge::RemotePage::Inspect(Profile* profile) { |
| 706 return debug_url_.empty(); | 670 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 671 RequestActivate( |
| 672 base::Bind(&RemotePage::InspectOnHandlerThread, this, profile)); |
| 707 } | 673 } |
| 708 | 674 |
| 709 void RemotePageTarget::Inspect(Profile* profile) const { | 675 static void Noop(int, const std::string&) {} |
| 710 std::string request = base::StringPrintf(kActivatePageRequest, id_.c_str()); | 676 |
| 711 base::Closure inspect_callback = base::Bind(&AgentHostDelegate::Create, | 677 void DevToolsAdbBridge::RemotePage::Activate() { |
| 712 id_, browser_, debug_url_, frontend_url_, profile); | 678 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 713 browser_->SendJsonRequest(request, inspect_callback); | 679 RequestActivate(base::Bind(&Noop)); |
| 714 } | 680 } |
| 715 | 681 |
| 716 bool RemotePageTarget::Activate() const { | 682 void DevToolsAdbBridge::RemotePage::Close() { |
| 717 std::string request = base::StringPrintf(kActivatePageRequest, id_.c_str()); | 683 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 718 browser_->SendJsonRequest(request, base::Closure()); | 684 if (attached()) |
| 719 return true; | 685 return; |
| 686 std::string request = base::StringPrintf(kClosePageRequest, id_.c_str()); |
| 687 adb_thread_->message_loop()->PostTask(FROM_HERE, |
| 688 base::Bind(&AndroidDevice::HttpQuery, |
| 689 device_, socket_, request, base::Bind(&Noop))); |
| 720 } | 690 } |
| 721 | 691 |
| 722 bool RemotePageTarget::Close() const { | 692 void DevToolsAdbBridge::RemotePage::Reload() { |
| 723 if (IsAttached()) | 693 SendProtocolCommand(kPageReloadCommand, NULL); |
| 724 return false; | |
| 725 std::string request = base::StringPrintf(kClosePageRequest, id_.c_str()); | |
| 726 browser_->SendJsonRequest(request, base::Closure()); | |
| 727 return true; | |
| 728 } | 694 } |
| 729 | 695 |
| 730 void RemotePageTarget::Reload() const { | 696 void DevToolsAdbBridge::RemotePage::SendProtocolCommand( |
| 731 browser_->SendProtocolCommand(debug_url_, kPageReloadCommand, NULL); | 697 const std::string& method, |
| 698 base::DictionaryValue* params) { |
| 699 if (attached()) |
| 700 return; |
| 701 DevToolsProtocol::Command command(1, method, params); |
| 702 new AdbProtocolCommand( |
| 703 adb_thread_, device_, socket_, debug_url_, command.Serialize()); |
| 732 } | 704 } |
| 733 | 705 |
| 734 void RemotePageTarget::Navigate(const std::string& url) const { | 706 DevToolsAdbBridge::RemotePage::~RemotePage() { |
| 735 base::DictionaryValue params; | |
| 736 params.SetString(kUrlParam, url); | |
| 737 browser_->SendProtocolCommand(debug_url_, kPageNavigateCommand, ¶ms); | |
| 738 } | 707 } |
| 739 | 708 |
| 709 void DevToolsAdbBridge::RemotePage::RequestActivate( |
| 710 const AndroidDevice::CommandCallback& callback) { |
| 711 std::string request = base::StringPrintf(kActivatePageRequest, id_.c_str()); |
| 712 adb_thread_->message_loop()->PostTask(FROM_HERE, |
| 713 base::Bind(&AndroidDevice::HttpQuery, |
| 714 device_, socket_, request, callback)); |
| 715 } |
| 716 |
| 717 void DevToolsAdbBridge::RemotePage::InspectOnHandlerThread( |
| 718 Profile* profile, int result, const std::string& response) { |
| 719 BrowserThread::PostTask( |
| 720 BrowserThread::UI, FROM_HERE, |
| 721 base::Bind(&RemotePage::InspectOnUIThread, this, profile)); |
| 722 } |
| 723 |
| 724 void DevToolsAdbBridge::RemotePage::InspectOnUIThread(Profile* profile) { |
| 725 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 726 AgentHostDelegates::iterator it = |
| 727 g_host_delegates.Get().find(agent_id_); |
| 728 if (it != g_host_delegates.Get().end()) { |
| 729 it->second->OpenFrontend(); |
| 730 } else if (!attached()) { |
| 731 new AgentHostDelegate( |
| 732 agent_id_, device_, socket_, debug_url_, |
| 733 frontend_url_, adb_thread_->message_loop(), profile); |
| 734 } |
| 735 } |
| 736 |
| 737 |
| 740 // DevToolsAdbBridge::RemoteBrowser ------------------------------------------- | 738 // DevToolsAdbBridge::RemoteBrowser ------------------------------------------- |
| 741 | 739 |
| 742 DevToolsAdbBridge::RemoteBrowser::RemoteBrowser( | 740 DevToolsAdbBridge::RemoteBrowser::RemoteBrowser( |
| 743 scoped_refptr<RefCountedAdbThread> adb_thread, | 741 scoped_refptr<RefCountedAdbThread> adb_thread, |
| 744 scoped_refptr<AndroidDevice> device, | 742 scoped_refptr<AndroidDevice> device, |
| 745 const std::string& socket) | 743 const std::string& socket) |
| 746 : adb_thread_(adb_thread), | 744 : adb_thread_(adb_thread), |
| 747 device_(device), | 745 device_(device), |
| 748 socket_(socket) { | 746 socket_(socket) { |
| 749 } | 747 } |
| 750 | 748 |
| 751 bool DevToolsAdbBridge::RemoteBrowser::IsChrome() const { | 749 void DevToolsAdbBridge::RemoteBrowser::Open(const std::string& url) { |
| 752 return product_.find(kChromeProductName) == 0; | |
| 753 } | |
| 754 | |
| 755 DevToolsAdbBridge::RemoteBrowser::ParsedVersion | |
| 756 DevToolsAdbBridge::RemoteBrowser::GetParsedVersion() const { | |
| 757 ParsedVersion result; | |
| 758 std::vector<std::string> parts; | |
| 759 Tokenize(version_, ".", &parts); | |
| 760 for (size_t i = 0; i != parts.size(); ++i) { | |
| 761 int value = 0; | |
| 762 base::StringToInt(parts[i], &value); | |
| 763 result.push_back(value); | |
| 764 } | |
| 765 return result; | |
| 766 } | |
| 767 | |
| 768 std::vector<DevToolsTargetImpl*> | |
| 769 DevToolsAdbBridge::RemoteBrowser::CreatePageTargets() { | |
| 770 std::vector<DevToolsTargetImpl*> result; | |
| 771 for (size_t i = 0; i < page_descriptors_->GetSize(); ++i) { | |
| 772 base::Value* item; | |
| 773 page_descriptors_->Get(i, &item); | |
| 774 if (!item) | |
| 775 continue; | |
| 776 base::DictionaryValue* dict; | |
| 777 if (!item->GetAsDictionary(&dict)) | |
| 778 continue; | |
| 779 result.push_back(new RemotePageTarget(this, *dict)); | |
| 780 } | |
| 781 return result; | |
| 782 } | |
| 783 | |
| 784 void DevToolsAdbBridge::RemoteBrowser::SetPageDescriptors( | |
| 785 const base::ListValue& list) { | |
| 786 page_descriptors_.reset(list.DeepCopy()); | |
| 787 } | |
| 788 | |
| 789 static void RespondOnUIThread(base::Closure callback, int, const std::string&) { | |
| 790 if (!callback.is_null()) | |
| 791 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback); | |
| 792 } | |
| 793 | |
| 794 void DevToolsAdbBridge::RemoteBrowser::SendJsonRequest( | |
| 795 const std::string& request, base::Closure callback) { | |
| 796 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 797 adb_thread_->message_loop()->PostTask(FROM_HERE, | 750 adb_thread_->message_loop()->PostTask(FROM_HERE, |
| 798 base::Bind(&AndroidDevice::HttpQuery, device_, socket_, request, | 751 base::Bind(&AndroidDevice::HttpQuery, |
| 799 base::Bind(&RespondOnUIThread, callback))); | 752 device_, socket_, kNewPageRequest, |
| 800 } | 753 base::Bind(&RemoteBrowser::PageCreatedOnHandlerThread, this, url))); |
| 801 | |
| 802 void DevToolsAdbBridge::RemoteBrowser::SendProtocolCommand( | |
| 803 const std::string& debug_url, | |
| 804 const std::string& method, | |
| 805 base::DictionaryValue* params) { | |
| 806 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 807 if (debug_url.empty()) | |
| 808 return; | |
| 809 DevToolsProtocol::Command command(1, method, params); | |
| 810 new AdbProtocolCommand( | |
| 811 adb_thread_, device_, socket_, debug_url, command.Serialize()); | |
| 812 } | |
| 813 | |
| 814 static void NoOp(int, const std::string&) {} | |
| 815 | |
| 816 void DevToolsAdbBridge::RemoteBrowser::Open(const std::string& url) { | |
| 817 ParsedVersion parsed_version = GetParsedVersion(); | |
| 818 if (IsChrome() && | |
| 819 !parsed_version.empty() && | |
| 820 parsed_version[0] >= kMinVersionNewWithURL) { | |
| 821 std::string query = net::EscapeQueryParamValue(url, false /* use_plus */); | |
| 822 std::string request = | |
| 823 base::StringPrintf(kNewPageRequestWithURL, query.c_str()); | |
| 824 adb_thread_->message_loop()->PostTask(FROM_HERE, | |
| 825 base::Bind(&AndroidDevice::HttpQuery, | |
| 826 device_, socket_, request, base::Bind(&NoOp))); | |
| 827 } else { | |
| 828 adb_thread_->message_loop()->PostTask(FROM_HERE, | |
| 829 base::Bind(&AndroidDevice::HttpQuery, | |
| 830 device_, socket_, kNewPageRequest, | |
| 831 base::Bind(&RemoteBrowser::PageCreatedOnHandlerThread, this, url))); | |
| 832 } | |
| 833 } | 754 } |
| 834 | 755 |
| 835 void DevToolsAdbBridge::RemoteBrowser::PageCreatedOnHandlerThread( | 756 void DevToolsAdbBridge::RemoteBrowser::PageCreatedOnHandlerThread( |
| 836 const std::string& url, int result, const std::string& response) { | 757 const std::string& url, int result, const std::string& response) { |
| 837 if (result < 0) | 758 if (result < 0) |
| 838 return; | 759 return; |
| 839 // Navigating too soon after the page creation breaks navigation history | 760 BrowserThread::PostTask( |
| 840 // (crbug.com/311014). This can be avoided by adding a moderate delay. | |
| 841 BrowserThread::PostDelayedTask( | |
| 842 BrowserThread::UI, FROM_HERE, | 761 BrowserThread::UI, FROM_HERE, |
| 843 base::Bind(&RemoteBrowser::PageCreatedOnUIThread, this, response, url), | 762 base::Bind(&RemoteBrowser::PageCreatedOnUIThread, this, response, url)); |
| 844 base::TimeDelta::FromMilliseconds(kNewPageNavigateDelayMs)); | |
| 845 } | 763 } |
| 846 | 764 |
| 847 void DevToolsAdbBridge::RemoteBrowser::PageCreatedOnUIThread( | 765 void DevToolsAdbBridge::RemoteBrowser::PageCreatedOnUIThread( |
| 848 const std::string& response, const std::string& url) { | 766 const std::string& response, const std::string& url) { |
| 849 scoped_ptr<base::Value> value(base::JSONReader::Read(response)); | 767 scoped_ptr<base::Value> value(base::JSONReader::Read(response)); |
| 850 base::DictionaryValue* dict; | 768 base::DictionaryValue* dict; |
| 851 if (value && value->GetAsDictionary(&dict)) { | 769 if (value && value->GetAsDictionary(&dict)) { |
| 852 RemotePageTarget new_page(this, *dict); | 770 scoped_refptr<RemotePage> new_page = |
| 853 new_page.Navigate(url); | 771 new RemotePage(adb_thread_, device_, socket_, *dict); |
| 772 base::DictionaryValue params; |
| 773 params.SetString(kUrlParam, url); |
| 774 new_page->SendProtocolCommand(kPageNavigateCommand, ¶ms); |
| 854 } | 775 } |
| 855 } | 776 } |
| 856 | 777 |
| 857 DevToolsAdbBridge::RemoteBrowser::~RemoteBrowser() { | 778 DevToolsAdbBridge::RemoteBrowser::~RemoteBrowser() { |
| 858 } | 779 } |
| 859 | 780 |
| 860 | 781 |
| 861 // DevToolsAdbBridge::RemoteDevice -------------------------------------------- | 782 // DevToolsAdbBridge::RemoteDevice -------------------------------------------- |
| 862 | 783 |
| 863 DevToolsAdbBridge::RemoteDevice::RemoteDevice( | 784 DevToolsAdbBridge::RemoteDevice::RemoteDevice( |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 901 } | 822 } |
| 902 | 823 |
| 903 void DevToolsAdbBridge::RemoveListener(Listener* listener) { | 824 void DevToolsAdbBridge::RemoveListener(Listener* listener) { |
| 904 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 825 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 905 Listeners::iterator it = | 826 Listeners::iterator it = |
| 906 std::find(listeners_.begin(), listeners_.end(), listener); | 827 std::find(listeners_.begin(), listeners_.end(), listener); |
| 907 DCHECK(it != listeners_.end()); | 828 DCHECK(it != listeners_.end()); |
| 908 listeners_.erase(it); | 829 listeners_.erase(it); |
| 909 } | 830 } |
| 910 | 831 |
| 911 bool DevToolsAdbBridge::HasDevToolsWindow(const std::string& agent_id) { | |
| 912 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 913 return g_host_delegates.Get().find(agent_id) != g_host_delegates.Get().end(); | |
| 914 } | |
| 915 | |
| 916 DevToolsAdbBridge::~DevToolsAdbBridge() { | 832 DevToolsAdbBridge::~DevToolsAdbBridge() { |
| 917 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 833 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 918 DCHECK(listeners_.empty()); | 834 DCHECK(listeners_.empty()); |
| 919 } | 835 } |
| 920 | 836 |
| 921 void DevToolsAdbBridge::RequestRemoteDevices() { | 837 void DevToolsAdbBridge::RequestRemoteDevices() { |
| 922 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 838 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 923 if (!has_message_loop_) | 839 if (!has_message_loop_) |
| 924 return; | 840 return; |
| 925 | 841 |
| (...skipping 13 matching lines...) Expand all Loading... |
| 939 | 855 |
| 940 if (listeners_.empty()) | 856 if (listeners_.empty()) |
| 941 return; | 857 return; |
| 942 | 858 |
| 943 BrowserThread::PostDelayedTask( | 859 BrowserThread::PostDelayedTask( |
| 944 BrowserThread::UI, | 860 BrowserThread::UI, |
| 945 FROM_HERE, | 861 FROM_HERE, |
| 946 base::Bind(&DevToolsAdbBridge::RequestRemoteDevices, this), | 862 base::Bind(&DevToolsAdbBridge::RequestRemoteDevices, this), |
| 947 base::TimeDelta::FromMilliseconds(kAdbPollingIntervalMs)); | 863 base::TimeDelta::FromMilliseconds(kAdbPollingIntervalMs)); |
| 948 } | 864 } |
| OLD | NEW |