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
3 // found in the LICENSE file.
5 #include "chrome/browser/devtools/device/devtools_android_bridge.h"
10 #include "base/base64.h"
11 #include "base/bind.h"
12 #include "base/command_line.h"
13 #include "base/compiler_specific.h"
14 #include "base/json/json_reader.h"
15 #include "base/lazy_instance.h"
16 #include "base/memory/singleton.h"
17 #include "base/message_loop/message_loop.h"
18 #include "base/prefs/pref_service.h"
19 #include "base/strings/string_number_conversions.h"
20 #include "base/strings/string_util.h"
21 #include "base/strings/stringprintf.h"
22 #include "base/strings/utf_string_conversions.h"
23 #include "base/threading/thread.h"
24 #include "base/values.h"
25 #include "chrome/browser/devtools/device/adb/adb_device_provider.h"
26 #include "chrome/browser/devtools/device/port_forwarding_controller.h"
27 #include "chrome/browser/devtools/device/self_device_provider.h"
28 #include "chrome/browser/devtools/device/usb/usb_device_provider.h"
29 #include "chrome/browser/devtools/device/webrtc/webrtc_device_provider.h"
30 #include "chrome/browser/devtools/devtools_protocol.h"
31 #include "chrome/browser/devtools/devtools_target_impl.h"
32 #include "chrome/browser/devtools/devtools_window.h"
33 #include "chrome/browser/devtools/remote_debugging_server.h"
34 #include "chrome/browser/profiles/profile.h"
35 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
36 #include "chrome/browser/signin/signin_manager_factory.h"
37 #include "chrome/common/chrome_switches.h"
38 #include "chrome/common/pref_names.h"
39 #include "components/keyed_service/content/browser_context_dependency_manager.h"
40 #include "components/signin/core/browser/profile_oauth2_token_service.h"
41 #include "components/signin/core/browser/signin_manager.h"
42 #include "content/public/browser/devtools_agent_host.h"
43 #include "content/public/browser/devtools_external_agent_proxy.h"
44 #include "content/public/browser/devtools_external_agent_proxy_delegate.h"
45 #include "content/public/browser/user_metrics.h"
46 #include "net/base/escape.h"
47 #include "net/base/net_errors.h"
49 using content::BrowserThread
;
53 const char kPageListRequest
[] = "/json";
54 const char kVersionRequest
[] = "/json/version";
55 const char kClosePageRequest
[] = "/json/close/%s";
56 const char kNewPageRequestWithURL
[] = "/json/new?%s";
57 const char kActivatePageRequest
[] = "/json/activate/%s";
58 const char kBrowserTargetSocket
[] = "/devtools/browser";
59 const int kAdbPollingIntervalMs
= 1000;
61 const char kPageReloadCommand
[] = "Page.reload";
63 const char kWebViewSocketPrefix
[] = "webview_devtools_remote";
65 bool IsWebRTCDeviceProviderEnabled() {
66 return base::CommandLine::ForCurrentProcess()->HasSwitch(
67 switches::kEnableDevToolsExperiments
);
70 bool BrowserIdFromString(const std::string
& browser_id_str
,
71 DevToolsAndroidBridge::BrowserId
* browser_id
) {
72 size_t colon_pos
= browser_id_str
.find(':');
73 if (colon_pos
== std::string::npos
)
75 browser_id
->first
= browser_id_str
.substr(0, colon_pos
);
76 browser_id
->second
= browser_id_str
.substr(colon_pos
+ 1);
82 // DiscoveryRequest -----------------------------------------------------
84 class DevToolsAndroidBridge::DiscoveryRequest
85 : public base::RefCountedThreadSafe
<DiscoveryRequest
,
86 BrowserThread::DeleteOnUIThread
> {
88 DiscoveryRequest(AndroidDeviceManager
* device_manager
,
89 const DeviceListCallback
& callback
);
91 friend struct BrowserThread::DeleteOnThread
<BrowserThread::UI
>;
92 friend class base::DeleteHelper
<DiscoveryRequest
>;
93 virtual ~DiscoveryRequest();
95 void ReceivedDevices(const AndroidDeviceManager::Devices
& devices
);
96 void ReceivedDeviceInfo(scoped_refptr
<AndroidDeviceManager::Device
> device
,
97 const AndroidDeviceManager::DeviceInfo
& device_info
);
98 void ReceivedVersion(scoped_refptr
<RemoteBrowser
>,
100 const std::string
& response
);
101 void ReceivedPages(scoped_refptr
<RemoteBrowser
>,
103 const std::string
& response
);
105 DeviceListCallback callback_
;
106 CompleteDevices complete_devices_
;
109 DevToolsAndroidBridge::DiscoveryRequest::DiscoveryRequest(
110 AndroidDeviceManager
* device_manager
,
111 const DeviceListCallback
& callback
)
112 : callback_(callback
) {
113 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
114 device_manager
->QueryDevices(
115 base::Bind(&DiscoveryRequest::ReceivedDevices
, this));
118 DevToolsAndroidBridge::DiscoveryRequest::~DiscoveryRequest() {
119 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
120 callback_
.Run(complete_devices_
);
123 void DevToolsAndroidBridge::DiscoveryRequest::ReceivedDevices(
124 const AndroidDeviceManager::Devices
& devices
) {
125 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
126 for (const auto& device
: devices
) {
127 device
->QueryDeviceInfo(
128 base::Bind(&DiscoveryRequest::ReceivedDeviceInfo
, this, device
));
132 void DevToolsAndroidBridge::DiscoveryRequest::ReceivedDeviceInfo(
133 scoped_refptr
<AndroidDeviceManager::Device
> device
,
134 const AndroidDeviceManager::DeviceInfo
& device_info
) {
135 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
136 scoped_refptr
<RemoteDevice
> remote_device
=
137 new RemoteDevice(device
->serial(), device_info
);
138 complete_devices_
.push_back(std::make_pair(device
, remote_device
));
139 for (RemoteBrowsers::iterator it
= remote_device
->browsers().begin();
140 it
!= remote_device
->browsers().end(); ++it
) {
141 device
->SendJsonRequest(
144 base::Bind(&DiscoveryRequest::ReceivedVersion
, this, *it
));
145 device
->SendJsonRequest(
148 base::Bind(&DiscoveryRequest::ReceivedPages
, this, *it
));
152 void DevToolsAndroidBridge::DiscoveryRequest::ReceivedVersion(
153 scoped_refptr
<RemoteBrowser
> browser
,
155 const std::string
& response
) {
156 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
159 // Parse version, append to package name if available,
160 scoped_ptr
<base::Value
> value(base::JSONReader::Read(response
));
161 base::DictionaryValue
* dict
;
162 if (value
&& value
->GetAsDictionary(&dict
)) {
163 std::string browser_name
;
164 if (dict
->GetString("Browser", &browser_name
)) {
165 std::vector
<std::string
> parts
;
166 Tokenize(browser_name
, "/", &parts
);
167 if (parts
.size() == 2)
168 browser
->version_
= parts
[1];
170 browser
->version_
= browser_name
;
173 if (dict
->GetString("Android-Package", &package
)) {
174 browser
->display_name_
=
175 AndroidDeviceManager::GetBrowserName(browser
->socket(), package
);
180 void DevToolsAndroidBridge::DiscoveryRequest::ReceivedPages(
181 scoped_refptr
<RemoteBrowser
> browser
,
183 const std::string
& response
) {
184 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
187 scoped_ptr
<base::Value
> value(base::JSONReader::Read(response
));
188 base::ListValue
* list_value
;
189 if (value
&& value
->GetAsList(&list_value
)) {
190 for (const auto& page_value
: *list_value
) {
191 base::DictionaryValue
* dict
;
192 if (page_value
->GetAsDictionary(&dict
))
193 browser
->pages_
.push_back(new RemotePage(browser
->browser_id_
, *dict
));
198 // ProtocolCommand ------------------------------------------------------------
202 class ProtocolCommand
203 : public AndroidDeviceManager::AndroidWebSocket::Delegate
{
206 scoped_refptr
<AndroidDeviceManager::Device
> device
,
207 const std::string
& socket
,
208 const std::string
& debug_url
,
209 const std::string
& command
,
210 const base::Closure callback
);
213 void OnSocketOpened() override
;
214 void OnFrameRead(const std::string
& message
) override
;
215 void OnSocketClosed() override
;
216 ~ProtocolCommand() override
;
218 const std::string command_
;
219 const base::Closure callback_
;
220 scoped_ptr
<AndroidDeviceManager::AndroidWebSocket
> web_socket_
;
222 DISALLOW_COPY_AND_ASSIGN(ProtocolCommand
);
225 ProtocolCommand::ProtocolCommand(
226 scoped_refptr
<AndroidDeviceManager::Device
> device
,
227 const std::string
& socket
,
228 const std::string
& debug_url
,
229 const std::string
& command
,
230 const base::Closure callback
)
233 web_socket_(device
->CreateWebSocket(socket
, debug_url
, this)) {
236 void ProtocolCommand::OnSocketOpened() {
237 web_socket_
->SendFrame(command_
);
240 void ProtocolCommand::OnFrameRead(const std::string
& message
) {
244 void ProtocolCommand::OnSocketClosed() {
248 ProtocolCommand::~ProtocolCommand() {
249 if (!callback_
.is_null())
256 DevToolsAndroidBridge::Factory
* DevToolsAndroidBridge::Factory::GetInstance() {
257 return Singleton
<DevToolsAndroidBridge::Factory
>::get();
261 DevToolsAndroidBridge
* DevToolsAndroidBridge::Factory::GetForProfile(
263 return static_cast<DevToolsAndroidBridge
*>(GetInstance()->
264 GetServiceForBrowserContext(profile
, true));
267 DevToolsAndroidBridge::Factory::Factory()
268 : BrowserContextKeyedServiceFactory(
269 "DevToolsAndroidBridge",
270 BrowserContextDependencyManager::GetInstance()) {
271 if (IsWebRTCDeviceProviderEnabled()) {
272 DependsOn(ProfileOAuth2TokenServiceFactory::GetInstance());
273 DependsOn(SigninManagerFactory::GetInstance());
277 DevToolsAndroidBridge::Factory::~Factory() {}
279 KeyedService
* DevToolsAndroidBridge::Factory::BuildServiceInstanceFor(
280 content::BrowserContext
* context
) const {
281 Profile
* profile
= Profile::FromBrowserContext(context
);
283 ProfileOAuth2TokenService
* token_service
= nullptr;
284 SigninManagerBase
* signin_manager
= nullptr;
286 if (IsWebRTCDeviceProviderEnabled()) {
287 token_service
= ProfileOAuth2TokenServiceFactory::GetForProfile(profile
);
288 signin_manager
= SigninManagerFactory::GetForProfile(profile
);
291 return new DevToolsAndroidBridge(
292 profile
, signin_manager
, token_service
);
295 // AgentHostDelegate ----------------------------------------------------------
297 class DevToolsAndroidBridge::AgentHostDelegate
298 : public content::DevToolsExternalAgentProxyDelegate
,
299 public AndroidDeviceManager::AndroidWebSocket::Delegate
{
301 static scoped_refptr
<content::DevToolsAgentHost
> GetOrCreateAgentHost(
302 DevToolsAndroidBridge
* bridge
,
303 const std::string
& id
,
304 const BrowserId
& browser_id
,
305 const std::string
& debug_url
);
309 DevToolsAndroidBridge
* bridge
,
310 const std::string
& id
,
311 const BrowserId
& browser_id
,
312 const std::string
& debug_url
);
313 ~AgentHostDelegate() override
;
314 void Attach(content::DevToolsExternalAgentProxy
* proxy
) override
;
315 void Detach() override
;
316 void SendMessageToBackend(const std::string
& message
) override
;
317 void OnSocketOpened() override
;
318 void OnFrameRead(const std::string
& message
) override
;
319 void OnSocketClosed() override
;
322 base::WeakPtr
<DevToolsAndroidBridge
> bridge_
;
323 BrowserId browser_id_
;
324 std::string debug_url_
;
326 std::vector
<std::string
> pending_messages_
;
327 scoped_refptr
<AndroidDeviceManager::Device
> device_
;
328 scoped_ptr
<AndroidDeviceManager::AndroidWebSocket
> web_socket_
;
329 content::DevToolsAgentHost
* agent_host_
;
330 content::DevToolsExternalAgentProxy
* proxy_
;
331 DISALLOW_COPY_AND_ASSIGN(AgentHostDelegate
);
335 scoped_refptr
<content::DevToolsAgentHost
>
336 DevToolsAndroidBridge::AgentHostDelegate::GetOrCreateAgentHost(
337 DevToolsAndroidBridge
* bridge
,
338 const std::string
& id
,
339 const BrowserId
& browser_id
,
340 const std::string
& debug_url
) {
341 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
342 AgentHostDelegates::iterator it
= bridge
->host_delegates_
.find(id
);
343 if (it
!= bridge
->host_delegates_
.end())
344 return it
->second
->agent_host_
;
346 AgentHostDelegate
* delegate
=
347 new AgentHostDelegate(bridge
, id
, browser_id
, debug_url
);
348 scoped_refptr
<content::DevToolsAgentHost
> result
=
349 content::DevToolsAgentHost::Create(delegate
);
350 delegate
->agent_host_
= result
.get();
354 DevToolsAndroidBridge::AgentHostDelegate::AgentHostDelegate(
355 DevToolsAndroidBridge
* bridge
,
356 const std::string
& id
,
357 const BrowserId
& browser_id
,
358 const std::string
& debug_url
)
360 bridge_(bridge
->AsWeakPtr()),
361 browser_id_(browser_id
),
362 debug_url_(debug_url
),
363 socket_opened_(false),
366 bridge_
->host_delegates_
[id
] = this;
369 DevToolsAndroidBridge::AgentHostDelegate::~AgentHostDelegate() {
371 bridge_
->host_delegates_
.erase(id_
);
374 void DevToolsAndroidBridge::AgentHostDelegate::Attach(
375 content::DevToolsExternalAgentProxy
* proxy
) {
377 content::RecordAction(browser_id_
.second
.find(kWebViewSocketPrefix
) == 0 ?
378 base::UserMetricsAction("DevTools_InspectAndroidWebView") :
379 base::UserMetricsAction("DevTools_InspectAndroidPage"));
381 // Retain the device so it's not released until AgentHost is detached.
383 device_
= bridge_
->FindDevice(browser_id_
.first
);
388 device_
->CreateWebSocket(browser_id_
.second
, debug_url_
, this));
391 void DevToolsAndroidBridge::AgentHostDelegate::Detach() {
396 void DevToolsAndroidBridge::AgentHostDelegate::SendMessageToBackend(
397 const std::string
& message
) {
399 web_socket_
->SendFrame(message
);
401 pending_messages_
.push_back(message
);
404 void DevToolsAndroidBridge::AgentHostDelegate::OnSocketOpened() {
405 socket_opened_
= true;
406 for (std::vector
<std::string
>::iterator it
= pending_messages_
.begin();
407 it
!= pending_messages_
.end(); ++it
) {
408 SendMessageToBackend(*it
);
410 pending_messages_
.clear();
413 void DevToolsAndroidBridge::AgentHostDelegate::OnFrameRead(
414 const std::string
& message
) {
416 proxy_
->DispatchOnClientHost(message
);
419 void DevToolsAndroidBridge::AgentHostDelegate::OnSocketClosed() {
421 proxy_
->ConnectionClosed();
424 //// RemotePageTarget ----------------------------------------------
426 class DevToolsAndroidBridge::RemotePageTarget
: public DevToolsTargetImpl
{
428 RemotePageTarget(DevToolsAndroidBridge
* bridge
,
429 const BrowserId
& browser_id
,
430 const base::DictionaryValue
& value
);
431 ~RemotePageTarget() override
;
433 // DevToolsTargetImpl overrides.
434 std::string
GetId() const override
;
435 bool IsAttached() const override
;
436 bool Activate() const override
;
437 bool Close() const override
;
438 void Inspect(Profile
* profile
) const override
;
439 void Reload() const override
;
442 base::WeakPtr
<DevToolsAndroidBridge
> bridge_
;
443 BrowserId browser_id_
;
444 std::string debug_url_
;
445 std::string frontend_url_
;
446 std::string remote_id_
;
447 std::string remote_type_
;
448 std::string local_id_
;
449 DISALLOW_COPY_AND_ASSIGN(RemotePageTarget
);
452 static std::string
GetStringProperty(const base::DictionaryValue
& value
,
453 const std::string
& name
) {
455 value
.GetString(name
, &result
);
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());
466 static std::string
GetFrontendURL(const base::DictionaryValue
& value
) {
467 std::string frontend_url
= GetStringProperty(value
, "devtoolsFrontendUrl");
468 size_t ws_param
= frontend_url
.find("?ws");
469 if (ws_param
!= std::string::npos
)
470 frontend_url
= frontend_url
.substr(0, ws_param
);
471 if (frontend_url
.find("http:") == 0)
472 frontend_url
= "https:" + frontend_url
.substr(5);
476 static std::string
GetDebugURL(const base::DictionaryValue
& value
) {
477 std::string debug_url
= GetStringProperty(value
, "webSocketDebuggerUrl");
479 if (debug_url
.find("ws://") == 0)
480 debug_url
= debug_url
.substr(5);
482 debug_url
= std::string();
486 DevToolsAndroidBridge::RemotePageTarget::RemotePageTarget(
487 DevToolsAndroidBridge
* bridge
,
488 const BrowserId
& browser_id
,
489 const base::DictionaryValue
& value
)
490 : DevToolsTargetImpl(AgentHostDelegate::GetOrCreateAgentHost(
492 BuildUniqueTargetId(browser_id
, value
),
494 GetDebugURL(value
))),
495 bridge_(bridge
->AsWeakPtr()),
496 browser_id_(browser_id
),
497 debug_url_(GetDebugURL(value
)),
498 frontend_url_(GetFrontendURL(value
)),
499 remote_id_(GetStringProperty(value
, "id")),
500 remote_type_(GetStringProperty(value
, "type")),
501 local_id_(BuildUniqueTargetId(browser_id
, value
)) {
502 set_type("adb_page");
503 set_url(GURL(GetStringProperty(value
, "url")));
504 set_title(base::UTF16ToUTF8(net::UnescapeForHTML(base::UTF8ToUTF16(
505 GetStringProperty(value
, "title")))));
506 set_description(GetStringProperty(value
, "description"));
507 set_favicon_url(GURL(GetStringProperty(value
, "faviconUrl")));
508 debug_url_
= GetDebugURL(value
);
511 DevToolsAndroidBridge::RemotePageTarget::~RemotePageTarget() {
514 std::string
DevToolsAndroidBridge::RemotePageTarget::GetId() const {
518 bool DevToolsAndroidBridge::RemotePageTarget::IsAttached() const {
519 return debug_url_
.empty();
522 static void NoOp(int, const std::string
&) {}
524 void DevToolsAndroidBridge::RemotePageTarget::Inspect(Profile
* profile
) const {
526 bool isWorker
= remote_type_
== kTargetTypeWorker
||
527 remote_type_
== kTargetTypeServiceWorker
;
528 DevToolsWindow::OpenExternalFrontend(profile
, frontend_url_
, GetAgentHost(),
532 bool DevToolsAndroidBridge::RemotePageTarget::Activate() const {
536 std::string request
= base::StringPrintf(kActivatePageRequest
,
538 bridge_
->SendJsonRequest(browser_id_
, request
, base::Bind(&NoOp
));
542 bool DevToolsAndroidBridge::RemotePageTarget::Close() const {
546 std::string request
= base::StringPrintf(kClosePageRequest
,
548 bridge_
->SendJsonRequest(browser_id_
, request
, base::Bind(&NoOp
));
552 void DevToolsAndroidBridge::RemotePageTarget::Reload() const {
556 bridge_
->SendProtocolCommand(browser_id_
, debug_url_
, kPageReloadCommand
,
557 NULL
, base::Closure());
560 // DevToolsAndroidBridge::RemotePage ------------------------------------------
562 DevToolsAndroidBridge::RemotePage::RemotePage(const BrowserId
& browser_id
,
563 const base::DictionaryValue
& dict
)
564 : browser_id_(browser_id
),
565 frontend_url_(GetFrontendURL(dict
)),
566 dict_(dict
.DeepCopy()) {
569 DevToolsAndroidBridge::RemotePage::~RemotePage() {
572 // DevToolsAndroidBridge::RemoteBrowser ---------------------------------------
574 DevToolsAndroidBridge::RemoteBrowser::RemoteBrowser(
575 const std::string
& serial
,
576 const AndroidDeviceManager::BrowserInfo
& browser_info
)
577 : browser_id_(std::make_pair(serial
, browser_info
.socket_name
)),
578 display_name_(browser_info
.display_name
),
579 user_(browser_info
.user
),
580 type_(browser_info
.type
) {
583 bool DevToolsAndroidBridge::RemoteBrowser::IsChrome() {
584 return type_
== AndroidDeviceManager::BrowserInfo::kTypeChrome
;
587 std::string
DevToolsAndroidBridge::RemoteBrowser::GetId() {
588 return serial() + ":" + socket();
591 DevToolsAndroidBridge::RemoteBrowser::ParsedVersion
592 DevToolsAndroidBridge::RemoteBrowser::GetParsedVersion() {
593 ParsedVersion result
;
594 std::vector
<std::string
> parts
;
595 Tokenize(version_
, ".", &parts
);
596 for (size_t i
= 0; i
!= parts
.size(); ++i
) {
598 base::StringToInt(parts
[i
], &value
);
599 result
.push_back(value
);
605 DevToolsAndroidBridge::CreatePageTarget(scoped_refptr
<RemotePage
> page
) {
606 return new RemotePageTarget(this, page
->browser_id_
, *page
->dict_
);
609 void DevToolsAndroidBridge::SendJsonRequest(
610 const BrowserId
& browser_id
,
611 const std::string
& request
,
612 const JsonRequestCallback
& callback
) {
613 scoped_refptr
<AndroidDeviceManager::Device
> device(
614 FindDevice(browser_id
.first
));
616 callback
.Run(net::ERR_FAILED
, std::string());
619 device
->SendJsonRequest(browser_id
.second
, request
, callback
);
622 void DevToolsAndroidBridge::SendProtocolCommand(
623 const BrowserId
& browser_id
,
624 const std::string
& debug_url
,
625 const std::string
& method
,
626 scoped_ptr
<base::DictionaryValue
> params
,
627 const base::Closure callback
) {
628 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
629 if (debug_url
.empty())
631 scoped_refptr
<AndroidDeviceManager::Device
> device(
632 FindDevice(browser_id
.first
));
638 device
, browser_id
.second
, debug_url
,
639 DevToolsProtocol::SerializeCommand(1, method
, params
.Pass()),
643 scoped_refptr
<content::DevToolsAgentHost
>
644 DevToolsAndroidBridge::GetBrowserAgentHost(
645 scoped_refptr
<RemoteBrowser
> browser
) {
646 return AgentHostDelegate::GetOrCreateAgentHost(
648 "adb:" + browser
->serial() + ":" + browser
->socket(),
649 browser
->browser_id_
,
650 kBrowserTargetSocket
);
653 void DevToolsAndroidBridge::SendJsonRequest(
654 const std::string
& browser_id_str
,
655 const std::string
& url
,
656 const JsonRequestCallback
& callback
) {
657 BrowserId browser_id
;
658 if (!BrowserIdFromString(browser_id_str
, &browser_id
)) {
659 callback
.Run(net::ERR_FAILED
, std::string());
662 SendJsonRequest(browser_id
, url
, callback
);
665 scoped_refptr
<AndroidDeviceManager::Device
> DevToolsAndroidBridge::FindDevice(
666 const std::string
& serial
) {
667 DeviceMap::iterator it
= device_map_
.find(serial
);
668 return it
== device_map_
.end() ? nullptr : it
->second
;
671 void DevToolsAndroidBridge::OpenRemotePage(scoped_refptr
<RemoteBrowser
> browser
,
672 const std::string
& input_url
) {
673 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
674 GURL
gurl(input_url
);
675 if (!gurl
.is_valid()) {
676 gurl
= GURL("http://" + input_url
);
677 if (!gurl
.is_valid())
680 std::string url
= gurl
.spec();
681 RemoteBrowser::ParsedVersion parsed_version
= browser
->GetParsedVersion();
683 std::string query
= net::EscapeQueryParamValue(url
, false /* use_plus */);
684 std::string request
=
685 base::StringPrintf(kNewPageRequestWithURL
, query
.c_str());
686 SendJsonRequest(browser
->browser_id_
, request
, base::Bind(&NoOp
));
689 DevToolsAndroidBridge::RemoteBrowser::~RemoteBrowser() {
692 // DevToolsAndroidBridge::RemoteDevice ----------------------------------------
694 DevToolsAndroidBridge::RemoteDevice::RemoteDevice(
695 const std::string
& serial
,
696 const AndroidDeviceManager::DeviceInfo
& device_info
)
698 model_(device_info
.model
),
699 connected_(device_info
.connected
),
700 screen_size_(device_info
.screen_size
) {
701 for (std::vector
<AndroidDeviceManager::BrowserInfo
>::const_iterator it
=
702 device_info
.browser_info
.begin();
703 it
!= device_info
.browser_info
.end();
705 browsers_
.push_back(new RemoteBrowser(serial
, *it
));
709 DevToolsAndroidBridge::RemoteDevice::~RemoteDevice() {
712 // DevToolsAndroidBridge ------------------------------------------------------
714 DevToolsAndroidBridge::DevToolsAndroidBridge(
716 SigninManagerBase
* signin_manager
,
717 ProfileOAuth2TokenService
* const token_service
)
719 signin_manager_(signin_manager
),
720 token_service_(token_service
),
721 device_manager_(AndroidDeviceManager::Create()),
722 task_scheduler_(base::Bind(&DevToolsAndroidBridge::ScheduleTaskDefault
)),
723 port_forwarding_controller_(new PortForwardingController(profile
, this)),
724 weak_factory_(this) {
725 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
726 pref_change_registrar_
.Init(profile_
->GetPrefs());
727 pref_change_registrar_
.Add(prefs::kDevToolsDiscoverUsbDevicesEnabled
,
728 base::Bind(&DevToolsAndroidBridge::CreateDeviceProviders
,
729 base::Unretained(this)));
730 CreateDeviceProviders();
733 void DevToolsAndroidBridge::AddDeviceListListener(
734 DeviceListListener
* listener
) {
735 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
736 bool polling_was_off
= !NeedsDeviceListPolling();
737 device_list_listeners_
.push_back(listener
);
739 StartDeviceListPolling();
742 void DevToolsAndroidBridge::RemoveDeviceListListener(
743 DeviceListListener
* listener
) {
744 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
745 DeviceListListeners::iterator it
= std::find(
746 device_list_listeners_
.begin(), device_list_listeners_
.end(), listener
);
747 DCHECK(it
!= device_list_listeners_
.end());
748 device_list_listeners_
.erase(it
);
749 if (!NeedsDeviceListPolling())
750 StopDeviceListPolling();
753 void DevToolsAndroidBridge::AddDeviceCountListener(
754 DeviceCountListener
* listener
) {
755 device_count_listeners_
.push_back(listener
);
756 if (device_count_listeners_
.size() == 1)
757 StartDeviceCountPolling();
760 void DevToolsAndroidBridge::RemoveDeviceCountListener(
761 DeviceCountListener
* listener
) {
762 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
763 DeviceCountListeners::iterator it
= std::find(
764 device_count_listeners_
.begin(), device_count_listeners_
.end(), listener
);
765 DCHECK(it
!= device_count_listeners_
.end());
766 device_count_listeners_
.erase(it
);
767 if (device_count_listeners_
.empty())
768 StopDeviceCountPolling();
771 void DevToolsAndroidBridge::AddPortForwardingListener(
772 PortForwardingListener
* listener
) {
773 bool polling_was_off
= !NeedsDeviceListPolling();
774 port_forwarding_listeners_
.push_back(listener
);
776 StartDeviceListPolling();
779 void DevToolsAndroidBridge::RemovePortForwardingListener(
780 PortForwardingListener
* listener
) {
781 PortForwardingListeners::iterator it
= std::find(
782 port_forwarding_listeners_
.begin(),
783 port_forwarding_listeners_
.end(),
785 DCHECK(it
!= port_forwarding_listeners_
.end());
786 port_forwarding_listeners_
.erase(it
);
787 if (!NeedsDeviceListPolling())
788 StopDeviceListPolling();
791 bool DevToolsAndroidBridge::HasDevToolsWindow(const std::string
& agent_id
) {
792 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
793 return host_delegates_
.find(agent_id
) != host_delegates_
.end();
796 DevToolsAndroidBridge::~DevToolsAndroidBridge() {
797 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
798 DCHECK(device_list_listeners_
.empty());
799 DCHECK(device_count_listeners_
.empty());
800 DCHECK(port_forwarding_listeners_
.empty());
803 void DevToolsAndroidBridge::StartDeviceListPolling() {
804 device_list_callback_
.Reset(
805 base::Bind(&DevToolsAndroidBridge::ReceivedDeviceList
, AsWeakPtr()));
806 RequestDeviceList(device_list_callback_
.callback());
809 void DevToolsAndroidBridge::StopDeviceListPolling() {
810 device_list_callback_
.Cancel();
814 bool DevToolsAndroidBridge::NeedsDeviceListPolling() {
815 return !device_list_listeners_
.empty() || !port_forwarding_listeners_
.empty();
818 void DevToolsAndroidBridge::RequestDeviceList(
819 const DeviceListCallback
& callback
) {
820 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
822 if (!NeedsDeviceListPolling() ||
823 !callback
.Equals(device_list_callback_
.callback()))
826 new DiscoveryRequest(device_manager_
.get(), callback
);
829 void DevToolsAndroidBridge::ReceivedDeviceList(
830 const CompleteDevices
& complete_devices
) {
831 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
834 RemoteDevices remote_devices
;
835 for (const auto& pair
: complete_devices
) {
836 device_map_
[pair
.first
->serial()] = pair
.first
;
837 remote_devices
.push_back(pair
.second
);
840 DeviceListListeners
copy(device_list_listeners_
);
841 for (DeviceListListeners::iterator it
= copy
.begin(); it
!= copy
.end(); ++it
)
842 (*it
)->DeviceListChanged(remote_devices
);
844 ForwardingStatus status
=
845 port_forwarding_controller_
->DeviceListChanged(remote_devices
);
846 PortForwardingListeners
forwarding_listeners(port_forwarding_listeners_
);
847 for (PortForwardingListeners::iterator it
= forwarding_listeners
.begin();
848 it
!= forwarding_listeners
.end(); ++it
) {
849 (*it
)->PortStatusChanged(status
);
852 if (!NeedsDeviceListPolling())
856 base::Bind(&DevToolsAndroidBridge::RequestDeviceList
,
857 AsWeakPtr(), device_list_callback_
.callback()));
860 void DevToolsAndroidBridge::StartDeviceCountPolling() {
861 device_count_callback_
.Reset(
862 base::Bind(&DevToolsAndroidBridge::ReceivedDeviceCount
, AsWeakPtr()));
863 RequestDeviceCount(device_count_callback_
.callback());
866 void DevToolsAndroidBridge::StopDeviceCountPolling() {
867 device_count_callback_
.Cancel();
870 void DevToolsAndroidBridge::RequestDeviceCount(
871 const base::Callback
<void(int)>& callback
) {
872 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
874 if (device_count_listeners_
.empty() ||
875 !callback
.Equals(device_count_callback_
.callback()))
878 UsbDeviceProvider::CountDevices(callback
);
881 void DevToolsAndroidBridge::ReceivedDeviceCount(int count
) {
882 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
884 DeviceCountListeners
copy(device_count_listeners_
);
885 for (DeviceCountListeners::iterator it
= copy
.begin(); it
!= copy
.end(); ++it
)
886 (*it
)->DeviceCountChanged(count
);
888 if (device_count_listeners_
.empty())
892 base::Bind(&DevToolsAndroidBridge::RequestDeviceCount
,
893 AsWeakPtr(), device_count_callback_
.callback()));
897 void DevToolsAndroidBridge::ScheduleTaskDefault(const base::Closure
& task
) {
898 BrowserThread::PostDelayedTask(
902 base::TimeDelta::FromMilliseconds(kAdbPollingIntervalMs
));
905 void DevToolsAndroidBridge::CreateDeviceProviders() {
906 AndroidDeviceManager::DeviceProviders device_providers
;
907 #if defined(DEBUG_DEVTOOLS)
908 RemoteDebuggingServer::EnableTetheringForDebug();
909 // We cannot rely on command line switch here as we might want to connect
910 // to another instance of Chrome. Using hard-coded port number instead.
911 const int kDefaultDebuggingPort
= 9222;
912 device_providers
.push_back(new SelfAsDeviceProvider(kDefaultDebuggingPort
));
914 device_providers
.push_back(new AdbDeviceProvider());
916 PrefService
* service
= profile_
->GetPrefs();
917 const PrefService::Preference
* pref
=
918 service
->FindPreference(prefs::kDevToolsDiscoverUsbDevicesEnabled
);
919 const base::Value
* pref_value
= pref
->GetValue();
922 if (pref_value
->GetAsBoolean(&enabled
) && enabled
) {
923 device_providers
.push_back(new UsbDeviceProvider(profile_
));
926 if (IsWebRTCDeviceProviderEnabled()) {
927 device_providers
.push_back(
928 new WebRTCDeviceProvider(profile_
, signin_manager_
, token_service_
));
931 device_manager_
->SetDeviceProviders(device_providers
);
932 if (NeedsDeviceListPolling()) {
933 StopDeviceListPolling();
934 StartDeviceListPolling();