[Presentation API, Android] Implement basic messaging
[chromium-blink-merge.git] / chrome / browser / devtools / device / devtools_android_bridge.cc
blob6e1f2e0df2d245701c2f94ff737b9907164d2807
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"
7 #include <map>
8 #include <set>
9 #include <vector>
11 #include "base/base64.h"
12 #include "base/bind.h"
13 #include "base/command_line.h"
14 #include "base/compiler_specific.h"
15 #include "base/json/json_reader.h"
16 #include "base/lazy_instance.h"
17 #include "base/memory/singleton.h"
18 #include "base/message_loop/message_loop.h"
19 #include "base/prefs/pref_service.h"
20 #include "base/strings/string_number_conversions.h"
21 #include "base/strings/string_split.h"
22 #include "base/strings/string_util.h"
23 #include "base/strings/stringprintf.h"
24 #include "base/strings/utf_string_conversions.h"
25 #include "base/threading/thread.h"
26 #include "base/values.h"
27 #include "chrome/browser/devtools/device/adb/adb_device_provider.h"
28 #include "chrome/browser/devtools/device/port_forwarding_controller.h"
29 #include "chrome/browser/devtools/device/tcp_device_provider.h"
30 #include "chrome/browser/devtools/device/usb/usb_device_provider.h"
31 #include "chrome/browser/devtools/device/webrtc/webrtc_device_provider.h"
32 #include "chrome/browser/devtools/devtools_protocol.h"
33 #include "chrome/browser/devtools/devtools_target_impl.h"
34 #include "chrome/browser/devtools/devtools_window.h"
35 #include "chrome/browser/devtools/remote_debugging_server.h"
36 #include "chrome/browser/profiles/profile.h"
37 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
38 #include "chrome/browser/signin/signin_manager_factory.h"
39 #include "chrome/common/chrome_switches.h"
40 #include "chrome/common/pref_names.h"
41 #include "components/keyed_service/content/browser_context_dependency_manager.h"
42 #include "components/signin/core/browser/profile_oauth2_token_service.h"
43 #include "components/signin/core/browser/signin_manager.h"
44 #include "content/public/browser/devtools_agent_host.h"
45 #include "content/public/browser/devtools_external_agent_proxy.h"
46 #include "content/public/browser/devtools_external_agent_proxy_delegate.h"
47 #include "content/public/browser/user_metrics.h"
48 #include "net/base/escape.h"
49 #include "net/base/host_port_pair.h"
50 #include "net/base/net_errors.h"
52 using content::BrowserThread;
54 namespace {
56 const char kPageListRequest[] = "/json";
57 const char kVersionRequest[] = "/json/version";
58 const char kClosePageRequest[] = "/json/close/%s";
59 const char kNewPageRequestWithURL[] = "/json/new?%s";
60 const char kActivatePageRequest[] = "/json/activate/%s";
61 const char kBrowserTargetSocket[] = "/devtools/browser";
62 const int kAdbPollingIntervalMs = 1000;
64 const char kPageReloadCommand[] = "Page.reload";
66 const char kWebViewSocketPrefix[] = "webview_devtools_remote";
68 bool IsWebRTCDeviceProviderEnabled() {
69 return base::CommandLine::ForCurrentProcess()->HasSwitch(
70 switches::kEnableDevToolsExperiments);
73 bool BrowserIdFromString(const std::string& browser_id_str,
74 DevToolsAndroidBridge::BrowserId* browser_id) {
75 size_t colon_pos = browser_id_str.find(':');
76 if (colon_pos == std::string::npos)
77 return false;
78 browser_id->first = browser_id_str.substr(0, colon_pos);
79 browser_id->second = browser_id_str.substr(colon_pos + 1);
80 return true;
83 } // namespace
85 // DiscoveryRequest -----------------------------------------------------
87 class DevToolsAndroidBridge::DiscoveryRequest
88 : public base::RefCountedThreadSafe<DiscoveryRequest,
89 BrowserThread::DeleteOnUIThread> {
90 public:
91 DiscoveryRequest(AndroidDeviceManager* device_manager,
92 const DeviceListCallback& callback);
93 private:
94 friend struct BrowserThread::DeleteOnThread<BrowserThread::UI>;
95 friend class base::DeleteHelper<DiscoveryRequest>;
96 virtual ~DiscoveryRequest();
98 void ReceivedDevices(const AndroidDeviceManager::Devices& devices);
99 void ReceivedDeviceInfo(scoped_refptr<AndroidDeviceManager::Device> device,
100 const AndroidDeviceManager::DeviceInfo& device_info);
101 void ReceivedVersion(scoped_refptr<RemoteBrowser>,
102 int result,
103 const std::string& response);
104 void ReceivedPages(scoped_refptr<RemoteBrowser>,
105 int result,
106 const std::string& response);
108 DeviceListCallback callback_;
109 CompleteDevices complete_devices_;
112 DevToolsAndroidBridge::DiscoveryRequest::DiscoveryRequest(
113 AndroidDeviceManager* device_manager,
114 const DeviceListCallback& callback)
115 : callback_(callback) {
116 DCHECK_CURRENTLY_ON(BrowserThread::UI);
117 device_manager->QueryDevices(
118 base::Bind(&DiscoveryRequest::ReceivedDevices, this));
121 DevToolsAndroidBridge::DiscoveryRequest::~DiscoveryRequest() {
122 DCHECK_CURRENTLY_ON(BrowserThread::UI);
123 callback_.Run(complete_devices_);
126 void DevToolsAndroidBridge::DiscoveryRequest::ReceivedDevices(
127 const AndroidDeviceManager::Devices& devices) {
128 DCHECK_CURRENTLY_ON(BrowserThread::UI);
129 for (const auto& device : devices) {
130 device->QueryDeviceInfo(
131 base::Bind(&DiscoveryRequest::ReceivedDeviceInfo, this, device));
135 void DevToolsAndroidBridge::DiscoveryRequest::ReceivedDeviceInfo(
136 scoped_refptr<AndroidDeviceManager::Device> device,
137 const AndroidDeviceManager::DeviceInfo& device_info) {
138 DCHECK_CURRENTLY_ON(BrowserThread::UI);
139 scoped_refptr<RemoteDevice> remote_device =
140 new RemoteDevice(device->serial(), device_info);
141 complete_devices_.push_back(std::make_pair(device, remote_device));
142 for (RemoteBrowsers::iterator it = remote_device->browsers().begin();
143 it != remote_device->browsers().end(); ++it) {
144 device->SendJsonRequest(
145 (*it)->socket(),
146 kVersionRequest,
147 base::Bind(&DiscoveryRequest::ReceivedVersion, this, *it));
148 device->SendJsonRequest(
149 (*it)->socket(),
150 kPageListRequest,
151 base::Bind(&DiscoveryRequest::ReceivedPages, this, *it));
155 void DevToolsAndroidBridge::DiscoveryRequest::ReceivedVersion(
156 scoped_refptr<RemoteBrowser> browser,
157 int result,
158 const std::string& response) {
159 DCHECK_CURRENTLY_ON(BrowserThread::UI);
160 if (result < 0)
161 return;
162 // Parse version, append to package name if available,
163 scoped_ptr<base::Value> value = base::JSONReader::Read(response);
164 base::DictionaryValue* dict;
165 if (value && value->GetAsDictionary(&dict)) {
166 std::string browser_name;
167 if (dict->GetString("Browser", &browser_name)) {
168 std::vector<std::string> parts = base::SplitString(
169 browser_name, "/", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
170 if (parts.size() == 2)
171 browser->version_ = parts[1];
172 else
173 browser->version_ = browser_name;
175 std::string package;
176 if (dict->GetString("Android-Package", &package)) {
177 browser->display_name_ =
178 AndroidDeviceManager::GetBrowserName(browser->socket(), package);
183 void DevToolsAndroidBridge::DiscoveryRequest::ReceivedPages(
184 scoped_refptr<RemoteBrowser> browser,
185 int result,
186 const std::string& response) {
187 DCHECK_CURRENTLY_ON(BrowserThread::UI);
188 if (result < 0)
189 return;
190 scoped_ptr<base::Value> value = base::JSONReader::Read(response);
191 base::ListValue* list_value;
192 if (value && value->GetAsList(&list_value)) {
193 for (const auto& page_value : *list_value) {
194 base::DictionaryValue* dict;
195 if (page_value->GetAsDictionary(&dict))
196 browser->pages_.push_back(new RemotePage(browser->browser_id_, *dict));
201 // ProtocolCommand ------------------------------------------------------------
203 namespace {
205 class ProtocolCommand
206 : public AndroidDeviceManager::AndroidWebSocket::Delegate {
207 public:
208 ProtocolCommand(
209 scoped_refptr<AndroidDeviceManager::Device> device,
210 const std::string& socket,
211 const std::string& target_path,
212 const std::string& command,
213 const base::Closure callback);
215 private:
216 void OnSocketOpened() override;
217 void OnFrameRead(const std::string& message) override;
218 void OnSocketClosed() override;
219 ~ProtocolCommand() override;
221 const std::string command_;
222 const base::Closure callback_;
223 scoped_ptr<AndroidDeviceManager::AndroidWebSocket> web_socket_;
225 DISALLOW_COPY_AND_ASSIGN(ProtocolCommand);
228 ProtocolCommand::ProtocolCommand(
229 scoped_refptr<AndroidDeviceManager::Device> device,
230 const std::string& socket,
231 const std::string& target_path,
232 const std::string& command,
233 const base::Closure callback)
234 : command_(command),
235 callback_(callback),
236 web_socket_(device->CreateWebSocket(socket, target_path, this)) {
239 void ProtocolCommand::OnSocketOpened() {
240 web_socket_->SendFrame(command_);
243 void ProtocolCommand::OnFrameRead(const std::string& message) {
244 delete this;
247 void ProtocolCommand::OnSocketClosed() {
248 delete this;
251 ProtocolCommand::~ProtocolCommand() {
252 if (!callback_.is_null())
253 callback_.Run();
256 } // namespace
258 // static
259 DevToolsAndroidBridge::Factory* DevToolsAndroidBridge::Factory::GetInstance() {
260 return Singleton<DevToolsAndroidBridge::Factory>::get();
263 // static
264 DevToolsAndroidBridge* DevToolsAndroidBridge::Factory::GetForProfile(
265 Profile* profile) {
266 return static_cast<DevToolsAndroidBridge*>(GetInstance()->
267 GetServiceForBrowserContext(profile, true));
270 DevToolsAndroidBridge::Factory::Factory()
271 : BrowserContextKeyedServiceFactory(
272 "DevToolsAndroidBridge",
273 BrowserContextDependencyManager::GetInstance()) {
274 if (IsWebRTCDeviceProviderEnabled()) {
275 DependsOn(ProfileOAuth2TokenServiceFactory::GetInstance());
276 DependsOn(SigninManagerFactory::GetInstance());
280 DevToolsAndroidBridge::Factory::~Factory() {}
282 KeyedService* DevToolsAndroidBridge::Factory::BuildServiceInstanceFor(
283 content::BrowserContext* context) const {
284 Profile* profile = Profile::FromBrowserContext(context);
286 ProfileOAuth2TokenService* token_service = nullptr;
287 SigninManagerBase* signin_manager = nullptr;
289 if (IsWebRTCDeviceProviderEnabled()) {
290 token_service = ProfileOAuth2TokenServiceFactory::GetForProfile(profile);
291 signin_manager = SigninManagerFactory::GetForProfile(profile);
294 return new DevToolsAndroidBridge(
295 profile, signin_manager, token_service);
298 // AgentHostDelegate ----------------------------------------------------------
300 class DevToolsAndroidBridge::AgentHostDelegate
301 : public content::DevToolsExternalAgentProxyDelegate,
302 public AndroidDeviceManager::AndroidWebSocket::Delegate {
303 public:
304 static scoped_refptr<content::DevToolsAgentHost> GetOrCreateAgentHost(
305 DevToolsAndroidBridge* bridge,
306 const std::string& id,
307 const BrowserId& browser_id,
308 const std::string& target_path);
310 private:
311 AgentHostDelegate(
312 DevToolsAndroidBridge* bridge,
313 const std::string& id,
314 const BrowserId& browser_id,
315 const std::string& target_path);
316 ~AgentHostDelegate() override;
317 void Attach(content::DevToolsExternalAgentProxy* proxy) override;
318 void Detach() override;
319 void SendMessageToBackend(const std::string& message) override;
320 void OnSocketOpened() override;
321 void OnFrameRead(const std::string& message) override;
322 void OnSocketClosed() override;
324 std::string id_;
325 base::WeakPtr<DevToolsAndroidBridge> bridge_;
326 BrowserId browser_id_;
327 std::string target_path_;
328 bool socket_opened_;
329 std::vector<std::string> pending_messages_;
330 scoped_refptr<AndroidDeviceManager::Device> device_;
331 scoped_ptr<AndroidDeviceManager::AndroidWebSocket> web_socket_;
332 content::DevToolsAgentHost* agent_host_;
333 content::DevToolsExternalAgentProxy* proxy_;
334 DISALLOW_COPY_AND_ASSIGN(AgentHostDelegate);
337 // static
338 scoped_refptr<content::DevToolsAgentHost>
339 DevToolsAndroidBridge::AgentHostDelegate::GetOrCreateAgentHost(
340 DevToolsAndroidBridge* bridge,
341 const std::string& id,
342 const BrowserId& browser_id,
343 const std::string& target_path) {
344 DCHECK_CURRENTLY_ON(BrowserThread::UI);
345 AgentHostDelegates::iterator it = bridge->host_delegates_.find(id);
346 if (it != bridge->host_delegates_.end())
347 return it->second->agent_host_;
349 AgentHostDelegate* delegate =
350 new AgentHostDelegate(bridge, id, browser_id, target_path);
351 scoped_refptr<content::DevToolsAgentHost> result =
352 content::DevToolsAgentHost::Create(delegate);
353 delegate->agent_host_ = result.get();
354 return result;
357 DevToolsAndroidBridge::AgentHostDelegate::AgentHostDelegate(
358 DevToolsAndroidBridge* bridge,
359 const std::string& id,
360 const BrowserId& browser_id,
361 const std::string& target_path)
362 : id_(id),
363 bridge_(bridge->AsWeakPtr()),
364 browser_id_(browser_id),
365 target_path_(target_path),
366 socket_opened_(false),
367 agent_host_(NULL),
368 proxy_(NULL) {
369 bridge_->host_delegates_[id] = this;
372 DevToolsAndroidBridge::AgentHostDelegate::~AgentHostDelegate() {
373 if (bridge_)
374 bridge_->host_delegates_.erase(id_);
377 void DevToolsAndroidBridge::AgentHostDelegate::Attach(
378 content::DevToolsExternalAgentProxy* proxy) {
379 proxy_ = proxy;
380 content::RecordAction(browser_id_.second.find(kWebViewSocketPrefix) == 0 ?
381 base::UserMetricsAction("DevTools_InspectAndroidWebView") :
382 base::UserMetricsAction("DevTools_InspectAndroidPage"));
384 // Retain the device so it's not released until AgentHost is detached.
385 if (bridge_)
386 device_ = bridge_->FindDevice(browser_id_.first);
387 if (!device_.get())
388 return;
390 web_socket_.reset(
391 device_->CreateWebSocket(browser_id_.second, target_path_, this));
394 void DevToolsAndroidBridge::AgentHostDelegate::Detach() {
395 web_socket_.reset();
396 device_ = nullptr;
399 void DevToolsAndroidBridge::AgentHostDelegate::SendMessageToBackend(
400 const std::string& message) {
401 if (socket_opened_)
402 web_socket_->SendFrame(message);
403 else
404 pending_messages_.push_back(message);
407 void DevToolsAndroidBridge::AgentHostDelegate::OnSocketOpened() {
408 socket_opened_ = true;
409 for (std::vector<std::string>::iterator it = pending_messages_.begin();
410 it != pending_messages_.end(); ++it) {
411 SendMessageToBackend(*it);
413 pending_messages_.clear();
416 void DevToolsAndroidBridge::AgentHostDelegate::OnFrameRead(
417 const std::string& message) {
418 if (proxy_)
419 proxy_->DispatchOnClientHost(message);
422 void DevToolsAndroidBridge::AgentHostDelegate::OnSocketClosed() {
423 if (proxy_)
424 proxy_->ConnectionClosed();
427 //// RemotePageTarget ----------------------------------------------
429 class DevToolsAndroidBridge::RemotePageTarget : public DevToolsTargetImpl {
430 public:
431 RemotePageTarget(DevToolsAndroidBridge* bridge,
432 const BrowserId& browser_id,
433 const base::DictionaryValue& value);
434 ~RemotePageTarget() override;
436 // DevToolsTargetImpl overrides.
437 std::string GetId() const override;
438 bool IsAttached() const override;
439 bool Activate() const override;
440 bool Close() const override;
441 void Inspect(Profile* profile) const override;
442 void Reload() const override;
444 private:
445 base::WeakPtr<DevToolsAndroidBridge> bridge_;
446 BrowserId browser_id_;
447 std::string target_path_;
448 std::string frontend_url_;
449 std::string remote_id_;
450 std::string remote_type_;
451 std::string local_id_;
452 DISALLOW_COPY_AND_ASSIGN(RemotePageTarget);
455 static std::string GetStringProperty(const base::DictionaryValue& value,
456 const std::string& name) {
457 std::string result;
458 value.GetString(name, &result);
459 return result;
462 static std::string BuildUniqueTargetId(
463 const DevToolsAndroidBridge::BrowserId& browser_id,
464 const base::DictionaryValue& value) {
465 return base::StringPrintf("%s:%s:%s", browser_id.first.c_str(),
466 browser_id.second.c_str(), GetStringProperty(value, "id").c_str());
469 static std::string GetFrontendURL(const base::DictionaryValue& value) {
470 std::string frontend_url = GetStringProperty(value, "devtoolsFrontendUrl");
471 size_t ws_param = frontend_url.find("?ws");
472 if (ws_param != std::string::npos)
473 frontend_url = frontend_url.substr(0, ws_param);
474 if (frontend_url.find("http:") == 0)
475 frontend_url = "https:" + frontend_url.substr(5);
476 return frontend_url;
479 static std::string GetTargetPath(const base::DictionaryValue& value) {
480 std::string target_path = GetStringProperty(value, "webSocketDebuggerUrl");
482 if (target_path.find("ws://") == 0) {
483 size_t pos = target_path.find("/", 5);
484 if (pos == std::string::npos)
485 pos = 5;
486 target_path = target_path.substr(pos);
487 } else {
488 target_path = std::string();
490 return target_path;
493 DevToolsAndroidBridge::RemotePageTarget::RemotePageTarget(
494 DevToolsAndroidBridge* bridge,
495 const BrowserId& browser_id,
496 const base::DictionaryValue& value)
497 : DevToolsTargetImpl(AgentHostDelegate::GetOrCreateAgentHost(
498 bridge,
499 BuildUniqueTargetId(browser_id, value),
500 browser_id,
501 GetTargetPath(value))),
502 bridge_(bridge->AsWeakPtr()),
503 browser_id_(browser_id),
504 target_path_(GetTargetPath(value)),
505 frontend_url_(GetFrontendURL(value)),
506 remote_id_(GetStringProperty(value, "id")),
507 remote_type_(GetStringProperty(value, "type")),
508 local_id_(BuildUniqueTargetId(browser_id, value)) {
509 set_type("adb_page");
510 set_url(GURL(GetStringProperty(value, "url")));
511 set_title(base::UTF16ToUTF8(net::UnescapeForHTML(base::UTF8ToUTF16(
512 GetStringProperty(value, "title")))));
513 set_description(GetStringProperty(value, "description"));
514 set_favicon_url(GURL(GetStringProperty(value, "faviconUrl")));
515 target_path_ = GetTargetPath(value);
518 DevToolsAndroidBridge::RemotePageTarget::~RemotePageTarget() {
521 std::string DevToolsAndroidBridge::RemotePageTarget::GetId() const {
522 return local_id_;
525 bool DevToolsAndroidBridge::RemotePageTarget::IsAttached() const {
526 return target_path_.empty();
529 static void NoOp(int, const std::string&) {}
531 void DevToolsAndroidBridge::RemotePageTarget::Inspect(Profile* profile) const {
532 Activate();
533 bool isWorker = remote_type_ == kTargetTypeWorker ||
534 remote_type_ == kTargetTypeServiceWorker;
535 DevToolsWindow::OpenExternalFrontend(profile, frontend_url_, GetAgentHost(),
536 isWorker);
539 bool DevToolsAndroidBridge::RemotePageTarget::Activate() const {
540 if (!bridge_)
541 return false;
543 std::string request = base::StringPrintf(kActivatePageRequest,
544 remote_id_.c_str());
545 bridge_->SendJsonRequest(browser_id_, request, base::Bind(&NoOp));
546 return true;
549 bool DevToolsAndroidBridge::RemotePageTarget::Close() const {
550 if (!bridge_)
551 return false;
553 std::string request = base::StringPrintf(kClosePageRequest,
554 remote_id_.c_str());
555 bridge_->SendJsonRequest(browser_id_, request, base::Bind(&NoOp));
556 return true;
559 void DevToolsAndroidBridge::RemotePageTarget::Reload() const {
560 if (!bridge_)
561 return;
563 bridge_->SendProtocolCommand(browser_id_, target_path_, kPageReloadCommand,
564 NULL, base::Closure());
567 // DevToolsAndroidBridge::RemotePage ------------------------------------------
569 DevToolsAndroidBridge::RemotePage::RemotePage(const BrowserId& browser_id,
570 const base::DictionaryValue& dict)
571 : browser_id_(browser_id),
572 frontend_url_(GetFrontendURL(dict)),
573 dict_(dict.DeepCopy()) {
576 DevToolsAndroidBridge::RemotePage::~RemotePage() {
579 // DevToolsAndroidBridge::RemoteBrowser ---------------------------------------
581 DevToolsAndroidBridge::RemoteBrowser::RemoteBrowser(
582 const std::string& serial,
583 const AndroidDeviceManager::BrowserInfo& browser_info)
584 : browser_id_(std::make_pair(serial, browser_info.socket_name)),
585 display_name_(browser_info.display_name),
586 user_(browser_info.user),
587 type_(browser_info.type) {
590 bool DevToolsAndroidBridge::RemoteBrowser::IsChrome() {
591 return type_ == AndroidDeviceManager::BrowserInfo::kTypeChrome;
594 std::string DevToolsAndroidBridge::RemoteBrowser::GetId() {
595 return serial() + ":" + socket();
598 DevToolsAndroidBridge::RemoteBrowser::ParsedVersion
599 DevToolsAndroidBridge::RemoteBrowser::GetParsedVersion() {
600 ParsedVersion result;
601 for (const base::StringPiece& part :
602 base::SplitStringPiece(
603 version_, ".", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY)) {
604 int value = 0;
605 base::StringToInt(part, &value);
606 result.push_back(value);
608 return result;
611 DevToolsTargetImpl*
612 DevToolsAndroidBridge::CreatePageTarget(scoped_refptr<RemotePage> page) {
613 return new RemotePageTarget(this, page->browser_id_, *page->dict_);
616 void DevToolsAndroidBridge::SendJsonRequest(
617 const BrowserId& browser_id,
618 const std::string& request,
619 const JsonRequestCallback& callback) {
620 scoped_refptr<AndroidDeviceManager::Device> device(
621 FindDevice(browser_id.first));
622 if (!device.get()) {
623 callback.Run(net::ERR_FAILED, std::string());
624 return;
626 device->SendJsonRequest(browser_id.second, request, callback);
629 void DevToolsAndroidBridge::SendProtocolCommand(
630 const BrowserId& browser_id,
631 const std::string& target_path,
632 const std::string& method,
633 scoped_ptr<base::DictionaryValue> params,
634 const base::Closure callback) {
635 DCHECK_CURRENTLY_ON(BrowserThread::UI);
636 if (target_path.empty())
637 return;
638 scoped_refptr<AndroidDeviceManager::Device> device(
639 FindDevice(browser_id.first));
640 if (!device.get()) {
641 callback.Run();
642 return;
644 new ProtocolCommand(
645 device, browser_id.second, target_path,
646 DevToolsProtocol::SerializeCommand(1, method, params.Pass()),
647 callback);
650 scoped_refptr<content::DevToolsAgentHost>
651 DevToolsAndroidBridge::GetBrowserAgentHost(
652 scoped_refptr<RemoteBrowser> browser) {
653 return AgentHostDelegate::GetOrCreateAgentHost(
654 this,
655 "adb:" + browser->serial() + ":" + browser->socket(),
656 browser->browser_id_,
657 kBrowserTargetSocket);
660 void DevToolsAndroidBridge::SendJsonRequest(
661 const std::string& browser_id_str,
662 const std::string& url,
663 const JsonRequestCallback& callback) {
664 BrowserId browser_id;
665 if (!BrowserIdFromString(browser_id_str, &browser_id)) {
666 callback.Run(net::ERR_FAILED, std::string());
667 return;
669 SendJsonRequest(browser_id, url, callback);
672 scoped_refptr<AndroidDeviceManager::Device> DevToolsAndroidBridge::FindDevice(
673 const std::string& serial) {
674 DeviceMap::iterator it = device_map_.find(serial);
675 return it == device_map_.end() ? nullptr : it->second;
678 void DevToolsAndroidBridge::OpenRemotePage(scoped_refptr<RemoteBrowser> browser,
679 const std::string& input_url) {
680 DCHECK_CURRENTLY_ON(BrowserThread::UI);
681 GURL gurl(input_url);
682 if (!gurl.is_valid()) {
683 gurl = GURL("http://" + input_url);
684 if (!gurl.is_valid())
685 return;
687 std::string url = gurl.spec();
688 RemoteBrowser::ParsedVersion parsed_version = browser->GetParsedVersion();
690 std::string query = net::EscapeQueryParamValue(url, false /* use_plus */);
691 std::string request =
692 base::StringPrintf(kNewPageRequestWithURL, query.c_str());
693 SendJsonRequest(browser->browser_id_, request, base::Bind(&NoOp));
696 DevToolsAndroidBridge::RemoteBrowser::~RemoteBrowser() {
699 // DevToolsAndroidBridge::RemoteDevice ----------------------------------------
701 DevToolsAndroidBridge::RemoteDevice::RemoteDevice(
702 const std::string& serial,
703 const AndroidDeviceManager::DeviceInfo& device_info)
704 : serial_(serial),
705 model_(device_info.model),
706 connected_(device_info.connected),
707 screen_size_(device_info.screen_size) {
708 for (std::vector<AndroidDeviceManager::BrowserInfo>::const_iterator it =
709 device_info.browser_info.begin();
710 it != device_info.browser_info.end();
711 ++it) {
712 browsers_.push_back(new RemoteBrowser(serial, *it));
716 DevToolsAndroidBridge::RemoteDevice::~RemoteDevice() {
719 // DevToolsAndroidBridge ------------------------------------------------------
721 DevToolsAndroidBridge::DevToolsAndroidBridge(
722 Profile* profile,
723 SigninManagerBase* signin_manager,
724 ProfileOAuth2TokenService* const token_service)
725 : profile_(profile),
726 signin_manager_(signin_manager),
727 token_service_(token_service),
728 device_manager_(AndroidDeviceManager::Create()),
729 task_scheduler_(base::Bind(&DevToolsAndroidBridge::ScheduleTaskDefault)),
730 port_forwarding_controller_(new PortForwardingController(profile, this)),
731 weak_factory_(this) {
732 DCHECK_CURRENTLY_ON(BrowserThread::UI);
733 pref_change_registrar_.Init(profile_->GetPrefs());
734 pref_change_registrar_.Add(prefs::kDevToolsDiscoverUsbDevicesEnabled,
735 base::Bind(&DevToolsAndroidBridge::CreateDeviceProviders,
736 base::Unretained(this)));
737 CreateDeviceProviders();
740 void DevToolsAndroidBridge::AddDeviceListListener(
741 DeviceListListener* listener) {
742 DCHECK_CURRENTLY_ON(BrowserThread::UI);
743 bool polling_was_off = !NeedsDeviceListPolling();
744 device_list_listeners_.push_back(listener);
745 if (polling_was_off)
746 StartDeviceListPolling();
749 void DevToolsAndroidBridge::RemoveDeviceListListener(
750 DeviceListListener* listener) {
751 DCHECK_CURRENTLY_ON(BrowserThread::UI);
752 DeviceListListeners::iterator it = std::find(
753 device_list_listeners_.begin(), device_list_listeners_.end(), listener);
754 DCHECK(it != device_list_listeners_.end());
755 device_list_listeners_.erase(it);
756 if (!NeedsDeviceListPolling())
757 StopDeviceListPolling();
760 void DevToolsAndroidBridge::AddDeviceCountListener(
761 DeviceCountListener* listener) {
762 device_count_listeners_.push_back(listener);
763 if (device_count_listeners_.size() == 1)
764 StartDeviceCountPolling();
767 void DevToolsAndroidBridge::RemoveDeviceCountListener(
768 DeviceCountListener* listener) {
769 DCHECK_CURRENTLY_ON(BrowserThread::UI);
770 DeviceCountListeners::iterator it = std::find(
771 device_count_listeners_.begin(), device_count_listeners_.end(), listener);
772 DCHECK(it != device_count_listeners_.end());
773 device_count_listeners_.erase(it);
774 if (device_count_listeners_.empty())
775 StopDeviceCountPolling();
778 void DevToolsAndroidBridge::AddPortForwardingListener(
779 PortForwardingListener* listener) {
780 bool polling_was_off = !NeedsDeviceListPolling();
781 port_forwarding_listeners_.push_back(listener);
782 if (polling_was_off)
783 StartDeviceListPolling();
786 void DevToolsAndroidBridge::RemovePortForwardingListener(
787 PortForwardingListener* listener) {
788 PortForwardingListeners::iterator it = std::find(
789 port_forwarding_listeners_.begin(),
790 port_forwarding_listeners_.end(),
791 listener);
792 DCHECK(it != port_forwarding_listeners_.end());
793 port_forwarding_listeners_.erase(it);
794 if (!NeedsDeviceListPolling())
795 StopDeviceListPolling();
798 bool DevToolsAndroidBridge::HasDevToolsWindow(const std::string& agent_id) {
799 DCHECK_CURRENTLY_ON(BrowserThread::UI);
800 return host_delegates_.find(agent_id) != host_delegates_.end();
803 DevToolsAndroidBridge::~DevToolsAndroidBridge() {
804 DCHECK_CURRENTLY_ON(BrowserThread::UI);
805 DCHECK(device_list_listeners_.empty());
806 DCHECK(device_count_listeners_.empty());
807 DCHECK(port_forwarding_listeners_.empty());
810 void DevToolsAndroidBridge::StartDeviceListPolling() {
811 device_list_callback_.Reset(
812 base::Bind(&DevToolsAndroidBridge::ReceivedDeviceList, AsWeakPtr()));
813 RequestDeviceList(device_list_callback_.callback());
816 void DevToolsAndroidBridge::StopDeviceListPolling() {
817 device_list_callback_.Cancel();
818 device_map_.clear();
821 bool DevToolsAndroidBridge::NeedsDeviceListPolling() {
822 return !device_list_listeners_.empty() || !port_forwarding_listeners_.empty();
825 void DevToolsAndroidBridge::RequestDeviceList(
826 const DeviceListCallback& callback) {
827 DCHECK_CURRENTLY_ON(BrowserThread::UI);
829 if (!NeedsDeviceListPolling() ||
830 !callback.Equals(device_list_callback_.callback()))
831 return;
833 new DiscoveryRequest(device_manager_.get(), callback);
836 void DevToolsAndroidBridge::ReceivedDeviceList(
837 const CompleteDevices& complete_devices) {
838 DCHECK_CURRENTLY_ON(BrowserThread::UI);
840 device_map_.clear();
841 RemoteDevices remote_devices;
842 for (const auto& pair : complete_devices) {
843 device_map_[pair.first->serial()] = pair.first;
844 remote_devices.push_back(pair.second);
847 DeviceListListeners copy(device_list_listeners_);
848 for (DeviceListListeners::iterator it = copy.begin(); it != copy.end(); ++it)
849 (*it)->DeviceListChanged(remote_devices);
851 ForwardingStatus status =
852 port_forwarding_controller_->DeviceListChanged(remote_devices);
853 PortForwardingListeners forwarding_listeners(port_forwarding_listeners_);
854 for (PortForwardingListeners::iterator it = forwarding_listeners.begin();
855 it != forwarding_listeners.end(); ++it) {
856 (*it)->PortStatusChanged(status);
859 if (!NeedsDeviceListPolling())
860 return;
862 task_scheduler_.Run(
863 base::Bind(&DevToolsAndroidBridge::RequestDeviceList,
864 AsWeakPtr(), device_list_callback_.callback()));
867 void DevToolsAndroidBridge::StartDeviceCountPolling() {
868 device_count_callback_.Reset(
869 base::Bind(&DevToolsAndroidBridge::ReceivedDeviceCount, AsWeakPtr()));
870 RequestDeviceCount(device_count_callback_.callback());
873 void DevToolsAndroidBridge::StopDeviceCountPolling() {
874 device_count_callback_.Cancel();
877 void DevToolsAndroidBridge::RequestDeviceCount(
878 const base::Callback<void(int)>& callback) {
879 DCHECK_CURRENTLY_ON(BrowserThread::UI);
881 if (device_count_listeners_.empty() ||
882 !callback.Equals(device_count_callback_.callback()))
883 return;
885 UsbDeviceProvider::CountDevices(callback);
888 void DevToolsAndroidBridge::ReceivedDeviceCount(int count) {
889 DCHECK_CURRENTLY_ON(BrowserThread::UI);
891 DeviceCountListeners copy(device_count_listeners_);
892 for (DeviceCountListeners::iterator it = copy.begin(); it != copy.end(); ++it)
893 (*it)->DeviceCountChanged(count);
895 if (device_count_listeners_.empty())
896 return;
898 task_scheduler_.Run(
899 base::Bind(&DevToolsAndroidBridge::RequestDeviceCount,
900 AsWeakPtr(), device_count_callback_.callback()));
903 // static
904 void DevToolsAndroidBridge::ScheduleTaskDefault(const base::Closure& task) {
905 BrowserThread::PostDelayedTask(
906 BrowserThread::UI,
907 FROM_HERE,
908 task,
909 base::TimeDelta::FromMilliseconds(kAdbPollingIntervalMs));
912 static scoped_refptr<TCPDeviceProvider> CreateTCPDeviceProvider() {
913 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
914 if (!command_line->HasSwitch(switches::kRemoteDebuggingTargets))
915 return nullptr;
916 std::string value =
917 command_line->GetSwitchValueASCII(switches::kRemoteDebuggingTargets);
918 std::vector<std::string> addresses = base::SplitString(
919 value, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
920 std::set<net::HostPortPair> targets;
921 for (const std::string& address : addresses) {
922 net::HostPortPair target = net::HostPortPair::FromString(address);
923 if (target.IsEmpty()) {
924 LOG(WARNING) << "Invalid target: " << address;
925 continue;
927 targets.insert(target);
929 if (targets.empty())
930 return nullptr;
931 return new TCPDeviceProvider(targets);
934 void DevToolsAndroidBridge::CreateDeviceProviders() {
935 AndroidDeviceManager::DeviceProviders device_providers;
937 if (scoped_refptr<TCPDeviceProvider> provider = CreateTCPDeviceProvider())
938 device_providers.push_back(provider);
939 device_providers.push_back(new AdbDeviceProvider());
941 PrefService* service = profile_->GetPrefs();
942 const PrefService::Preference* pref =
943 service->FindPreference(prefs::kDevToolsDiscoverUsbDevicesEnabled);
944 const base::Value* pref_value = pref->GetValue();
946 bool enabled;
947 if (pref_value->GetAsBoolean(&enabled) && enabled) {
948 device_providers.push_back(new UsbDeviceProvider(profile_));
951 if (IsWebRTCDeviceProviderEnabled()) {
952 device_providers.push_back(
953 new WebRTCDeviceProvider(profile_, signin_manager_, token_service_));
956 device_manager_->SetDeviceProviders(device_providers);
957 if (NeedsDeviceListPolling()) {
958 StopDeviceListPolling();
959 StartDeviceListPolling();