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 |