| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/devtools/device/devtools_android_bridge.h" | 5 #include "chrome/browser/devtools/device/devtools_device_discovery.h" |
| 6 | 6 |
| 7 #include <stddef.h> | |
| 8 #include <algorithm> | |
| 9 #include <map> | |
| 10 #include <set> | |
| 11 #include <utility> | |
| 12 #include <vector> | |
| 13 | |
| 14 #include "base/base64.h" | |
| 15 #include "base/bind.h" | 7 #include "base/bind.h" |
| 16 #include "base/command_line.h" | |
| 17 #include "base/compiler_specific.h" | |
| 18 #include "base/json/json_reader.h" | 8 #include "base/json/json_reader.h" |
| 19 #include "base/lazy_instance.h" | |
| 20 #include "base/macros.h" | |
| 21 #include "base/memory/ptr_util.h" | 9 #include "base/memory/ptr_util.h" |
| 22 #include "base/memory/singleton.h" | |
| 23 #include "base/message_loop/message_loop.h" | |
| 24 #include "base/strings/string_number_conversions.h" | 10 #include "base/strings/string_number_conversions.h" |
| 25 #include "base/strings/string_split.h" | 11 #include "base/strings/string_split.h" |
| 26 #include "base/strings/string_util.h" | 12 #include "base/strings/string_util.h" |
| 27 #include "base/strings/stringprintf.h" | 13 #include "base/strings/stringprintf.h" |
| 28 #include "base/strings/utf_string_conversions.h" | 14 #include "base/strings/utf_string_conversions.h" |
| 29 #include "base/threading/thread.h" | |
| 30 #include "base/values.h" | 15 #include "base/values.h" |
| 31 #include "chrome/browser/devtools/device/adb/adb_device_provider.h" | |
| 32 #include "chrome/browser/devtools/device/port_forwarding_controller.h" | |
| 33 #include "chrome/browser/devtools/device/tcp_device_provider.h" | |
| 34 #include "chrome/browser/devtools/device/usb/usb_device_provider.h" | |
| 35 #include "chrome/browser/devtools/devtools_protocol.h" | 16 #include "chrome/browser/devtools/devtools_protocol.h" |
| 36 #include "chrome/browser/devtools/devtools_window.h" | 17 #include "chrome/browser/devtools/devtools_window.h" |
| 37 #include "chrome/browser/devtools/remote_debugging_server.h" | |
| 38 #include "chrome/browser/profiles/profile.h" | |
| 39 #include "chrome/common/chrome_switches.h" | |
| 40 #include "chrome/common/features.h" | |
| 41 #include "chrome/common/pref_names.h" | |
| 42 #include "components/keyed_service/content/browser_context_dependency_manager.h" | |
| 43 #include "components/prefs/pref_service.h" | |
| 44 #include "components/signin/core/browser/profile_oauth2_token_service.h" | |
| 45 #include "components/signin/core/browser/signin_manager.h" | |
| 46 #include "content/public/browser/devtools_agent_host.h" | 18 #include "content/public/browser/devtools_agent_host.h" |
| 47 #include "content/public/browser/devtools_external_agent_proxy.h" | 19 #include "content/public/browser/devtools_external_agent_proxy.h" |
| 48 #include "content/public/browser/devtools_external_agent_proxy_delegate.h" | 20 #include "content/public/browser/devtools_external_agent_proxy_delegate.h" |
| 49 #include "content/public/browser/user_metrics.h" | 21 #include "content/public/browser/user_metrics.h" |
| 50 #include "net/base/escape.h" | 22 #include "net/base/escape.h" |
| 51 #include "net/base/host_port_pair.h" | |
| 52 #include "net/base/net_errors.h" | |
| 53 | |
| 54 #if BUILDFLAG(ENABLE_SERVICE_DISCOVERY) | |
| 55 #include "chrome/browser/devtools/device/cast_device_provider.h" | |
| 56 #endif | |
| 57 | 23 |
| 58 using content::BrowserThread; | 24 using content::BrowserThread; |
| 59 using content::DevToolsAgentHost; | 25 using content::DevToolsAgentHost; |
| 26 using RemoteBrowser = DevToolsDeviceDiscovery::RemoteBrowser; |
| 27 using RemoteDevice = DevToolsDeviceDiscovery::RemoteDevice; |
| 28 using RemotePage = DevToolsDeviceDiscovery::RemotePage; |
| 60 | 29 |
| 61 namespace { | 30 namespace { |
| 62 | 31 |
| 63 const char kPageListRequest[] = "/json"; | 32 const char kPageListRequest[] = "/json"; |
| 64 const char kVersionRequest[] = "/json/version"; | 33 const char kVersionRequest[] = "/json/version"; |
| 65 const char kClosePageRequest[] = "/json/close/%s"; | 34 const char kClosePageRequest[] = "/json/close/%s"; |
| 66 const char kNewPageRequestWithURL[] = "/json/new?%s"; | |
| 67 const char kActivatePageRequest[] = "/json/activate/%s"; | 35 const char kActivatePageRequest[] = "/json/activate/%s"; |
| 68 const char kBrowserTargetSocket[] = "/devtools/browser"; | 36 const char kBrowserTargetSocket[] = "/devtools/browser"; |
| 69 const int kAdbPollingIntervalMs = 1000; | 37 const int kPollingIntervalMs = 1000; |
| 70 | 38 |
| 71 const char kPageReloadCommand[] = "Page.reload"; | 39 const char kPageReloadCommand[] = "Page.reload"; |
| 72 | 40 |
| 73 const char kWebViewSocketPrefix[] = "webview_devtools_remote"; | 41 const char kWebViewSocketPrefix[] = "webview_devtools_remote"; |
| 74 | 42 |
| 75 const char kChromeDiscoveryURL[] = "localhost:9222"; | |
| 76 const char kNodeDiscoveryURL[] = "localhost:9229"; | |
| 77 | |
| 78 bool BrowserIdFromString(const std::string& browser_id_str, | |
| 79 std::string* serial, | |
| 80 std::string* browser_id) { | |
| 81 size_t colon_pos = browser_id_str.find(':'); | |
| 82 if (colon_pos == std::string::npos) | |
| 83 return false; | |
| 84 *serial = browser_id_str.substr(0, colon_pos); | |
| 85 *browser_id = browser_id_str.substr(colon_pos + 1); | |
| 86 return true; | |
| 87 } | |
| 88 | |
| 89 static void NoOp(int, const std::string&) {} | 43 static void NoOp(int, const std::string&) {} |
| 90 | 44 |
| 91 } // namespace | 45 static void ScheduleTaskDefault(const base::Closure& task) { |
| 92 | 46 BrowserThread::PostDelayedTask( |
| 93 // DiscoveryRequest ----------------------------------------------------- | 47 BrowserThread::UI, |
| 94 | 48 FROM_HERE, |
| 95 class DevToolsAndroidBridge::DiscoveryRequest | 49 task, |
| 96 : public base::RefCountedThreadSafe<DiscoveryRequest, | 50 base::TimeDelta::FromMilliseconds(kPollingIntervalMs)); |
| 97 BrowserThread::DeleteOnUIThread> { | |
| 98 public: | |
| 99 DiscoveryRequest(AndroidDeviceManager* device_manager, | |
| 100 const DeviceListCallback& callback); | |
| 101 private: | |
| 102 friend struct BrowserThread::DeleteOnThread<BrowserThread::UI>; | |
| 103 friend class base::DeleteHelper<DiscoveryRequest>; | |
| 104 virtual ~DiscoveryRequest(); | |
| 105 | |
| 106 void ReceivedDevices(const AndroidDeviceManager::Devices& devices); | |
| 107 void ReceivedDeviceInfo(scoped_refptr<AndroidDeviceManager::Device> device, | |
| 108 const AndroidDeviceManager::DeviceInfo& device_info); | |
| 109 void ReceivedVersion(scoped_refptr<RemoteBrowser>, | |
| 110 int result, | |
| 111 const std::string& response); | |
| 112 void ReceivedPages(scoped_refptr<AndroidDeviceManager::Device> device, | |
| 113 scoped_refptr<RemoteBrowser>, | |
| 114 int result, | |
| 115 const std::string& response); | |
| 116 | |
| 117 DeviceListCallback callback_; | |
| 118 CompleteDevices complete_devices_; | |
| 119 }; | |
| 120 | |
| 121 DevToolsAndroidBridge::DiscoveryRequest::DiscoveryRequest( | |
| 122 AndroidDeviceManager* device_manager, | |
| 123 const DeviceListCallback& callback) | |
| 124 : callback_(callback) { | |
| 125 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 126 device_manager->QueryDevices( | |
| 127 base::Bind(&DiscoveryRequest::ReceivedDevices, this)); | |
| 128 } | |
| 129 | |
| 130 DevToolsAndroidBridge::DiscoveryRequest::~DiscoveryRequest() { | |
| 131 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 132 callback_.Run(complete_devices_); | |
| 133 } | |
| 134 | |
| 135 void DevToolsAndroidBridge::DiscoveryRequest::ReceivedDevices( | |
| 136 const AndroidDeviceManager::Devices& devices) { | |
| 137 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 138 for (const auto& device : devices) { | |
| 139 device->QueryDeviceInfo( | |
| 140 base::Bind(&DiscoveryRequest::ReceivedDeviceInfo, this, device)); | |
| 141 } | |
| 142 } | |
| 143 | |
| 144 void DevToolsAndroidBridge::DiscoveryRequest::ReceivedDeviceInfo( | |
| 145 scoped_refptr<AndroidDeviceManager::Device> device, | |
| 146 const AndroidDeviceManager::DeviceInfo& device_info) { | |
| 147 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 148 scoped_refptr<RemoteDevice> remote_device = | |
| 149 new RemoteDevice(device->serial(), device_info); | |
| 150 complete_devices_.push_back(std::make_pair(device, remote_device)); | |
| 151 for (RemoteBrowsers::iterator it = remote_device->browsers().begin(); | |
| 152 it != remote_device->browsers().end(); ++it) { | |
| 153 device->SendJsonRequest( | |
| 154 (*it)->socket(), | |
| 155 kVersionRequest, | |
| 156 base::Bind(&DiscoveryRequest::ReceivedVersion, this, *it)); | |
| 157 device->SendJsonRequest( | |
| 158 (*it)->socket(), | |
| 159 kPageListRequest, | |
| 160 base::Bind(&DiscoveryRequest::ReceivedPages, this, device, *it)); | |
| 161 } | |
| 162 } | |
| 163 | |
| 164 void DevToolsAndroidBridge::DiscoveryRequest::ReceivedVersion( | |
| 165 scoped_refptr<RemoteBrowser> browser, | |
| 166 int result, | |
| 167 const std::string& response) { | |
| 168 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 169 if (result < 0) | |
| 170 return; | |
| 171 // Parse version, append to package name if available, | |
| 172 std::unique_ptr<base::Value> value = base::JSONReader::Read(response); | |
| 173 base::DictionaryValue* dict; | |
| 174 if (value && value->GetAsDictionary(&dict)) { | |
| 175 std::string browser_name; | |
| 176 if (dict->GetString("Browser", &browser_name)) { | |
| 177 std::vector<std::string> parts = base::SplitString( | |
| 178 browser_name, "/", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY); | |
| 179 if (parts.size() == 2) | |
| 180 browser->version_ = parts[1]; | |
| 181 else | |
| 182 browser->version_ = browser_name; | |
| 183 } | |
| 184 std::string package; | |
| 185 if (dict->GetString("Android-Package", &package)) { | |
| 186 browser->display_name_ = | |
| 187 AndroidDeviceManager::GetBrowserName(browser->socket(), package); | |
| 188 } | |
| 189 } | |
| 190 } | |
| 191 | |
| 192 void DevToolsAndroidBridge::DiscoveryRequest::ReceivedPages( | |
| 193 scoped_refptr<AndroidDeviceManager::Device> device, | |
| 194 scoped_refptr<RemoteBrowser> browser, | |
| 195 int result, | |
| 196 const std::string& response) { | |
| 197 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 198 if (result < 0) | |
| 199 return; | |
| 200 std::unique_ptr<base::Value> value = base::JSONReader::Read(response); | |
| 201 base::ListValue* list_value; | |
| 202 if (value && value->GetAsList(&list_value)) { | |
| 203 for (const auto& page_value : *list_value) { | |
| 204 base::DictionaryValue* dict; | |
| 205 if (page_value->GetAsDictionary(&dict)) | |
| 206 browser->pages_.push_back( | |
| 207 new RemotePage(device, browser->browser_id_, *dict)); | |
| 208 } | |
| 209 } | |
| 210 } | 51 } |
| 211 | 52 |
| 212 // ProtocolCommand ------------------------------------------------------------ | 53 // ProtocolCommand ------------------------------------------------------------ |
| 213 | 54 |
| 214 namespace { | |
| 215 | |
| 216 class ProtocolCommand | 55 class ProtocolCommand |
| 217 : public AndroidDeviceManager::AndroidWebSocket::Delegate { | 56 : public AndroidDeviceManager::AndroidWebSocket::Delegate { |
| 218 public: | 57 public: |
| 219 ProtocolCommand( | 58 ProtocolCommand( |
| 220 scoped_refptr<AndroidDeviceManager::Device> device, | 59 scoped_refptr<AndroidDeviceManager::Device> device, |
| 221 const std::string& socket, | 60 const std::string& socket, |
| 222 const std::string& target_path, | 61 const std::string& target_path, |
| 223 const std::string& command, | 62 const std::string& command, |
| 224 const base::Closure callback); | 63 const base::Closure callback); |
| 225 | 64 |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 257 | 96 |
| 258 void ProtocolCommand::OnSocketClosed() { | 97 void ProtocolCommand::OnSocketClosed() { |
| 259 delete this; | 98 delete this; |
| 260 } | 99 } |
| 261 | 100 |
| 262 ProtocolCommand::~ProtocolCommand() { | 101 ProtocolCommand::~ProtocolCommand() { |
| 263 if (!callback_.is_null()) | 102 if (!callback_.is_null()) |
| 264 callback_.Run(); | 103 callback_.Run(); |
| 265 } | 104 } |
| 266 | 105 |
| 267 } // namespace | |
| 268 | |
| 269 // static | |
| 270 DevToolsAndroidBridge::Factory* DevToolsAndroidBridge::Factory::GetInstance() { | |
| 271 return base::Singleton<DevToolsAndroidBridge::Factory>::get(); | |
| 272 } | |
| 273 | |
| 274 // static | |
| 275 DevToolsAndroidBridge* DevToolsAndroidBridge::Factory::GetForProfile( | |
| 276 Profile* profile) { | |
| 277 return static_cast<DevToolsAndroidBridge*>(GetInstance()-> | |
| 278 GetServiceForBrowserContext(profile->GetOriginalProfile(), true)); | |
| 279 } | |
| 280 | |
| 281 DevToolsAndroidBridge::Factory::Factory() | |
| 282 : BrowserContextKeyedServiceFactory( | |
| 283 "DevToolsAndroidBridge", | |
| 284 BrowserContextDependencyManager::GetInstance()) { | |
| 285 } | |
| 286 | |
| 287 DevToolsAndroidBridge::Factory::~Factory() {} | |
| 288 | |
| 289 KeyedService* DevToolsAndroidBridge::Factory::BuildServiceInstanceFor( | |
| 290 content::BrowserContext* context) const { | |
| 291 Profile* profile = Profile::FromBrowserContext(context); | |
| 292 | |
| 293 return new DevToolsAndroidBridge(profile); | |
| 294 } | |
| 295 | |
| 296 // AgentHostDelegate ---------------------------------------------------------- | 106 // AgentHostDelegate ---------------------------------------------------------- |
| 297 | 107 |
| 298 class DevToolsAndroidBridge::AgentHostDelegate | 108 class AgentHostDelegate |
| 299 : public content::DevToolsExternalAgentProxyDelegate, | 109 : public content::DevToolsExternalAgentProxyDelegate, |
| 300 public AndroidDeviceManager::AndroidWebSocket::Delegate { | 110 public AndroidDeviceManager::AndroidWebSocket::Delegate { |
| 301 public: | 111 public: |
| 302 static scoped_refptr<content::DevToolsAgentHost> GetOrCreateAgentHost( | 112 static scoped_refptr<content::DevToolsAgentHost> GetOrCreateAgentHost( |
| 303 scoped_refptr<AndroidDeviceManager::Device> device, | 113 scoped_refptr<AndroidDeviceManager::Device> device, |
| 304 const std::string& browser_id, | 114 const std::string& browser_id, |
| 305 const std::string& local_id, | 115 const std::string& local_id, |
| 306 const std::string& target_path, | 116 const std::string& target_path, |
| 307 const std::string& type, | 117 const std::string& type, |
| 308 base::DictionaryValue* value); | 118 base::DictionaryValue* value); |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 392 pos = 5; | 202 pos = 5; |
| 393 target_path = target_path.substr(pos); | 203 target_path = target_path.substr(pos); |
| 394 } else { | 204 } else { |
| 395 target_path = std::string(); | 205 target_path = std::string(); |
| 396 } | 206 } |
| 397 return target_path; | 207 return target_path; |
| 398 } | 208 } |
| 399 | 209 |
| 400 // static | 210 // static |
| 401 scoped_refptr<content::DevToolsAgentHost> | 211 scoped_refptr<content::DevToolsAgentHost> |
| 402 DevToolsAndroidBridge::AgentHostDelegate::GetOrCreateAgentHost( | 212 AgentHostDelegate::GetOrCreateAgentHost( |
| 403 scoped_refptr<AndroidDeviceManager::Device> device, | 213 scoped_refptr<AndroidDeviceManager::Device> device, |
| 404 const std::string& browser_id, | 214 const std::string& browser_id, |
| 405 const std::string& local_id, | 215 const std::string& local_id, |
| 406 const std::string& target_path, | 216 const std::string& target_path, |
| 407 const std::string& type, | 217 const std::string& type, |
| 408 base::DictionaryValue* value) { | 218 base::DictionaryValue* value) { |
| 409 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 219 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 410 scoped_refptr<DevToolsAgentHost> result = | 220 scoped_refptr<DevToolsAgentHost> result = |
| 411 DevToolsAgentHost::GetForId(local_id); | 221 DevToolsAgentHost::GetForId(local_id); |
| 412 if (result) | 222 if (result) |
| 413 return result; | 223 return result; |
| 414 | 224 |
| 415 AgentHostDelegate* delegate = new AgentHostDelegate( | 225 AgentHostDelegate* delegate = new AgentHostDelegate( |
| 416 device, browser_id, local_id, target_path, type, value); | 226 device, browser_id, local_id, target_path, type, value); |
| 417 result = content::DevToolsAgentHost::Forward( | 227 result = content::DevToolsAgentHost::Forward( |
| 418 local_id, base::WrapUnique(delegate)); | 228 local_id, base::WrapUnique(delegate)); |
| 419 delegate->agent_host_ = result.get(); | 229 delegate->agent_host_ = result.get(); |
| 420 return result; | 230 return result; |
| 421 } | 231 } |
| 422 | 232 |
| 423 DevToolsAndroidBridge::AgentHostDelegate::AgentHostDelegate( | 233 AgentHostDelegate::AgentHostDelegate( |
| 424 scoped_refptr<AndroidDeviceManager::Device> device, | 234 scoped_refptr<AndroidDeviceManager::Device> device, |
| 425 const std::string& browser_id, | 235 const std::string& browser_id, |
| 426 const std::string& local_id, | 236 const std::string& local_id, |
| 427 const std::string& target_path, | 237 const std::string& target_path, |
| 428 const std::string& type, | 238 const std::string& type, |
| 429 base::DictionaryValue* value) | 239 base::DictionaryValue* value) |
| 430 : device_(device), | 240 : device_(device), |
| 431 browser_id_(browser_id), | 241 browser_id_(browser_id), |
| 432 local_id_(local_id), | 242 local_id_(local_id), |
| 433 target_path_(target_path), | 243 target_path_(target_path), |
| 434 remote_type_(type), | 244 remote_type_(type), |
| 435 remote_id_(value ? GetStringProperty(value, "id") : ""), | 245 remote_id_(value ? GetStringProperty(value, "id") : ""), |
| 436 frontend_url_(value ? GetFrontendURLFromValue(value) : ""), | 246 frontend_url_(value ? GetFrontendURLFromValue(value) : ""), |
| 437 title_(value ? base::UTF16ToUTF8(net::UnescapeForHTML(base::UTF8ToUTF16( | 247 title_(value ? base::UTF16ToUTF8(net::UnescapeForHTML(base::UTF8ToUTF16( |
| 438 GetStringProperty(value, "title")))) : ""), | 248 GetStringProperty(value, "title")))) : ""), |
| 439 description_(value ? GetStringProperty(value, "description") : ""), | 249 description_(value ? GetStringProperty(value, "description") : ""), |
| 440 url_(GURL(value ? GetStringProperty(value, "url") : "")), | 250 url_(GURL(value ? GetStringProperty(value, "url") : "")), |
| 441 favicon_url_(GURL(value ? GetStringProperty(value, "faviconUrl") : "")), | 251 favicon_url_(GURL(value ? GetStringProperty(value, "faviconUrl") : "")), |
| 442 socket_opened_(false), | 252 socket_opened_(false), |
| 443 agent_host_(nullptr), | 253 agent_host_(nullptr), |
| 444 proxy_(nullptr) { | 254 proxy_(nullptr) { |
| 445 } | 255 } |
| 446 | 256 |
| 447 DevToolsAndroidBridge::AgentHostDelegate::~AgentHostDelegate() { | 257 AgentHostDelegate::~AgentHostDelegate() { |
| 448 } | 258 } |
| 449 | 259 |
| 450 void DevToolsAndroidBridge::AgentHostDelegate::Attach( | 260 void AgentHostDelegate::Attach(content::DevToolsExternalAgentProxy* proxy) { |
| 451 content::DevToolsExternalAgentProxy* proxy) { | |
| 452 proxy_ = proxy; | 261 proxy_ = proxy; |
| 453 content::RecordAction( | 262 content::RecordAction( |
| 454 base::StartsWith(browser_id_, kWebViewSocketPrefix, | 263 base::StartsWith(browser_id_, kWebViewSocketPrefix, |
| 455 base::CompareCase::SENSITIVE) | 264 base::CompareCase::SENSITIVE) |
| 456 ? base::UserMetricsAction("DevTools_InspectAndroidWebView") | 265 ? base::UserMetricsAction("DevTools_InspectAndroidWebView") |
| 457 : base::UserMetricsAction("DevTools_InspectAndroidPage")); | 266 : base::UserMetricsAction("DevTools_InspectAndroidPage")); |
| 458 web_socket_.reset( | 267 web_socket_.reset( |
| 459 device_->CreateWebSocket(browser_id_, target_path_, this)); | 268 device_->CreateWebSocket(browser_id_, target_path_, this)); |
| 460 } | 269 } |
| 461 | 270 |
| 462 void DevToolsAndroidBridge::AgentHostDelegate::Detach() { | 271 void AgentHostDelegate::Detach() { |
| 463 web_socket_.reset(); | 272 web_socket_.reset(); |
| 464 proxy_ = nullptr; | 273 proxy_ = nullptr; |
| 465 } | 274 } |
| 466 | 275 |
| 467 std::string DevToolsAndroidBridge::AgentHostDelegate::GetType() { | 276 std::string AgentHostDelegate::GetType() { |
| 468 return remote_type_; | 277 return remote_type_; |
| 469 } | 278 } |
| 470 | 279 |
| 471 std::string DevToolsAndroidBridge::AgentHostDelegate::GetTitle() { | 280 std::string AgentHostDelegate::GetTitle() { |
| 472 return title_; | 281 return title_; |
| 473 } | 282 } |
| 474 | 283 |
| 475 std::string DevToolsAndroidBridge::AgentHostDelegate::GetDescription() { | 284 std::string AgentHostDelegate::GetDescription() { |
| 476 return description_; | 285 return description_; |
| 477 } | 286 } |
| 478 | 287 |
| 479 GURL DevToolsAndroidBridge::AgentHostDelegate::GetURL() { | 288 GURL AgentHostDelegate::GetURL() { |
| 480 return url_; | 289 return url_; |
| 481 } | 290 } |
| 482 | 291 |
| 483 GURL DevToolsAndroidBridge::AgentHostDelegate::GetFaviconURL() { | 292 GURL AgentHostDelegate::GetFaviconURL() { |
| 484 return favicon_url_; | 293 return favicon_url_; |
| 485 } | 294 } |
| 486 | 295 |
| 487 std::string DevToolsAndroidBridge::AgentHostDelegate::GetFrontendURL() { | 296 std::string AgentHostDelegate::GetFrontendURL() { |
| 488 return frontend_url_; | 297 return frontend_url_; |
| 489 } | 298 } |
| 490 | 299 |
| 491 bool DevToolsAndroidBridge::AgentHostDelegate::Activate() { | 300 bool AgentHostDelegate::Activate() { |
| 492 std::string request = base::StringPrintf(kActivatePageRequest, | 301 std::string request = base::StringPrintf(kActivatePageRequest, |
| 493 remote_id_.c_str()); | 302 remote_id_.c_str()); |
| 494 device_->SendJsonRequest(browser_id_, request, base::Bind(&NoOp)); | 303 device_->SendJsonRequest(browser_id_, request, base::Bind(&NoOp)); |
| 495 return true; | 304 return true; |
| 496 } | 305 } |
| 497 | 306 |
| 498 void DevToolsAndroidBridge::AgentHostDelegate::Reload() { | 307 void AgentHostDelegate::Reload() { |
| 499 SendProtocolCommand(target_path_, kPageReloadCommand, nullptr, | 308 SendProtocolCommand(target_path_, kPageReloadCommand, nullptr, |
| 500 base::Closure()); | 309 base::Closure()); |
| 501 } | 310 } |
| 502 | 311 |
| 503 bool DevToolsAndroidBridge::AgentHostDelegate::Close() { | 312 bool AgentHostDelegate::Close() { |
| 504 std::string request = base::StringPrintf(kClosePageRequest, | 313 std::string request = base::StringPrintf(kClosePageRequest, |
| 505 remote_id_.c_str()); | 314 remote_id_.c_str()); |
| 506 device_->SendJsonRequest(browser_id_, request, base::Bind(&NoOp)); | 315 device_->SendJsonRequest(browser_id_, request, base::Bind(&NoOp)); |
| 507 return true; | 316 return true; |
| 508 } | 317 } |
| 509 | 318 |
| 510 void DevToolsAndroidBridge::AgentHostDelegate::SendMessageToBackend( | 319 void AgentHostDelegate::SendMessageToBackend(const std::string& message) { |
| 511 const std::string& message) { | |
| 512 // We could have detached due to physical connection being closed. | 320 // We could have detached due to physical connection being closed. |
| 513 if (!proxy_) | 321 if (!proxy_) |
| 514 return; | 322 return; |
| 515 if (socket_opened_) | 323 if (socket_opened_) |
| 516 web_socket_->SendFrame(message); | 324 web_socket_->SendFrame(message); |
| 517 else | 325 else |
| 518 pending_messages_.push_back(message); | 326 pending_messages_.push_back(message); |
| 519 } | 327 } |
| 520 | 328 |
| 521 void DevToolsAndroidBridge::AgentHostDelegate::OnSocketOpened() { | 329 void AgentHostDelegate::OnSocketOpened() { |
| 522 socket_opened_ = true; | 330 socket_opened_ = true; |
| 523 for (std::vector<std::string>::iterator it = pending_messages_.begin(); | 331 for (std::vector<std::string>::iterator it = pending_messages_.begin(); |
| 524 it != pending_messages_.end(); ++it) { | 332 it != pending_messages_.end(); ++it) { |
| 525 SendMessageToBackend(*it); | 333 SendMessageToBackend(*it); |
| 526 } | 334 } |
| 527 pending_messages_.clear(); | 335 pending_messages_.clear(); |
| 528 } | 336 } |
| 529 | 337 |
| 530 void DevToolsAndroidBridge::AgentHostDelegate::OnFrameRead( | 338 void AgentHostDelegate::OnFrameRead(const std::string& message) { |
| 531 const std::string& message) { | |
| 532 if (proxy_) | 339 if (proxy_) |
| 533 proxy_->DispatchOnClientHost(message); | 340 proxy_->DispatchOnClientHost(message); |
| 534 } | 341 } |
| 535 | 342 |
| 536 void DevToolsAndroidBridge::AgentHostDelegate::OnSocketClosed() { | 343 void AgentHostDelegate::OnSocketClosed() { |
| 537 if (proxy_) { | 344 if (proxy_) { |
| 538 std::string message = "{ \"method\": \"Inspector.detached\", " | 345 std::string message = "{ \"method\": \"Inspector.detached\", " |
| 539 "\"params\": { \"reason\": \"Connection lost.\"} }"; | 346 "\"params\": { \"reason\": \"Connection lost.\"} }"; |
| 540 proxy_->DispatchOnClientHost(message); | 347 proxy_->DispatchOnClientHost(message); |
| 541 Detach(); | 348 Detach(); |
| 542 } | 349 } |
| 543 } | 350 } |
| 544 | 351 |
| 545 void DevToolsAndroidBridge::AgentHostDelegate::SendProtocolCommand( | 352 void AgentHostDelegate::SendProtocolCommand( |
| 546 const std::string& target_path, | 353 const std::string& target_path, |
| 547 const std::string& method, | 354 const std::string& method, |
| 548 std::unique_ptr<base::DictionaryValue> params, | 355 std::unique_ptr<base::DictionaryValue> params, |
| 549 const base::Closure callback) { | 356 const base::Closure callback) { |
| 550 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 357 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 551 if (target_path.empty()) | 358 if (target_path.empty()) |
| 552 return; | 359 return; |
| 553 new ProtocolCommand( | 360 new ProtocolCommand( |
| 554 device_, browser_id_, target_path, | 361 device_, browser_id_, target_path, |
| 555 DevToolsProtocol::SerializeCommand(1, method, std::move(params)), | 362 DevToolsProtocol::SerializeCommand(1, method, std::move(params)), |
| 556 callback); | 363 callback); |
| 557 } | 364 } |
| 558 | 365 |
| 559 // DevToolsAndroidBridge::RemotePage ------------------------------------------ | 366 } // namespace |
| 560 | 367 |
| 561 DevToolsAndroidBridge::RemotePage::RemotePage( | 368 // DevToolsDeviceDiscovery::DiscoveryRequest ---------------------------------- |
| 369 |
| 370 class DevToolsDeviceDiscovery::DiscoveryRequest |
| 371 : public base::RefCountedThreadSafe<DiscoveryRequest, |
| 372 BrowserThread::DeleteOnUIThread> { |
| 373 public: |
| 374 DiscoveryRequest(AndroidDeviceManager* device_manager, |
| 375 const DevToolsDeviceDiscovery::DeviceListCallback& callback); |
| 376 private: |
| 377 friend struct BrowserThread::DeleteOnThread<BrowserThread::UI>; |
| 378 friend class base::DeleteHelper<DiscoveryRequest>; |
| 379 virtual ~DiscoveryRequest(); |
| 380 |
| 381 void ReceivedDevices(const AndroidDeviceManager::Devices& devices); |
| 382 void ReceivedDeviceInfo(scoped_refptr<AndroidDeviceManager::Device> device, |
| 383 const AndroidDeviceManager::DeviceInfo& device_info); |
| 384 void ReceivedVersion(scoped_refptr<RemoteBrowser>, |
| 385 int result, |
| 386 const std::string& response); |
| 387 void ReceivedPages(scoped_refptr<AndroidDeviceManager::Device> device, |
| 388 scoped_refptr<RemoteBrowser>, |
| 389 int result, |
| 390 const std::string& response); |
| 391 |
| 392 DevToolsDeviceDiscovery::DeviceListCallback callback_; |
| 393 DevToolsDeviceDiscovery::CompleteDevices complete_devices_; |
| 394 }; |
| 395 |
| 396 DevToolsDeviceDiscovery::DiscoveryRequest::DiscoveryRequest( |
| 397 AndroidDeviceManager* device_manager, |
| 398 const DevToolsDeviceDiscovery::DeviceListCallback& callback) |
| 399 : callback_(callback) { |
| 400 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 401 device_manager->QueryDevices( |
| 402 base::Bind(&DiscoveryRequest::ReceivedDevices, this)); |
| 403 } |
| 404 |
| 405 DevToolsDeviceDiscovery::DiscoveryRequest::~DiscoveryRequest() { |
| 406 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 407 callback_.Run(complete_devices_); |
| 408 } |
| 409 |
| 410 void DevToolsDeviceDiscovery::DiscoveryRequest::ReceivedDevices( |
| 411 const AndroidDeviceManager::Devices& devices) { |
| 412 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 413 for (const auto& device : devices) { |
| 414 device->QueryDeviceInfo( |
| 415 base::Bind(&DiscoveryRequest::ReceivedDeviceInfo, this, device)); |
| 416 } |
| 417 } |
| 418 |
| 419 void DevToolsDeviceDiscovery::DiscoveryRequest::ReceivedDeviceInfo( |
| 420 scoped_refptr<AndroidDeviceManager::Device> device, |
| 421 const AndroidDeviceManager::DeviceInfo& device_info) { |
| 422 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 423 scoped_refptr<RemoteDevice> remote_device = |
| 424 new RemoteDevice(device->serial(), device_info); |
| 425 complete_devices_.push_back(std::make_pair(device, remote_device)); |
| 426 for (RemoteBrowsers::iterator it = remote_device->browsers().begin(); |
| 427 it != remote_device->browsers().end(); ++it) { |
| 428 device->SendJsonRequest( |
| 429 (*it)->socket(), |
| 430 kVersionRequest, |
| 431 base::Bind(&DiscoveryRequest::ReceivedVersion, this, *it)); |
| 432 device->SendJsonRequest( |
| 433 (*it)->socket(), |
| 434 kPageListRequest, |
| 435 base::Bind(&DiscoveryRequest::ReceivedPages, this, device, *it)); |
| 436 } |
| 437 } |
| 438 |
| 439 void DevToolsDeviceDiscovery::DiscoveryRequest::ReceivedVersion( |
| 440 scoped_refptr<RemoteBrowser> browser, |
| 441 int result, |
| 442 const std::string& response) { |
| 443 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 444 if (result < 0) |
| 445 return; |
| 446 // Parse version, append to package name if available, |
| 447 std::unique_ptr<base::Value> value = base::JSONReader::Read(response); |
| 448 base::DictionaryValue* dict; |
| 449 if (value && value->GetAsDictionary(&dict)) { |
| 450 std::string browser_name; |
| 451 if (dict->GetString("Browser", &browser_name)) { |
| 452 std::vector<std::string> parts = base::SplitString( |
| 453 browser_name, "/", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY); |
| 454 if (parts.size() == 2) |
| 455 browser->version_ = parts[1]; |
| 456 else |
| 457 browser->version_ = browser_name; |
| 458 } |
| 459 std::string package; |
| 460 if (dict->GetString("Android-Package", &package)) { |
| 461 browser->display_name_ = |
| 462 AndroidDeviceManager::GetBrowserName(browser->socket(), package); |
| 463 } |
| 464 } |
| 465 } |
| 466 |
| 467 void DevToolsDeviceDiscovery::DiscoveryRequest::ReceivedPages( |
| 468 scoped_refptr<AndroidDeviceManager::Device> device, |
| 469 scoped_refptr<RemoteBrowser> browser, |
| 470 int result, |
| 471 const std::string& response) { |
| 472 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 473 if (result < 0) |
| 474 return; |
| 475 std::unique_ptr<base::Value> value = base::JSONReader::Read(response); |
| 476 base::ListValue* list_value; |
| 477 if (value && value->GetAsList(&list_value)) { |
| 478 for (const auto& page_value : *list_value) { |
| 479 base::DictionaryValue* dict; |
| 480 if (page_value->GetAsDictionary(&dict)) |
| 481 browser->pages_.push_back( |
| 482 new RemotePage(device, browser->browser_id_, *dict)); |
| 483 } |
| 484 } |
| 485 } |
| 486 |
| 487 // DevToolsDeviceDiscovery::RemotePage ---------------------------------------- |
| 488 |
| 489 DevToolsDeviceDiscovery::RemotePage::RemotePage( |
| 562 scoped_refptr<AndroidDeviceManager::Device> device, | 490 scoped_refptr<AndroidDeviceManager::Device> device, |
| 563 const std::string& browser_id, | 491 const std::string& browser_id, |
| 564 const base::DictionaryValue& dict) | 492 const base::DictionaryValue& dict) |
| 565 : device_(device), | 493 : device_(device), |
| 566 browser_id_(browser_id), | 494 browser_id_(browser_id), |
| 567 dict_(dict.DeepCopy()) { | 495 dict_(dict.DeepCopy()) { |
| 568 } | 496 } |
| 569 | 497 |
| 570 DevToolsAndroidBridge::RemotePage::~RemotePage() { | 498 DevToolsDeviceDiscovery::RemotePage::~RemotePage() { |
| 571 } | 499 } |
| 572 | 500 |
| 573 scoped_refptr<content::DevToolsAgentHost> | 501 scoped_refptr<content::DevToolsAgentHost> |
| 574 DevToolsAndroidBridge::RemotePage::CreateTarget() { | 502 DevToolsDeviceDiscovery::RemotePage::CreateTarget() { |
| 575 std::string local_id = BuildUniqueTargetId(device_->serial(), | 503 std::string local_id = BuildUniqueTargetId(device_->serial(), |
| 576 browser_id_, | 504 browser_id_, |
| 577 dict_.get()); | 505 dict_.get()); |
| 578 std::string target_path = GetTargetPath(dict_.get()); | 506 std::string target_path = GetTargetPath(dict_.get()); |
| 579 std::string type = GetStringProperty(dict_.get(), "type"); | 507 std::string type = GetStringProperty(dict_.get(), "type"); |
| 580 | 508 |
| 581 return AgentHostDelegate::GetOrCreateAgentHost( | 509 return AgentHostDelegate::GetOrCreateAgentHost( |
| 582 device_, browser_id_, local_id, target_path, type, dict_.get()); | 510 device_, browser_id_, local_id, target_path, type, dict_.get()); |
| 583 } | 511 } |
| 584 | 512 |
| 585 // DevToolsAndroidBridge::RemoteBrowser --------------------------------------- | 513 // DevToolsDeviceDiscovery::RemoteBrowser ------------------------------------- |
| 586 | 514 |
| 587 DevToolsAndroidBridge::RemoteBrowser::RemoteBrowser( | 515 DevToolsDeviceDiscovery::RemoteBrowser::RemoteBrowser( |
| 588 const std::string& serial, | 516 const std::string& serial, |
| 589 const AndroidDeviceManager::BrowserInfo& browser_info) | 517 const AndroidDeviceManager::BrowserInfo& browser_info) |
| 590 : serial_(serial), | 518 : serial_(serial), |
| 591 browser_id_(browser_info.socket_name), | 519 browser_id_(browser_info.socket_name), |
| 592 display_name_(browser_info.display_name), | 520 display_name_(browser_info.display_name), |
| 593 user_(browser_info.user), | 521 user_(browser_info.user), |
| 594 type_(browser_info.type) { | 522 type_(browser_info.type) { |
| 595 } | 523 } |
| 596 | 524 |
| 597 bool DevToolsAndroidBridge::RemoteBrowser::IsChrome() { | 525 bool DevToolsDeviceDiscovery::RemoteBrowser::IsChrome() { |
| 598 return type_ == AndroidDeviceManager::BrowserInfo::kTypeChrome; | 526 return type_ == AndroidDeviceManager::BrowserInfo::kTypeChrome; |
| 599 } | 527 } |
| 600 | 528 |
| 601 std::string DevToolsAndroidBridge::RemoteBrowser::GetId() { | 529 std::string DevToolsDeviceDiscovery::RemoteBrowser::GetId() { |
| 602 return serial() + ":" + socket(); | 530 return serial() + ":" + socket(); |
| 603 } | 531 } |
| 604 | 532 |
| 605 DevToolsAndroidBridge::RemoteBrowser::ParsedVersion | 533 DevToolsDeviceDiscovery::RemoteBrowser::ParsedVersion |
| 606 DevToolsAndroidBridge::RemoteBrowser::GetParsedVersion() { | 534 DevToolsDeviceDiscovery::RemoteBrowser::GetParsedVersion() { |
| 607 ParsedVersion result; | 535 ParsedVersion result; |
| 608 for (const base::StringPiece& part : | 536 for (const base::StringPiece& part : |
| 609 base::SplitStringPiece( | 537 base::SplitStringPiece( |
| 610 version_, ".", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY)) { | 538 version_, ".", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY)) { |
| 611 int value = 0; | 539 int value = 0; |
| 612 base::StringToInt(part, &value); | 540 base::StringToInt(part, &value); |
| 613 result.push_back(value); | 541 result.push_back(value); |
| 614 } | 542 } |
| 615 return result; | 543 return result; |
| 616 } | 544 } |
| 617 | 545 |
| 618 scoped_refptr<content::DevToolsAgentHost> | 546 DevToolsDeviceDiscovery::RemoteBrowser::~RemoteBrowser() { |
| 619 DevToolsAndroidBridge::GetBrowserAgentHost( | |
| 620 scoped_refptr<RemoteBrowser> browser) { | |
| 621 DeviceMap::iterator it = device_map_.find(browser->serial()); | |
| 622 if (it == device_map_.end()) | |
| 623 return nullptr; | |
| 624 | |
| 625 return AgentHostDelegate::GetOrCreateAgentHost( | |
| 626 it->second, | |
| 627 browser->browser_id_, | |
| 628 "adb:" + browser->serial() + ":" + browser->socket(), | |
| 629 kBrowserTargetSocket, DevToolsAgentHost::kTypeBrowser, nullptr); | |
| 630 } | 547 } |
| 631 | 548 |
| 632 void DevToolsAndroidBridge::SendJsonRequest( | 549 // DevToolsDeviceDiscovery::RemoteDevice -------------------------------------- |
| 633 const std::string& browser_id_str, | |
| 634 const std::string& url, | |
| 635 const JsonRequestCallback& callback) { | |
| 636 std::string serial; | |
| 637 std::string browser_id; | |
| 638 if (!BrowserIdFromString(browser_id_str, &serial, &browser_id)) { | |
| 639 callback.Run(net::ERR_FAILED, std::string()); | |
| 640 return; | |
| 641 } | |
| 642 DeviceMap::iterator it = device_map_.find(serial); | |
| 643 if (it == device_map_.end()) { | |
| 644 callback.Run(net::ERR_FAILED, std::string()); | |
| 645 return; | |
| 646 } | |
| 647 it->second->SendJsonRequest(browser_id, url, callback); | |
| 648 } | |
| 649 | 550 |
| 650 void DevToolsAndroidBridge::OpenRemotePage(scoped_refptr<RemoteBrowser> browser, | 551 DevToolsDeviceDiscovery::RemoteDevice::RemoteDevice( |
| 651 const std::string& input_url) { | |
| 652 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 653 GURL gurl(input_url); | |
| 654 if (!gurl.is_valid()) { | |
| 655 gurl = GURL("http://" + input_url); | |
| 656 if (!gurl.is_valid()) | |
| 657 return; | |
| 658 } | |
| 659 std::string url = gurl.spec(); | |
| 660 RemoteBrowser::ParsedVersion parsed_version = browser->GetParsedVersion(); | |
| 661 | |
| 662 std::string query = net::EscapeQueryParamValue(url, false /* use_plus */); | |
| 663 std::string request = | |
| 664 base::StringPrintf(kNewPageRequestWithURL, query.c_str()); | |
| 665 SendJsonRequest(browser->GetId(), request, base::Bind(&NoOp)); | |
| 666 } | |
| 667 | |
| 668 DevToolsAndroidBridge::RemoteBrowser::~RemoteBrowser() { | |
| 669 } | |
| 670 | |
| 671 // DevToolsAndroidBridge::RemoteDevice ---------------------------------------- | |
| 672 | |
| 673 DevToolsAndroidBridge::RemoteDevice::RemoteDevice( | |
| 674 const std::string& serial, | 552 const std::string& serial, |
| 675 const AndroidDeviceManager::DeviceInfo& device_info) | 553 const AndroidDeviceManager::DeviceInfo& device_info) |
| 676 : serial_(serial), | 554 : serial_(serial), |
| 677 model_(device_info.model), | 555 model_(device_info.model), |
| 678 connected_(device_info.connected), | 556 connected_(device_info.connected), |
| 679 screen_size_(device_info.screen_size) { | 557 screen_size_(device_info.screen_size) { |
| 680 for (std::vector<AndroidDeviceManager::BrowserInfo>::const_iterator it = | 558 for (std::vector<AndroidDeviceManager::BrowserInfo>::const_iterator it = |
| 681 device_info.browser_info.begin(); | 559 device_info.browser_info.begin(); |
| 682 it != device_info.browser_info.end(); | 560 it != device_info.browser_info.end(); |
| 683 ++it) { | 561 ++it) { |
| 684 browsers_.push_back(new RemoteBrowser(serial, *it)); | 562 browsers_.push_back(new RemoteBrowser(serial, *it)); |
| 685 } | 563 } |
| 686 } | 564 } |
| 687 | 565 |
| 688 DevToolsAndroidBridge::RemoteDevice::~RemoteDevice() { | 566 DevToolsDeviceDiscovery::RemoteDevice::~RemoteDevice() { |
| 689 } | 567 } |
| 690 | 568 |
| 691 // DevToolsAndroidBridge ------------------------------------------------------ | 569 // DevToolsDeviceDiscovery ---------------------------------------------------- |
| 692 | 570 |
| 693 // static | 571 DevToolsDeviceDiscovery::DevToolsDeviceDiscovery( |
| 694 void DevToolsAndroidBridge::QueryCompleteDevices( | |
| 695 AndroidDeviceManager* device_manager, | 572 AndroidDeviceManager* device_manager, |
| 696 const DeviceListCallback& callback) { | 573 const DeviceListCallback& callback) |
| 697 new DiscoveryRequest(device_manager, callback); | 574 : device_manager_(device_manager), |
| 575 callback_(callback), |
| 576 task_scheduler_(base::Bind(&ScheduleTaskDefault)), |
| 577 weak_factory_(this) { |
| 578 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 579 RequestDeviceList(); |
| 698 } | 580 } |
| 699 | 581 |
| 700 DevToolsAndroidBridge::DevToolsAndroidBridge( | 582 DevToolsDeviceDiscovery::~DevToolsDeviceDiscovery() { |
| 701 Profile* profile) | |
| 702 : profile_(profile), | |
| 703 device_manager_(AndroidDeviceManager::Create()), | |
| 704 task_scheduler_(base::Bind(&DevToolsAndroidBridge::ScheduleTaskDefault)), | |
| 705 port_forwarding_controller_(new PortForwardingController(profile)), | |
| 706 weak_factory_(this) { | |
| 707 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 583 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 708 pref_change_registrar_.Init(profile_->GetPrefs()); | |
| 709 pref_change_registrar_.Add(prefs::kDevToolsDiscoverUsbDevicesEnabled, | |
| 710 base::Bind(&DevToolsAndroidBridge::CreateDeviceProviders, | |
| 711 base::Unretained(this))); | |
| 712 pref_change_registrar_.Add(prefs::kDevToolsTCPDiscoveryConfig, | |
| 713 base::Bind(&DevToolsAndroidBridge::CreateDeviceProviders, | |
| 714 base::Unretained(this))); | |
| 715 pref_change_registrar_.Add(prefs::kDevToolsDiscoverTCPTargetsEnabled, | |
| 716 base::Bind(&DevToolsAndroidBridge::CreateDeviceProviders, | |
| 717 base::Unretained(this))); | |
| 718 base::ListValue* target_discovery = new base::ListValue(); | |
| 719 target_discovery->AppendString(kChromeDiscoveryURL); | |
| 720 target_discovery->AppendString(kNodeDiscoveryURL); | |
| 721 profile->GetPrefs()->SetDefaultPrefValue( | |
| 722 prefs::kDevToolsTCPDiscoveryConfig, target_discovery); | |
| 723 CreateDeviceProviders(); | |
| 724 } | 584 } |
| 725 | 585 |
| 726 void DevToolsAndroidBridge::AddDeviceListListener( | 586 void DevToolsDeviceDiscovery::SetScheduler( |
| 727 DeviceListListener* listener) { | 587 base::Callback<void(const base::Closure&)> scheduler) { |
| 728 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 588 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 729 bool polling_was_off = !NeedsDeviceListPolling(); | 589 task_scheduler_ = scheduler; |
| 730 device_list_listeners_.push_back(listener); | |
| 731 if (polling_was_off) | |
| 732 StartDeviceListPolling(); | |
| 733 } | |
| 734 | |
| 735 void DevToolsAndroidBridge::RemoveDeviceListListener( | |
| 736 DeviceListListener* listener) { | |
| 737 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 738 DeviceListListeners::iterator it = std::find( | |
| 739 device_list_listeners_.begin(), device_list_listeners_.end(), listener); | |
| 740 DCHECK(it != device_list_listeners_.end()); | |
| 741 device_list_listeners_.erase(it); | |
| 742 if (!NeedsDeviceListPolling()) | |
| 743 StopDeviceListPolling(); | |
| 744 } | |
| 745 | |
| 746 void DevToolsAndroidBridge::AddDeviceCountListener( | |
| 747 DeviceCountListener* listener) { | |
| 748 device_count_listeners_.push_back(listener); | |
| 749 if (device_count_listeners_.size() == 1) | |
| 750 StartDeviceCountPolling(); | |
| 751 } | |
| 752 | |
| 753 void DevToolsAndroidBridge::RemoveDeviceCountListener( | |
| 754 DeviceCountListener* listener) { | |
| 755 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 756 DeviceCountListeners::iterator it = std::find( | |
| 757 device_count_listeners_.begin(), device_count_listeners_.end(), listener); | |
| 758 DCHECK(it != device_count_listeners_.end()); | |
| 759 device_count_listeners_.erase(it); | |
| 760 if (device_count_listeners_.empty()) | |
| 761 StopDeviceCountPolling(); | |
| 762 } | |
| 763 | |
| 764 void DevToolsAndroidBridge::AddPortForwardingListener( | |
| 765 PortForwardingListener* listener) { | |
| 766 bool polling_was_off = !NeedsDeviceListPolling(); | |
| 767 port_forwarding_listeners_.push_back(listener); | |
| 768 if (polling_was_off) | |
| 769 StartDeviceListPolling(); | |
| 770 } | |
| 771 | |
| 772 void DevToolsAndroidBridge::RemovePortForwardingListener( | |
| 773 PortForwardingListener* listener) { | |
| 774 PortForwardingListeners::iterator it = std::find( | |
| 775 port_forwarding_listeners_.begin(), | |
| 776 port_forwarding_listeners_.end(), | |
| 777 listener); | |
| 778 DCHECK(it != port_forwarding_listeners_.end()); | |
| 779 port_forwarding_listeners_.erase(it); | |
| 780 if (!NeedsDeviceListPolling()) | |
| 781 StopDeviceListPolling(); | |
| 782 } | |
| 783 | |
| 784 DevToolsAndroidBridge::~DevToolsAndroidBridge() { | |
| 785 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 786 DCHECK(device_list_listeners_.empty()); | |
| 787 DCHECK(device_count_listeners_.empty()); | |
| 788 DCHECK(port_forwarding_listeners_.empty()); | |
| 789 } | |
| 790 | |
| 791 void DevToolsAndroidBridge::StartDeviceListPolling() { | |
| 792 device_list_callback_.Reset( | |
| 793 base::Bind(&DevToolsAndroidBridge::ReceivedDeviceList, AsWeakPtr())); | |
| 794 RequestDeviceList(device_list_callback_.callback()); | |
| 795 } | |
| 796 | |
| 797 void DevToolsAndroidBridge::StopDeviceListPolling() { | |
| 798 device_list_callback_.Cancel(); | |
| 799 device_map_.clear(); | |
| 800 port_forwarding_controller_->CloseAllConnections(); | |
| 801 } | |
| 802 | |
| 803 bool DevToolsAndroidBridge::NeedsDeviceListPolling() { | |
| 804 return !device_list_listeners_.empty() || !port_forwarding_listeners_.empty(); | |
| 805 } | |
| 806 | |
| 807 void DevToolsAndroidBridge::RequestDeviceList( | |
| 808 const DeviceListCallback& callback) { | |
| 809 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 810 | |
| 811 if (!NeedsDeviceListPolling() || | |
| 812 !callback.Equals(device_list_callback_.callback())) | |
| 813 return; | |
| 814 | |
| 815 new DiscoveryRequest(device_manager_.get(), callback); | |
| 816 } | |
| 817 | |
| 818 void DevToolsAndroidBridge::ReceivedDeviceList( | |
| 819 const CompleteDevices& complete_devices) { | |
| 820 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 821 | |
| 822 device_map_.clear(); | |
| 823 RemoteDevices remote_devices; | |
| 824 for (const auto& pair : complete_devices) { | |
| 825 device_map_[pair.first->serial()] = pair.first; | |
| 826 remote_devices.push_back(pair.second); | |
| 827 } | |
| 828 | |
| 829 DeviceListListeners copy(device_list_listeners_); | |
| 830 for (DeviceListListeners::iterator it = copy.begin(); it != copy.end(); ++it) | |
| 831 (*it)->DeviceListChanged(remote_devices); | |
| 832 | |
| 833 ForwardingStatus status = | |
| 834 port_forwarding_controller_->DeviceListChanged(complete_devices); | |
| 835 PortForwardingListeners forwarding_listeners(port_forwarding_listeners_); | |
| 836 for (PortForwardingListeners::iterator it = forwarding_listeners.begin(); | |
| 837 it != forwarding_listeners.end(); ++it) { | |
| 838 (*it)->PortStatusChanged(status); | |
| 839 } | |
| 840 | |
| 841 if (!NeedsDeviceListPolling()) | |
| 842 return; | |
| 843 | |
| 844 task_scheduler_.Run( | |
| 845 base::Bind(&DevToolsAndroidBridge::RequestDeviceList, | |
| 846 AsWeakPtr(), device_list_callback_.callback())); | |
| 847 } | |
| 848 | |
| 849 void DevToolsAndroidBridge::StartDeviceCountPolling() { | |
| 850 device_count_callback_.Reset( | |
| 851 base::Bind(&DevToolsAndroidBridge::ReceivedDeviceCount, AsWeakPtr())); | |
| 852 RequestDeviceCount(device_count_callback_.callback()); | |
| 853 } | |
| 854 | |
| 855 void DevToolsAndroidBridge::StopDeviceCountPolling() { | |
| 856 device_count_callback_.Cancel(); | |
| 857 } | |
| 858 | |
| 859 void DevToolsAndroidBridge::RequestDeviceCount( | |
| 860 const base::Callback<void(int)>& callback) { | |
| 861 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 862 | |
| 863 if (device_count_listeners_.empty() || | |
| 864 !callback.Equals(device_count_callback_.callback())) | |
| 865 return; | |
| 866 | |
| 867 UsbDeviceProvider::CountDevices(callback); | |
| 868 } | |
| 869 | |
| 870 void DevToolsAndroidBridge::ReceivedDeviceCount(int count) { | |
| 871 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 872 | |
| 873 DeviceCountListeners copy(device_count_listeners_); | |
| 874 for (DeviceCountListeners::iterator it = copy.begin(); it != copy.end(); ++it) | |
| 875 (*it)->DeviceCountChanged(count); | |
| 876 | |
| 877 if (device_count_listeners_.empty()) | |
| 878 return; | |
| 879 | |
| 880 task_scheduler_.Run( | |
| 881 base::Bind(&DevToolsAndroidBridge::RequestDeviceCount, | |
| 882 AsWeakPtr(), device_count_callback_.callback())); | |
| 883 } | 590 } |
| 884 | 591 |
| 885 // static | 592 // static |
| 886 void DevToolsAndroidBridge::ScheduleTaskDefault(const base::Closure& task) { | 593 scoped_refptr<content::DevToolsAgentHost> |
| 887 BrowserThread::PostDelayedTask( | 594 DevToolsDeviceDiscovery::CreateBrowserAgentHost( |
| 888 BrowserThread::UI, | 595 scoped_refptr<AndroidDeviceManager::Device> device, |
| 889 FROM_HERE, | 596 scoped_refptr<RemoteBrowser> browser) { |
| 890 task, | 597 return AgentHostDelegate::GetOrCreateAgentHost( |
| 891 base::TimeDelta::FromMilliseconds(kAdbPollingIntervalMs)); | 598 device, |
| 599 browser->browser_id_, |
| 600 "adb:" + browser->serial() + ":" + browser->socket(), |
| 601 kBrowserTargetSocket, DevToolsAgentHost::kTypeBrowser, nullptr); |
| 892 } | 602 } |
| 893 | 603 |
| 894 static std::set<net::HostPortPair> ParseTargetDiscoveryPreferenceValue( | 604 void DevToolsDeviceDiscovery::RequestDeviceList() { |
| 895 const base::ListValue* preferenceValue) { | 605 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 896 std::set<net::HostPortPair> targets; | 606 new DiscoveryRequest( |
| 897 if (!preferenceValue || preferenceValue->empty()) | 607 device_manager_, |
| 898 return targets; | 608 base::Bind(&DevToolsDeviceDiscovery::ReceivedDeviceList, |
| 899 std::string address; | 609 weak_factory_.GetWeakPtr())); |
| 900 for (size_t i = 0; i < preferenceValue->GetSize(); i++) { | |
| 901 if (!preferenceValue->GetString(i, &address)) | |
| 902 continue; | |
| 903 net::HostPortPair target = net::HostPortPair::FromString(address); | |
| 904 if (target.IsEmpty()) { | |
| 905 LOG(WARNING) << "Invalid target: " << address; | |
| 906 continue; | |
| 907 } | |
| 908 targets.insert(target); | |
| 909 } | |
| 910 return targets; | |
| 911 } | 610 } |
| 912 | 611 |
| 913 static scoped_refptr<TCPDeviceProvider> CreateTCPDeviceProvider( | 612 void DevToolsDeviceDiscovery::ReceivedDeviceList( |
| 914 const base::ListValue* targetDiscoveryConfig) { | 613 const CompleteDevices& complete_devices) { |
| 915 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); | 614 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 916 std::set<net::HostPortPair> targets = | 615 task_scheduler_.Run(base::Bind(&DevToolsDeviceDiscovery::RequestDeviceList, |
| 917 ParseTargetDiscoveryPreferenceValue(targetDiscoveryConfig); | 616 weak_factory_.GetWeakPtr())); |
| 918 if (targets.empty() && | 617 // |callback_| should be run last as it may destroy |this|. |
| 919 !command_line->HasSwitch(switches::kRemoteDebuggingTargets)) | 618 callback_.Run(complete_devices); |
| 920 return nullptr; | |
| 921 std::string value = | |
| 922 command_line->GetSwitchValueASCII(switches::kRemoteDebuggingTargets); | |
| 923 std::vector<std::string> addresses = base::SplitString( | |
| 924 value, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); | |
| 925 for (const std::string& address : addresses) { | |
| 926 net::HostPortPair target = net::HostPortPair::FromString(address); | |
| 927 if (target.IsEmpty()) { | |
| 928 LOG(WARNING) << "Invalid target: " << address; | |
| 929 continue; | |
| 930 } | |
| 931 targets.insert(target); | |
| 932 } | |
| 933 if (targets.empty()) | |
| 934 return nullptr; | |
| 935 return new TCPDeviceProvider(targets); | |
| 936 } | 619 } |
| 937 | 620 |
| 938 void DevToolsAndroidBridge::CreateDeviceProviders() { | 621 namespace { |
| 939 AndroidDeviceManager::DeviceProviders device_providers; | |
| 940 PrefService* service = profile_->GetPrefs(); | |
| 941 const base::ListValue* targets = | |
| 942 service->GetBoolean(prefs::kDevToolsDiscoverTCPTargetsEnabled) | |
| 943 ? service->GetList(prefs::kDevToolsTCPDiscoveryConfig) | |
| 944 : nullptr; | |
| 945 scoped_refptr<TCPDeviceProvider> provider = CreateTCPDeviceProvider(targets); | |
| 946 if (tcp_provider_callback_) | |
| 947 tcp_provider_callback_.Run(provider); | |
| 948 | 622 |
| 949 if (provider) | 623 class OnceWrapper { |
| 950 device_providers.push_back(provider); | 624 public: |
| 951 | 625 OnceWrapper(AndroidDeviceManager* device_manager, |
| 952 #if BUILDFLAG(ENABLE_SERVICE_DISCOVERY) | 626 const DevToolsDeviceDiscovery::DeviceListCallback& callback) |
| 953 device_providers.push_back(new CastDeviceProvider()); | 627 : callback_(callback) { |
| 954 #endif | 628 discovery_.reset(new DevToolsDeviceDiscovery(device_manager, |
| 955 | 629 base::Bind(&OnceWrapper::Callback, base::Unretained(this)))); |
| 956 device_providers.push_back(new AdbDeviceProvider()); | 630 discovery_->SetScheduler(base::Bind(&OnceWrapper::NoOp)); |
| 957 | |
| 958 const PrefService::Preference* pref = | |
| 959 service->FindPreference(prefs::kDevToolsDiscoverUsbDevicesEnabled); | |
| 960 const base::Value* pref_value = pref->GetValue(); | |
| 961 | |
| 962 bool enabled; | |
| 963 if (pref_value->GetAsBoolean(&enabled) && enabled) { | |
| 964 device_providers.push_back(new UsbDeviceProvider(profile_)); | |
| 965 } | 631 } |
| 966 | 632 |
| 967 device_manager_->SetDeviceProviders(device_providers); | 633 private: |
| 968 if (NeedsDeviceListPolling()) { | 634 static void NoOp(const base::Closure&) {} |
| 969 StopDeviceListPolling(); | 635 |
| 970 StartDeviceListPolling(); | 636 void Callback(const DevToolsDeviceDiscovery::CompleteDevices& devices) { |
| 637 callback_.Run(devices); |
| 638 delete this; |
| 971 } | 639 } |
| 640 |
| 641 std::unique_ptr<DevToolsDeviceDiscovery> discovery_; |
| 642 const DevToolsDeviceDiscovery::DeviceListCallback callback_; |
| 643 }; |
| 644 |
| 645 } // namespace |
| 646 |
| 647 // static |
| 648 void DevToolsDeviceDiscovery::DiscoverOnce( |
| 649 AndroidDeviceManager* device_manager, |
| 650 const DeviceListCallback& callback) { |
| 651 new OnceWrapper(device_manager, callback); |
| 972 } | 652 } |
| 973 | |
| 974 void DevToolsAndroidBridge::set_tcp_provider_callback_for_test( | |
| 975 TCPProviderCallback callback) { | |
| 976 tcp_provider_callback_ = callback; | |
| 977 CreateDeviceProviders(); | |
| 978 } | |
| OLD | NEW |