Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / devtools / device / devtools_android_bridge.cc
blobff1868a511f54cac64e46566ae1d6fa4b3c9b49a
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 base::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;
397 proxy_ = nullptr;
400 void DevToolsAndroidBridge::AgentHostDelegate::SendMessageToBackend(
401 const std::string& message) {
402 // We could have detached due to physical connection being closed.
403 if (!proxy_)
404 return;
405 if (socket_opened_)
406 web_socket_->SendFrame(message);
407 else
408 pending_messages_.push_back(message);
411 void DevToolsAndroidBridge::AgentHostDelegate::OnSocketOpened() {
412 socket_opened_ = true;
413 for (std::vector<std::string>::iterator it = pending_messages_.begin();
414 it != pending_messages_.end(); ++it) {
415 SendMessageToBackend(*it);
417 pending_messages_.clear();
420 void DevToolsAndroidBridge::AgentHostDelegate::OnFrameRead(
421 const std::string& message) {
422 if (proxy_)
423 proxy_->DispatchOnClientHost(message);
426 void DevToolsAndroidBridge::AgentHostDelegate::OnSocketClosed() {
427 if (proxy_) {
428 std::string message = "{ \"method\": \"Inspector.detached\", "
429 "\"params\": { \"reason\": \"Connection lost.\"} }";
430 proxy_->DispatchOnClientHost(message);
431 Detach();
435 //// RemotePageTarget ----------------------------------------------
437 class DevToolsAndroidBridge::RemotePageTarget : public DevToolsTargetImpl {
438 public:
439 RemotePageTarget(DevToolsAndroidBridge* bridge,
440 const BrowserId& browser_id,
441 const base::DictionaryValue& value);
442 ~RemotePageTarget() override;
444 // DevToolsTargetImpl overrides.
445 std::string GetId() const override;
446 bool IsAttached() const override;
447 bool Activate() const override;
448 bool Close() const override;
449 void Inspect(Profile* profile) const override;
450 void Reload() const override;
452 private:
453 base::WeakPtr<DevToolsAndroidBridge> bridge_;
454 BrowserId browser_id_;
455 std::string target_path_;
456 std::string frontend_url_;
457 std::string remote_id_;
458 std::string remote_type_;
459 std::string local_id_;
460 DISALLOW_COPY_AND_ASSIGN(RemotePageTarget);
463 static std::string GetStringProperty(const base::DictionaryValue& value,
464 const std::string& name) {
465 std::string result;
466 value.GetString(name, &result);
467 return result;
470 static std::string BuildUniqueTargetId(
471 const DevToolsAndroidBridge::BrowserId& browser_id,
472 const base::DictionaryValue& value) {
473 return base::StringPrintf("%s:%s:%s", browser_id.first.c_str(),
474 browser_id.second.c_str(), GetStringProperty(value, "id").c_str());
477 static std::string GetFrontendURL(const base::DictionaryValue& value) {
478 std::string frontend_url = GetStringProperty(value, "devtoolsFrontendUrl");
479 size_t ws_param = frontend_url.find("?ws");
480 if (ws_param != std::string::npos)
481 frontend_url = frontend_url.substr(0, ws_param);
482 if (frontend_url.find("http:") == 0)
483 frontend_url = "https:" + frontend_url.substr(5);
484 return frontend_url;
487 static std::string GetTargetPath(const base::DictionaryValue& value) {
488 std::string target_path = GetStringProperty(value, "webSocketDebuggerUrl");
490 if (target_path.find("ws://") == 0) {
491 size_t pos = target_path.find("/", 5);
492 if (pos == std::string::npos)
493 pos = 5;
494 target_path = target_path.substr(pos);
495 } else {
496 target_path = std::string();
498 return target_path;
501 DevToolsAndroidBridge::RemotePageTarget::RemotePageTarget(
502 DevToolsAndroidBridge* bridge,
503 const BrowserId& browser_id,
504 const base::DictionaryValue& value)
505 : DevToolsTargetImpl(AgentHostDelegate::GetOrCreateAgentHost(
506 bridge,
507 BuildUniqueTargetId(browser_id, value),
508 browser_id,
509 GetTargetPath(value))),
510 bridge_(bridge->AsWeakPtr()),
511 browser_id_(browser_id),
512 target_path_(GetTargetPath(value)),
513 frontend_url_(GetFrontendURL(value)),
514 remote_id_(GetStringProperty(value, "id")),
515 remote_type_(GetStringProperty(value, "type")),
516 local_id_(BuildUniqueTargetId(browser_id, value)) {
517 set_type("adb_page");
518 set_url(GURL(GetStringProperty(value, "url")));
519 set_title(base::UTF16ToUTF8(net::UnescapeForHTML(base::UTF8ToUTF16(
520 GetStringProperty(value, "title")))));
521 set_description(GetStringProperty(value, "description"));
522 set_favicon_url(GURL(GetStringProperty(value, "faviconUrl")));
523 target_path_ = GetTargetPath(value);
526 DevToolsAndroidBridge::RemotePageTarget::~RemotePageTarget() {
529 std::string DevToolsAndroidBridge::RemotePageTarget::GetId() const {
530 return local_id_;
533 bool DevToolsAndroidBridge::RemotePageTarget::IsAttached() const {
534 return target_path_.empty();
537 static void NoOp(int, const std::string&) {}
539 void DevToolsAndroidBridge::RemotePageTarget::Inspect(Profile* profile) const {
540 Activate();
541 bool isWorker = remote_type_ == kTargetTypeWorker ||
542 remote_type_ == kTargetTypeServiceWorker;
543 DevToolsWindow::OpenExternalFrontend(profile, frontend_url_, GetAgentHost(),
544 isWorker);
547 bool DevToolsAndroidBridge::RemotePageTarget::Activate() const {
548 if (!bridge_)
549 return false;
551 std::string request = base::StringPrintf(kActivatePageRequest,
552 remote_id_.c_str());
553 bridge_->SendJsonRequest(browser_id_, request, base::Bind(&NoOp));
554 return true;
557 bool DevToolsAndroidBridge::RemotePageTarget::Close() const {
558 if (!bridge_)
559 return false;
561 std::string request = base::StringPrintf(kClosePageRequest,
562 remote_id_.c_str());
563 bridge_->SendJsonRequest(browser_id_, request, base::Bind(&NoOp));
564 return true;
567 void DevToolsAndroidBridge::RemotePageTarget::Reload() const {
568 if (!bridge_)
569 return;
571 bridge_->SendProtocolCommand(browser_id_, target_path_, kPageReloadCommand,
572 NULL, base::Closure());
575 // DevToolsAndroidBridge::RemotePage ------------------------------------------
577 DevToolsAndroidBridge::RemotePage::RemotePage(const BrowserId& browser_id,
578 const base::DictionaryValue& dict)
579 : browser_id_(browser_id),
580 frontend_url_(GetFrontendURL(dict)),
581 dict_(dict.DeepCopy()) {
584 DevToolsAndroidBridge::RemotePage::~RemotePage() {
587 // DevToolsAndroidBridge::RemoteBrowser ---------------------------------------
589 DevToolsAndroidBridge::RemoteBrowser::RemoteBrowser(
590 const std::string& serial,
591 const AndroidDeviceManager::BrowserInfo& browser_info)
592 : browser_id_(std::make_pair(serial, browser_info.socket_name)),
593 display_name_(browser_info.display_name),
594 user_(browser_info.user),
595 type_(browser_info.type) {
598 bool DevToolsAndroidBridge::RemoteBrowser::IsChrome() {
599 return type_ == AndroidDeviceManager::BrowserInfo::kTypeChrome;
602 std::string DevToolsAndroidBridge::RemoteBrowser::GetId() {
603 return serial() + ":" + socket();
606 DevToolsAndroidBridge::RemoteBrowser::ParsedVersion
607 DevToolsAndroidBridge::RemoteBrowser::GetParsedVersion() {
608 ParsedVersion result;
609 for (const base::StringPiece& part :
610 base::SplitStringPiece(
611 version_, ".", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY)) {
612 int value = 0;
613 base::StringToInt(part, &value);
614 result.push_back(value);
616 return result;
619 DevToolsTargetImpl*
620 DevToolsAndroidBridge::CreatePageTarget(scoped_refptr<RemotePage> page) {
621 return new RemotePageTarget(this, page->browser_id_, *page->dict_);
624 void DevToolsAndroidBridge::SendJsonRequest(
625 const BrowserId& browser_id,
626 const std::string& request,
627 const JsonRequestCallback& callback) {
628 scoped_refptr<AndroidDeviceManager::Device> device(
629 FindDevice(browser_id.first));
630 if (!device.get()) {
631 callback.Run(net::ERR_FAILED, std::string());
632 return;
634 device->SendJsonRequest(browser_id.second, request, callback);
637 void DevToolsAndroidBridge::SendProtocolCommand(
638 const BrowserId& browser_id,
639 const std::string& target_path,
640 const std::string& method,
641 scoped_ptr<base::DictionaryValue> params,
642 const base::Closure callback) {
643 DCHECK_CURRENTLY_ON(BrowserThread::UI);
644 if (target_path.empty())
645 return;
646 scoped_refptr<AndroidDeviceManager::Device> device(
647 FindDevice(browser_id.first));
648 if (!device.get()) {
649 callback.Run();
650 return;
652 new ProtocolCommand(
653 device, browser_id.second, target_path,
654 DevToolsProtocol::SerializeCommand(1, method, params.Pass()),
655 callback);
658 scoped_refptr<content::DevToolsAgentHost>
659 DevToolsAndroidBridge::GetBrowserAgentHost(
660 scoped_refptr<RemoteBrowser> browser) {
661 return AgentHostDelegate::GetOrCreateAgentHost(
662 this,
663 "adb:" + browser->serial() + ":" + browser->socket(),
664 browser->browser_id_,
665 kBrowserTargetSocket);
668 void DevToolsAndroidBridge::SendJsonRequest(
669 const std::string& browser_id_str,
670 const std::string& url,
671 const JsonRequestCallback& callback) {
672 BrowserId browser_id;
673 if (!BrowserIdFromString(browser_id_str, &browser_id)) {
674 callback.Run(net::ERR_FAILED, std::string());
675 return;
677 SendJsonRequest(browser_id, url, callback);
680 scoped_refptr<AndroidDeviceManager::Device> DevToolsAndroidBridge::FindDevice(
681 const std::string& serial) {
682 DeviceMap::iterator it = device_map_.find(serial);
683 return it == device_map_.end() ? nullptr : it->second;
686 void DevToolsAndroidBridge::OpenRemotePage(scoped_refptr<RemoteBrowser> browser,
687 const std::string& input_url) {
688 DCHECK_CURRENTLY_ON(BrowserThread::UI);
689 GURL gurl(input_url);
690 if (!gurl.is_valid()) {
691 gurl = GURL("http://" + input_url);
692 if (!gurl.is_valid())
693 return;
695 std::string url = gurl.spec();
696 RemoteBrowser::ParsedVersion parsed_version = browser->GetParsedVersion();
698 std::string query = net::EscapeQueryParamValue(url, false /* use_plus */);
699 std::string request =
700 base::StringPrintf(kNewPageRequestWithURL, query.c_str());
701 SendJsonRequest(browser->browser_id_, request, base::Bind(&NoOp));
704 DevToolsAndroidBridge::RemoteBrowser::~RemoteBrowser() {
707 // DevToolsAndroidBridge::RemoteDevice ----------------------------------------
709 DevToolsAndroidBridge::RemoteDevice::RemoteDevice(
710 const std::string& serial,
711 const AndroidDeviceManager::DeviceInfo& device_info)
712 : serial_(serial),
713 model_(device_info.model),
714 connected_(device_info.connected),
715 screen_size_(device_info.screen_size) {
716 for (std::vector<AndroidDeviceManager::BrowserInfo>::const_iterator it =
717 device_info.browser_info.begin();
718 it != device_info.browser_info.end();
719 ++it) {
720 browsers_.push_back(new RemoteBrowser(serial, *it));
724 DevToolsAndroidBridge::RemoteDevice::~RemoteDevice() {
727 // DevToolsAndroidBridge ------------------------------------------------------
729 DevToolsAndroidBridge::DevToolsAndroidBridge(
730 Profile* profile,
731 SigninManagerBase* signin_manager,
732 ProfileOAuth2TokenService* const token_service)
733 : profile_(profile),
734 signin_manager_(signin_manager),
735 token_service_(token_service),
736 device_manager_(AndroidDeviceManager::Create()),
737 task_scheduler_(base::Bind(&DevToolsAndroidBridge::ScheduleTaskDefault)),
738 port_forwarding_controller_(new PortForwardingController(profile, this)),
739 weak_factory_(this) {
740 DCHECK_CURRENTLY_ON(BrowserThread::UI);
741 pref_change_registrar_.Init(profile_->GetPrefs());
742 pref_change_registrar_.Add(prefs::kDevToolsDiscoverUsbDevicesEnabled,
743 base::Bind(&DevToolsAndroidBridge::CreateDeviceProviders,
744 base::Unretained(this)));
745 CreateDeviceProviders();
748 void DevToolsAndroidBridge::AddDeviceListListener(
749 DeviceListListener* listener) {
750 DCHECK_CURRENTLY_ON(BrowserThread::UI);
751 bool polling_was_off = !NeedsDeviceListPolling();
752 device_list_listeners_.push_back(listener);
753 if (polling_was_off)
754 StartDeviceListPolling();
757 void DevToolsAndroidBridge::RemoveDeviceListListener(
758 DeviceListListener* listener) {
759 DCHECK_CURRENTLY_ON(BrowserThread::UI);
760 DeviceListListeners::iterator it = std::find(
761 device_list_listeners_.begin(), device_list_listeners_.end(), listener);
762 DCHECK(it != device_list_listeners_.end());
763 device_list_listeners_.erase(it);
764 if (!NeedsDeviceListPolling())
765 StopDeviceListPolling();
768 void DevToolsAndroidBridge::AddDeviceCountListener(
769 DeviceCountListener* listener) {
770 device_count_listeners_.push_back(listener);
771 if (device_count_listeners_.size() == 1)
772 StartDeviceCountPolling();
775 void DevToolsAndroidBridge::RemoveDeviceCountListener(
776 DeviceCountListener* listener) {
777 DCHECK_CURRENTLY_ON(BrowserThread::UI);
778 DeviceCountListeners::iterator it = std::find(
779 device_count_listeners_.begin(), device_count_listeners_.end(), listener);
780 DCHECK(it != device_count_listeners_.end());
781 device_count_listeners_.erase(it);
782 if (device_count_listeners_.empty())
783 StopDeviceCountPolling();
786 void DevToolsAndroidBridge::AddPortForwardingListener(
787 PortForwardingListener* listener) {
788 bool polling_was_off = !NeedsDeviceListPolling();
789 port_forwarding_listeners_.push_back(listener);
790 if (polling_was_off)
791 StartDeviceListPolling();
794 void DevToolsAndroidBridge::RemovePortForwardingListener(
795 PortForwardingListener* listener) {
796 PortForwardingListeners::iterator it = std::find(
797 port_forwarding_listeners_.begin(),
798 port_forwarding_listeners_.end(),
799 listener);
800 DCHECK(it != port_forwarding_listeners_.end());
801 port_forwarding_listeners_.erase(it);
802 if (!NeedsDeviceListPolling())
803 StopDeviceListPolling();
806 bool DevToolsAndroidBridge::HasDevToolsWindow(const std::string& agent_id) {
807 DCHECK_CURRENTLY_ON(BrowserThread::UI);
808 return host_delegates_.find(agent_id) != host_delegates_.end();
811 DevToolsAndroidBridge::~DevToolsAndroidBridge() {
812 DCHECK_CURRENTLY_ON(BrowserThread::UI);
813 DCHECK(device_list_listeners_.empty());
814 DCHECK(device_count_listeners_.empty());
815 DCHECK(port_forwarding_listeners_.empty());
818 void DevToolsAndroidBridge::StartDeviceListPolling() {
819 device_list_callback_.Reset(
820 base::Bind(&DevToolsAndroidBridge::ReceivedDeviceList, AsWeakPtr()));
821 RequestDeviceList(device_list_callback_.callback());
824 void DevToolsAndroidBridge::StopDeviceListPolling() {
825 device_list_callback_.Cancel();
826 device_map_.clear();
829 bool DevToolsAndroidBridge::NeedsDeviceListPolling() {
830 return !device_list_listeners_.empty() || !port_forwarding_listeners_.empty();
833 void DevToolsAndroidBridge::RequestDeviceList(
834 const DeviceListCallback& callback) {
835 DCHECK_CURRENTLY_ON(BrowserThread::UI);
837 if (!NeedsDeviceListPolling() ||
838 !callback.Equals(device_list_callback_.callback()))
839 return;
841 new DiscoveryRequest(device_manager_.get(), callback);
844 void DevToolsAndroidBridge::ReceivedDeviceList(
845 const CompleteDevices& complete_devices) {
846 DCHECK_CURRENTLY_ON(BrowserThread::UI);
848 device_map_.clear();
849 RemoteDevices remote_devices;
850 for (const auto& pair : complete_devices) {
851 device_map_[pair.first->serial()] = pair.first;
852 remote_devices.push_back(pair.second);
855 DeviceListListeners copy(device_list_listeners_);
856 for (DeviceListListeners::iterator it = copy.begin(); it != copy.end(); ++it)
857 (*it)->DeviceListChanged(remote_devices);
859 ForwardingStatus status =
860 port_forwarding_controller_->DeviceListChanged(remote_devices);
861 PortForwardingListeners forwarding_listeners(port_forwarding_listeners_);
862 for (PortForwardingListeners::iterator it = forwarding_listeners.begin();
863 it != forwarding_listeners.end(); ++it) {
864 (*it)->PortStatusChanged(status);
867 if (!NeedsDeviceListPolling())
868 return;
870 task_scheduler_.Run(
871 base::Bind(&DevToolsAndroidBridge::RequestDeviceList,
872 AsWeakPtr(), device_list_callback_.callback()));
875 void DevToolsAndroidBridge::StartDeviceCountPolling() {
876 device_count_callback_.Reset(
877 base::Bind(&DevToolsAndroidBridge::ReceivedDeviceCount, AsWeakPtr()));
878 RequestDeviceCount(device_count_callback_.callback());
881 void DevToolsAndroidBridge::StopDeviceCountPolling() {
882 device_count_callback_.Cancel();
885 void DevToolsAndroidBridge::RequestDeviceCount(
886 const base::Callback<void(int)>& callback) {
887 DCHECK_CURRENTLY_ON(BrowserThread::UI);
889 if (device_count_listeners_.empty() ||
890 !callback.Equals(device_count_callback_.callback()))
891 return;
893 UsbDeviceProvider::CountDevices(callback);
896 void DevToolsAndroidBridge::ReceivedDeviceCount(int count) {
897 DCHECK_CURRENTLY_ON(BrowserThread::UI);
899 DeviceCountListeners copy(device_count_listeners_);
900 for (DeviceCountListeners::iterator it = copy.begin(); it != copy.end(); ++it)
901 (*it)->DeviceCountChanged(count);
903 if (device_count_listeners_.empty())
904 return;
906 task_scheduler_.Run(
907 base::Bind(&DevToolsAndroidBridge::RequestDeviceCount,
908 AsWeakPtr(), device_count_callback_.callback()));
911 // static
912 void DevToolsAndroidBridge::ScheduleTaskDefault(const base::Closure& task) {
913 BrowserThread::PostDelayedTask(
914 BrowserThread::UI,
915 FROM_HERE,
916 task,
917 base::TimeDelta::FromMilliseconds(kAdbPollingIntervalMs));
920 static scoped_refptr<TCPDeviceProvider> CreateTCPDeviceProvider() {
921 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
922 if (!command_line->HasSwitch(switches::kRemoteDebuggingTargets))
923 return nullptr;
924 std::string value =
925 command_line->GetSwitchValueASCII(switches::kRemoteDebuggingTargets);
926 std::vector<std::string> addresses = base::SplitString(
927 value, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
928 std::set<net::HostPortPair> targets;
929 for (const std::string& address : addresses) {
930 net::HostPortPair target = net::HostPortPair::FromString(address);
931 if (target.IsEmpty()) {
932 LOG(WARNING) << "Invalid target: " << address;
933 continue;
935 targets.insert(target);
937 if (targets.empty())
938 return nullptr;
939 return new TCPDeviceProvider(targets);
942 void DevToolsAndroidBridge::CreateDeviceProviders() {
943 AndroidDeviceManager::DeviceProviders device_providers;
945 if (scoped_refptr<TCPDeviceProvider> provider = CreateTCPDeviceProvider())
946 device_providers.push_back(provider);
947 device_providers.push_back(new AdbDeviceProvider());
949 PrefService* service = profile_->GetPrefs();
950 const PrefService::Preference* pref =
951 service->FindPreference(prefs::kDevToolsDiscoverUsbDevicesEnabled);
952 const base::Value* pref_value = pref->GetValue();
954 bool enabled;
955 if (pref_value->GetAsBoolean(&enabled) && enabled) {
956 device_providers.push_back(new UsbDeviceProvider(profile_));
959 if (IsWebRTCDeviceProviderEnabled()) {
960 device_providers.push_back(
961 new WebRTCDeviceProvider(profile_, signin_manager_, token_service_));
964 device_manager_->SetDeviceProviders(device_providers);
965 if (NeedsDeviceListPolling()) {
966 StopDeviceListPolling();
967 StartDeviceListPolling();