Home | History | Annotate | Download | only in device
      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.
      4 
      5 #include "chrome/browser/devtools/device/devtools_android_bridge.h"
      6 
      7 #include <map>
      8 #include <vector>
      9 
     10 #include "base/base64.h"
     11 #include "base/bind.h"
     12 #include "base/compiler_specific.h"
     13 #include "base/json/json_reader.h"
     14 #include "base/lazy_instance.h"
     15 #include "base/message_loop/message_loop.h"
     16 #include "base/prefs/pref_service.h"
     17 #include "base/strings/string_number_conversions.h"
     18 #include "base/strings/string_util.h"
     19 #include "base/strings/stringprintf.h"
     20 #include "base/strings/utf_string_conversions.h"
     21 #include "base/threading/thread.h"
     22 #include "base/values.h"
     23 #include "chrome/browser/devtools/browser_list_tabcontents_provider.h"
     24 #include "chrome/browser/devtools/device/adb/adb_device_info_query.h"
     25 #include "chrome/browser/devtools/device/adb/adb_device_provider.h"
     26 #include "chrome/browser/devtools/device/port_forwarding_controller.h"
     27 #include "chrome/browser/devtools/device/self_device_provider.h"
     28 #include "chrome/browser/devtools/device/usb/usb_device_provider.h"
     29 #include "chrome/browser/devtools/devtools_protocol.h"
     30 #include "chrome/browser/devtools/devtools_target_impl.h"
     31 #include "chrome/browser/devtools/devtools_window.h"
     32 #include "chrome/browser/profiles/profile.h"
     33 #include "chrome/common/pref_names.h"
     34 #include "components/keyed_service/content/browser_context_dependency_manager.h"
     35 #include "content/public/browser/devtools_agent_host.h"
     36 #include "content/public/browser/devtools_external_agent_proxy.h"
     37 #include "content/public/browser/devtools_external_agent_proxy_delegate.h"
     38 #include "content/public/browser/user_metrics.h"
     39 #include "net/base/escape.h"
     40 
     41 using content::BrowserThread;
     42 
     43 namespace {
     44 
     45 const char kPageListRequest[] = "/json";
     46 const char kVersionRequest[] = "/json/version";
     47 const char kClosePageRequest[] = "/json/close/%s";
     48 const char kNewPageRequest[] = "/json/new";
     49 const char kNewPageRequestWithURL[] = "/json/new?%s";
     50 const char kActivatePageRequest[] = "/json/activate/%s";
     51 const char kBrowserTargetSocket[] = "/devtools/browser";
     52 const int kAdbPollingIntervalMs = 1000;
     53 
     54 const char kUrlParam[] = "url";
     55 const char kPageReloadCommand[] = "Page.reload";
     56 const char kPageNavigateCommand[] = "Page.navigate";
     57 
     58 const int kMinVersionNewWithURL = 32;
     59 const int kNewPageNavigateDelayMs = 500;
     60 
     61 // DiscoveryRequest -----------------------------------------------------
     62 
     63 class DiscoveryRequest : public base::RefCountedThreadSafe<
     64     DiscoveryRequest,
     65     BrowserThread::DeleteOnUIThread> {
     66  public:
     67   typedef AndroidDeviceManager::Device Device;
     68   typedef AndroidDeviceManager::Devices Devices;
     69   typedef AndroidDeviceManager::DeviceInfo DeviceInfo;
     70   typedef DevToolsAndroidBridge::RemoteDevice RemoteDevice;
     71   typedef DevToolsAndroidBridge::RemoteDevices RemoteDevices;
     72   typedef DevToolsAndroidBridge::RemoteBrowser RemoteBrowser;
     73   typedef DevToolsAndroidBridge::RemoteBrowsers RemoteBrowsers;
     74   typedef base::Callback<void(const RemoteDevices&)> DiscoveryCallback;
     75 
     76   DiscoveryRequest(AndroidDeviceManager* device_manager,
     77                    const DiscoveryCallback& callback);
     78  private:
     79   friend struct BrowserThread::DeleteOnThread<BrowserThread::UI>;
     80   friend class base::DeleteHelper<DiscoveryRequest>;
     81   virtual ~DiscoveryRequest();
     82 
     83   void ReceivedDevices(const Devices& devices);
     84   void ReceivedDeviceInfo(scoped_refptr<Device> device,
     85                           const DeviceInfo& device_info);
     86   void ReceivedVersion(scoped_refptr<RemoteBrowser>,
     87                        int result,
     88                        const std::string& response);
     89   void ReceivedPages(scoped_refptr<RemoteBrowser>,
     90                      int result,
     91                      const std::string& response);
     92 
     93   DiscoveryCallback callback_;
     94   RemoteDevices remote_devices_;
     95 };
     96 
     97 DiscoveryRequest::DiscoveryRequest(
     98     AndroidDeviceManager* device_manager,
     99     const DiscoveryCallback& callback)
    100     : callback_(callback) {
    101   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    102   device_manager->QueryDevices(
    103       base::Bind(&DiscoveryRequest::ReceivedDevices, this));
    104 }
    105 
    106 DiscoveryRequest::~DiscoveryRequest() {
    107   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    108   callback_.Run(remote_devices_);
    109 }
    110 
    111 void DiscoveryRequest::ReceivedDevices(const Devices& devices) {
    112   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    113   for (Devices::const_iterator it = devices.begin();
    114        it != devices.end(); ++it) {
    115     (*it)->QueryDeviceInfo(
    116         base::Bind(&DiscoveryRequest::ReceivedDeviceInfo, this, *it));
    117   }
    118 }
    119 
    120 void DiscoveryRequest::ReceivedDeviceInfo(scoped_refptr<Device> device,
    121                                           const DeviceInfo& device_info) {
    122   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    123   scoped_refptr<RemoteDevice> remote_device =
    124       new RemoteDevice(device, device_info);
    125   remote_devices_.push_back(remote_device);
    126   for (RemoteBrowsers::iterator it = remote_device->browsers().begin();
    127        it != remote_device->browsers().end(); ++it) {
    128     (*it)->SendJsonRequest(
    129         kVersionRequest,
    130         base::Bind(&DiscoveryRequest::ReceivedVersion, this, *it));
    131     (*it)->SendJsonRequest(
    132         kPageListRequest,
    133         base::Bind(&DiscoveryRequest::ReceivedPages, this, *it));
    134   }
    135 }
    136 
    137 void DiscoveryRequest::ReceivedVersion(scoped_refptr<RemoteBrowser> browser,
    138                                        int result,
    139                                        const std::string& response) {
    140   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    141   if (result < 0)
    142     return;
    143   // Parse version, append to package name if available,
    144   scoped_ptr<base::Value> value(base::JSONReader::Read(response));
    145   base::DictionaryValue* dict;
    146   if (value && value->GetAsDictionary(&dict)) {
    147     std::string browser_name;
    148     if (dict->GetString("Browser", &browser_name)) {
    149       std::vector<std::string> parts;
    150       Tokenize(browser_name, "/", &parts);
    151       if (parts.size() == 2)
    152         browser->set_version(parts[1]);
    153       else
    154         browser->set_version(browser_name);
    155     }
    156     std::string package;
    157     if (dict->GetString("Android-Package", &package)) {
    158       browser->set_display_name(
    159           AdbDeviceInfoQuery::GetDisplayName(browser->socket(), package));
    160     }
    161   }
    162 }
    163 
    164 void DiscoveryRequest::ReceivedPages(scoped_refptr<RemoteBrowser> browser,
    165                                      int result,
    166                                      const std::string& response) {
    167   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    168   if (result < 0)
    169     return;
    170   scoped_ptr<base::Value> value(base::JSONReader::Read(response));
    171   base::ListValue* list_value;
    172   if (value && value->GetAsList(&list_value))
    173     browser->SetPageDescriptors(*list_value);
    174 }
    175 
    176 // ProtocolCommand ------------------------------------------------------------
    177 
    178 class ProtocolCommand
    179     : public DevToolsAndroidBridge::AndroidWebSocket::Delegate {
    180  public:
    181   ProtocolCommand(
    182       scoped_refptr<DevToolsAndroidBridge::RemoteBrowser> browser,
    183       const std::string& debug_url,
    184       const std::string& command,
    185       const base::Closure callback);
    186 
    187  private:
    188   virtual void OnSocketOpened() OVERRIDE;
    189   virtual void OnFrameRead(const std::string& message) OVERRIDE;
    190   virtual void OnSocketClosed() OVERRIDE;
    191   virtual ~ProtocolCommand();
    192 
    193   const std::string command_;
    194   const base::Closure callback_;
    195   scoped_ptr<DevToolsAndroidBridge::AndroidWebSocket> web_socket_;
    196 
    197   DISALLOW_COPY_AND_ASSIGN(ProtocolCommand);
    198 };
    199 
    200 ProtocolCommand::ProtocolCommand(
    201     scoped_refptr<DevToolsAndroidBridge::RemoteBrowser> browser,
    202     const std::string& debug_url,
    203     const std::string& command,
    204     const base::Closure callback)
    205     : command_(command),
    206       callback_(callback),
    207       web_socket_(browser->CreateWebSocket(debug_url, this)) {
    208 }
    209 
    210 void ProtocolCommand::OnSocketOpened() {
    211   web_socket_->SendFrame(command_);
    212 }
    213 
    214 void ProtocolCommand::OnFrameRead(const std::string& message) {
    215   delete this;
    216 }
    217 
    218 void ProtocolCommand::OnSocketClosed() {
    219   delete this;
    220 }
    221 
    222 ProtocolCommand::~ProtocolCommand() {
    223   if (!callback_.is_null())
    224     callback_.Run();
    225 }
    226 
    227 }  // namespace
    228 
    229 class AgentHostDelegate;
    230 
    231 typedef std::map<std::string, AgentHostDelegate*> AgentHostDelegates;
    232 
    233 base::LazyInstance<AgentHostDelegates>::Leaky g_host_delegates =
    234     LAZY_INSTANCE_INITIALIZER;
    235 
    236 DevToolsAndroidBridge::Wrapper::Wrapper(content::BrowserContext* context) {
    237   bridge_ = new DevToolsAndroidBridge(Profile::FromBrowserContext(context));
    238 }
    239 
    240 DevToolsAndroidBridge::Wrapper::~Wrapper() {
    241 }
    242 
    243 DevToolsAndroidBridge* DevToolsAndroidBridge::Wrapper::Get() {
    244   return bridge_.get();
    245 }
    246 
    247 // static
    248 DevToolsAndroidBridge::Factory* DevToolsAndroidBridge::Factory::GetInstance() {
    249   return Singleton<DevToolsAndroidBridge::Factory>::get();
    250 }
    251 
    252 // static
    253 DevToolsAndroidBridge* DevToolsAndroidBridge::Factory::GetForProfile(
    254     Profile* profile) {
    255   DevToolsAndroidBridge::Wrapper* wrapper =
    256       static_cast<DevToolsAndroidBridge::Wrapper*>(GetInstance()->
    257           GetServiceForBrowserContext(profile, true));
    258   return wrapper ? wrapper->Get() : NULL;
    259 }
    260 
    261 DevToolsAndroidBridge::Factory::Factory()
    262     : BrowserContextKeyedServiceFactory(
    263           "DevToolsAndroidBridge",
    264           BrowserContextDependencyManager::GetInstance()) {}
    265 
    266 DevToolsAndroidBridge::Factory::~Factory() {}
    267 
    268 KeyedService* DevToolsAndroidBridge::Factory::BuildServiceInstanceFor(
    269     content::BrowserContext* context) const {
    270   return new DevToolsAndroidBridge::Wrapper(context);
    271 }
    272 
    273 
    274 // AgentHostDelegate ----------------------------------------------------------
    275 
    276 class AgentHostDelegate
    277     : public content::DevToolsExternalAgentProxyDelegate,
    278       public DevToolsAndroidBridge::AndroidWebSocket::Delegate {
    279  public:
    280   static scoped_refptr<content::DevToolsAgentHost> GetOrCreateAgentHost(
    281       const std::string& id,
    282       scoped_refptr<DevToolsAndroidBridge::RemoteBrowser> browser,
    283       const std::string& debug_url);
    284 
    285  private:
    286   AgentHostDelegate(
    287       const std::string& id,
    288       scoped_refptr<DevToolsAndroidBridge::RemoteBrowser> browser,
    289       const std::string& debug_url);
    290   virtual ~AgentHostDelegate();
    291   virtual void Attach(content::DevToolsExternalAgentProxy* proxy) OVERRIDE;
    292   virtual void Detach() OVERRIDE;
    293   virtual void SendMessageToBackend(
    294       const std::string& message) OVERRIDE;
    295   virtual void OnSocketOpened() OVERRIDE;
    296   virtual void OnFrameRead(const std::string& message) OVERRIDE;
    297   virtual void OnSocketClosed() OVERRIDE;
    298 
    299   const std::string id_;
    300   scoped_refptr<DevToolsAndroidBridge::RemoteBrowser> browser_;
    301   const std::string debug_url_;
    302   bool socket_opened_;
    303   bool is_web_view_;
    304   std::vector<std::string> pending_messages_;
    305   scoped_ptr<DevToolsAndroidBridge::AndroidWebSocket> web_socket_;
    306   content::DevToolsAgentHost* agent_host_;
    307   content::DevToolsExternalAgentProxy* proxy_;
    308   DISALLOW_COPY_AND_ASSIGN(AgentHostDelegate);
    309 };
    310 
    311 // static
    312 scoped_refptr<content::DevToolsAgentHost>
    313 AgentHostDelegate::GetOrCreateAgentHost(
    314     const std::string& id,
    315     scoped_refptr<DevToolsAndroidBridge::RemoteBrowser> browser,
    316     const std::string& debug_url) {
    317   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    318   AgentHostDelegates::iterator it = g_host_delegates.Get().find(id);
    319   if (it != g_host_delegates.Get().end())
    320     return it->second->agent_host_;
    321 
    322   AgentHostDelegate* delegate = new AgentHostDelegate(id, browser, debug_url);
    323   scoped_refptr<content::DevToolsAgentHost> result =
    324       content::DevToolsAgentHost::Create(delegate);
    325   delegate->agent_host_ = result.get();
    326   return result;
    327 }
    328 
    329 AgentHostDelegate::AgentHostDelegate(
    330     const std::string& id,
    331     scoped_refptr<DevToolsAndroidBridge::RemoteBrowser> browser,
    332     const std::string& debug_url)
    333     : id_(id),
    334       browser_(browser),
    335       debug_url_(debug_url),
    336       socket_opened_(false),
    337       is_web_view_(browser->IsWebView()),
    338       agent_host_(NULL),
    339       proxy_(NULL) {
    340   g_host_delegates.Get()[id] = this;
    341 }
    342 
    343 AgentHostDelegate::~AgentHostDelegate() {
    344   g_host_delegates.Get().erase(id_);
    345 }
    346 
    347 void AgentHostDelegate::Attach(content::DevToolsExternalAgentProxy* proxy) {
    348   proxy_ = proxy;
    349   content::RecordAction(base::UserMetricsAction(is_web_view_ ?
    350       "DevTools_InspectAndroidWebView" : "DevTools_InspectAndroidPage"));
    351   web_socket_.reset(browser_->CreateWebSocket(debug_url_, this));
    352 }
    353 
    354 void AgentHostDelegate::Detach() {
    355   web_socket_.reset();
    356 }
    357 
    358 void AgentHostDelegate::SendMessageToBackend(const std::string& message) {
    359   if (socket_opened_)
    360     web_socket_->SendFrame(message);
    361   else
    362     pending_messages_.push_back(message);
    363 }
    364 
    365 void AgentHostDelegate::OnSocketOpened() {
    366   socket_opened_ = true;
    367   for (std::vector<std::string>::iterator it = pending_messages_.begin();
    368        it != pending_messages_.end(); ++it) {
    369     SendMessageToBackend(*it);
    370   }
    371   pending_messages_.clear();
    372 }
    373 
    374 void AgentHostDelegate::OnFrameRead(const std::string& message) {
    375   if (proxy_)
    376       proxy_->DispatchOnClientHost(message);
    377 }
    378 
    379 void AgentHostDelegate::OnSocketClosed() {
    380   if (proxy_)
    381     proxy_->ConnectionClosed();
    382 }
    383 
    384 //// RemotePageTarget ----------------------------------------------
    385 
    386 class RemotePageTarget : public DevToolsTargetImpl,
    387                          public DevToolsAndroidBridge::RemotePage {
    388  public:
    389   RemotePageTarget(scoped_refptr<DevToolsAndroidBridge::RemoteBrowser> browser,
    390                    const base::DictionaryValue& value);
    391   virtual ~RemotePageTarget();
    392 
    393   // DevToolsAndroidBridge::RemotePage implementation.
    394   virtual DevToolsTargetImpl* GetTarget() OVERRIDE;
    395   virtual std::string GetFrontendURL() OVERRIDE;
    396 
    397   // DevToolsTargetImpl overrides.
    398   virtual std::string GetId() const OVERRIDE;
    399   virtual bool IsAttached() const OVERRIDE;
    400   virtual bool Activate() const OVERRIDE;
    401   virtual bool Close() const OVERRIDE;
    402   virtual void Inspect(Profile* profile) const OVERRIDE;
    403   virtual void Reload() const OVERRIDE;
    404 
    405   void Navigate(const std::string& url, base::Closure callback) const;
    406 
    407  private:
    408   scoped_refptr<DevToolsAndroidBridge::RemoteBrowser> browser_;
    409   std::string debug_url_;
    410   std::string frontend_url_;
    411   std::string remote_id_;
    412   std::string remote_type_;
    413   std::string local_id_;
    414   DISALLOW_COPY_AND_ASSIGN(RemotePageTarget);
    415 };
    416 
    417 static std::string GetStringProperty(const base::DictionaryValue& value,
    418                                      const std::string& name) {
    419   std::string result;
    420   value.GetString(name, &result);
    421   return result;
    422 }
    423 
    424 static std::string BuildUniqueTargetId(
    425     DevToolsAndroidBridge::RemoteBrowser* browser,
    426     const base::DictionaryValue& value) {
    427   return base::StringPrintf("%s:%s:%s", browser->serial().c_str(),
    428       browser->socket().c_str(), GetStringProperty(value, "id").c_str());
    429 }
    430 
    431 static std::string GetDebugURL(const base::DictionaryValue& value) {
    432   std::string debug_url = GetStringProperty(value, "webSocketDebuggerUrl");
    433 
    434   if (debug_url.find("ws://") == 0)
    435     debug_url = debug_url.substr(5);
    436   else
    437     debug_url = "";
    438   return debug_url;
    439 }
    440 
    441 RemotePageTarget::RemotePageTarget(
    442     scoped_refptr<DevToolsAndroidBridge::RemoteBrowser> browser,
    443     const base::DictionaryValue& value)
    444     : DevToolsTargetImpl(AgentHostDelegate::GetOrCreateAgentHost(
    445                              BuildUniqueTargetId(browser.get(), value),
    446                              browser, GetDebugURL(value))),
    447       browser_(browser),
    448       debug_url_(GetDebugURL(value)),
    449       remote_id_(GetStringProperty(value, "id")),
    450       remote_type_(GetStringProperty(value, "type")),
    451       local_id_(BuildUniqueTargetId(browser.get(), value)) {
    452   set_type("adb_page");
    453   set_url(GURL(GetStringProperty(value, "url")));
    454   set_title(base::UTF16ToUTF8(net::UnescapeForHTML(base::UTF8ToUTF16(
    455       GetStringProperty(value, "title")))));
    456   set_description(GetStringProperty(value, "description"));
    457   set_favicon_url(GURL(GetStringProperty(value, "faviconUrl")));
    458   debug_url_ = GetDebugURL(value);
    459   frontend_url_ = GetStringProperty(value, "devtoolsFrontendUrl");
    460 
    461   size_t ws_param = frontend_url_.find("?ws");
    462   if (ws_param != std::string::npos)
    463     frontend_url_ = frontend_url_.substr(0, ws_param);
    464   if (frontend_url_.find("http:") == 0)
    465     frontend_url_ = "https:" + frontend_url_.substr(5);
    466 }
    467 
    468 RemotePageTarget::~RemotePageTarget() {
    469 }
    470 
    471 DevToolsTargetImpl* RemotePageTarget::GetTarget() {
    472   return this;
    473 }
    474 
    475 std::string RemotePageTarget::GetFrontendURL() {
    476   return frontend_url_;
    477 }
    478 
    479 std::string RemotePageTarget::GetId() const {
    480   return local_id_;
    481 }
    482 
    483 bool RemotePageTarget::IsAttached() const {
    484   return debug_url_.empty();
    485 }
    486 
    487 static void NoOp(int, const std::string&) {}
    488 
    489 void RemotePageTarget::Inspect(Profile* profile) const {
    490   Activate();
    491   bool isWorker = remote_type_ == kTargetTypeWorker ||
    492                   remote_type_ == kTargetTypeServiceWorker;
    493   DevToolsWindow::OpenExternalFrontend(profile, frontend_url_, GetAgentHost(),
    494                                        isWorker);
    495 }
    496 
    497 bool RemotePageTarget::Activate() const {
    498   std::string request = base::StringPrintf(kActivatePageRequest,
    499                                            remote_id_.c_str());
    500   browser_->SendJsonRequest(request, base::Bind(&NoOp));
    501   return true;
    502 }
    503 
    504 bool RemotePageTarget::Close() const {
    505   std::string request = base::StringPrintf(kClosePageRequest,
    506                                            remote_id_.c_str());
    507   browser_->SendJsonRequest(request, base::Bind(&NoOp));
    508   return true;
    509 }
    510 
    511 void RemotePageTarget::Reload() const {
    512   browser_->SendProtocolCommand(debug_url_, kPageReloadCommand, NULL,
    513                                 base::Closure());
    514 }
    515 
    516 void RemotePageTarget::Navigate(const std::string& url,
    517                                 base::Closure callback) const {
    518   base::DictionaryValue params;
    519   params.SetString(kUrlParam, url);
    520   browser_->SendProtocolCommand(debug_url_, kPageNavigateCommand, &params,
    521                                 callback);
    522 }
    523 
    524 // DevToolsAndroidBridge::RemoteBrowser ---------------------------------------
    525 
    526 DevToolsAndroidBridge::RemoteBrowser::RemoteBrowser(
    527     scoped_refptr<Device> device,
    528     const AndroidDeviceManager::BrowserInfo& browser_info)
    529     : device_(device),
    530       socket_(browser_info.socket_name),
    531       display_name_(browser_info.display_name),
    532       type_(browser_info.type),
    533       page_descriptors_(new base::ListValue()) {
    534 }
    535 
    536 bool DevToolsAndroidBridge::RemoteBrowser::IsChrome() const {
    537   return type_ == AndroidDeviceManager::BrowserInfo::kTypeChrome;
    538 }
    539 
    540 bool DevToolsAndroidBridge::RemoteBrowser::IsWebView() const {
    541   return type_ == AndroidDeviceManager::BrowserInfo::kTypeWebView;
    542 }
    543 
    544 DevToolsAndroidBridge::RemoteBrowser::ParsedVersion
    545 DevToolsAndroidBridge::RemoteBrowser::GetParsedVersion() const {
    546   ParsedVersion result;
    547   std::vector<std::string> parts;
    548   Tokenize(version_, ".", &parts);
    549   for (size_t i = 0; i != parts.size(); ++i) {
    550     int value = 0;
    551     base::StringToInt(parts[i], &value);
    552     result.push_back(value);
    553   }
    554   return result;
    555 }
    556 
    557 std::vector<DevToolsAndroidBridge::RemotePage*>
    558 DevToolsAndroidBridge::RemoteBrowser::CreatePages() {
    559   std::vector<DevToolsAndroidBridge::RemotePage*> result;
    560   for (size_t i = 0; i < page_descriptors_->GetSize(); ++i) {
    561     base::Value* item;
    562     page_descriptors_->Get(i, &item);
    563     if (!item)
    564       continue;
    565     base::DictionaryValue* dict;
    566     if (!item->GetAsDictionary(&dict))
    567       continue;
    568     result.push_back(new RemotePageTarget(this, *dict));
    569   }
    570   return result;
    571 }
    572 
    573 void DevToolsAndroidBridge::RemoteBrowser::SetPageDescriptors(
    574     const base::ListValue& list) {
    575   page_descriptors_.reset(list.DeepCopy());
    576 }
    577 
    578 static void RespondOnUIThread(
    579     const DevToolsAndroidBridge::JsonRequestCallback& callback,
    580     int result,
    581     const std::string& response) {
    582   if (callback.is_null())
    583     return;
    584   BrowserThread::PostTask(
    585       BrowserThread::UI, FROM_HERE, base::Bind(callback, result, response));
    586 }
    587 
    588 void DevToolsAndroidBridge::RemoteBrowser::SendJsonRequest(
    589     const std::string& request, const JsonRequestCallback& callback) {
    590   device_->SendJsonRequest(socket_, request, callback);
    591 }
    592 
    593 void DevToolsAndroidBridge::RemoteBrowser::SendProtocolCommand(
    594     const std::string& debug_url,
    595     const std::string& method,
    596     base::DictionaryValue* params,
    597     const base::Closure callback) {
    598   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    599   if (debug_url.empty())
    600     return;
    601   DevToolsProtocol::Command command(1, method, params);
    602   new ProtocolCommand(this, debug_url, command.Serialize(), callback);
    603 }
    604 
    605 void DevToolsAndroidBridge::RemoteBrowser::Open(
    606     const std::string& url,
    607     const DevToolsAndroidBridge::RemotePageCallback& callback) {
    608   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    609   InnerOpen(url, base::Bind(&RemoteBrowser::RespondToOpenOnUIThread,
    610                             this, callback));
    611 }
    612 
    613 scoped_refptr<content::DevToolsAgentHost>
    614 DevToolsAndroidBridge::RemoteBrowser::GetAgentHost() {
    615   return AgentHostDelegate::GetOrCreateAgentHost(
    616       "adb:" + device_->serial() + ":" + socket_, this, kBrowserTargetSocket);
    617 }
    618 
    619 DevToolsAndroidBridge::AndroidWebSocket*
    620 DevToolsAndroidBridge::RemoteBrowser::CreateWebSocket(
    621     const std::string& url,
    622     DevToolsAndroidBridge::AndroidWebSocket::Delegate* delegate) {
    623   return device_->CreateWebSocket(socket_, url, delegate);
    624 }
    625 
    626 void DevToolsAndroidBridge::RemoteBrowser::RespondToOpenOnUIThread(
    627     const DevToolsAndroidBridge::RemotePageCallback& callback,
    628     int result,
    629     const std::string& response) {
    630   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    631   if (result < 0) {
    632     callback.Run(NULL);
    633     return;
    634   }
    635   scoped_ptr<base::Value> value(base::JSONReader::Read(response));
    636   base::DictionaryValue* dict;
    637   if (value && value->GetAsDictionary(&dict)) {
    638     RemotePageTarget* new_page = new RemotePageTarget(this, *dict);
    639     callback.Run(new_page);
    640   }
    641 }
    642 
    643 void DevToolsAndroidBridge::RemoteBrowser::InnerOpen(
    644     const std::string& input_url,
    645     const JsonRequestCallback& callback) {
    646   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    647   GURL gurl(input_url);
    648   if (!gurl.is_valid()) {
    649     gurl = GURL("http://" + input_url);
    650     if (!gurl.is_valid())
    651      return;
    652   }
    653   std::string url = gurl.spec();
    654 
    655   ParsedVersion parsed_version = GetParsedVersion();
    656   if (IsChrome() &&
    657       !parsed_version.empty() &&
    658       parsed_version[0] >= kMinVersionNewWithURL) {
    659     std::string query = net::EscapeQueryParamValue(url, false /* use_plus */);
    660     std::string request =
    661         base::StringPrintf(kNewPageRequestWithURL, query.c_str());
    662     SendJsonRequest(request, callback);
    663   } else {
    664     SendJsonRequest(kNewPageRequest,
    665         base::Bind(&RemoteBrowser::PageCreatedOnUIThread, this,
    666                    callback, url));
    667   }
    668 }
    669 
    670 void DevToolsAndroidBridge::RemoteBrowser::PageCreatedOnUIThread(
    671     const JsonRequestCallback& callback,
    672     const std::string& url, int result, const std::string& response) {
    673   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    674 
    675   if (result < 0)
    676     return;
    677   // Navigating too soon after the page creation breaks navigation history
    678   // (crbug.com/311014). This can be avoided by adding a moderate delay.
    679   BrowserThread::PostDelayedTask(
    680       BrowserThread::UI, FROM_HERE,
    681       base::Bind(&RemoteBrowser::NavigatePageOnUIThread,
    682                  this, callback, result, response, url),
    683       base::TimeDelta::FromMilliseconds(kNewPageNavigateDelayMs));
    684 }
    685 
    686 void DevToolsAndroidBridge::RemoteBrowser::NavigatePageOnUIThread(
    687     const JsonRequestCallback& callback,
    688     int result, const std::string& response, const std::string& url) {
    689   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    690   scoped_ptr<base::Value> value(base::JSONReader::Read(response));
    691   base::DictionaryValue* dict;
    692 
    693   if (value && value->GetAsDictionary(&dict)) {
    694     RemotePageTarget new_page(this, *dict);
    695     new_page.Navigate(url,
    696         base::Bind(&RespondOnUIThread, callback, result, response));
    697   }
    698 }
    699 
    700 DevToolsAndroidBridge::RemoteBrowser::~RemoteBrowser() {
    701 }
    702 
    703 // DevToolsAndroidBridge::RemoteDevice ----------------------------------------
    704 
    705 DevToolsAndroidBridge::RemoteDevice::RemoteDevice(
    706     scoped_refptr<AndroidDeviceManager::Device> device,
    707     const AndroidDeviceManager::DeviceInfo& device_info)
    708     : device_(device),
    709       model_(device_info.model),
    710       connected_(device_info.connected),
    711       screen_size_(device_info.screen_size) {
    712   for (std::vector<AndroidDeviceManager::BrowserInfo>::const_iterator it =
    713       device_info.browser_info.begin();
    714       it != device_info.browser_info.end();
    715       ++it) {
    716     browsers_.push_back(new DevToolsAndroidBridge::RemoteBrowser(device, *it));
    717   }
    718 }
    719 
    720 void DevToolsAndroidBridge::RemoteDevice::OpenSocket(
    721     const std::string& socket_name,
    722     const AndroidDeviceManager::SocketCallback& callback) {
    723   device_->OpenSocket(socket_name, callback);
    724 }
    725 
    726 DevToolsAndroidBridge::RemoteDevice::~RemoteDevice() {
    727 }
    728 
    729 // DevToolsAndroidBridge ------------------------------------------------------
    730 
    731 DevToolsAndroidBridge::DevToolsAndroidBridge(Profile* profile)
    732     : profile_(profile),
    733       device_manager_(AndroidDeviceManager::Create()),
    734       task_scheduler_(base::Bind(&DevToolsAndroidBridge::ScheduleTaskDefault)),
    735       port_forwarding_controller_(new PortForwardingController(profile)) {
    736   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    737   pref_change_registrar_.Init(profile_->GetPrefs());
    738   pref_change_registrar_.Add(prefs::kDevToolsDiscoverUsbDevicesEnabled,
    739       base::Bind(&DevToolsAndroidBridge::CreateDeviceProviders,
    740                  base::Unretained(this)));
    741   CreateDeviceProviders();
    742 }
    743 
    744 void DevToolsAndroidBridge::AddDeviceListListener(
    745     DeviceListListener* listener) {
    746   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    747   bool polling_was_off = !NeedsDeviceListPolling();
    748   device_list_listeners_.push_back(listener);
    749   if (polling_was_off)
    750     StartDeviceListPolling();
    751 }
    752 
    753 void DevToolsAndroidBridge::RemoveDeviceListListener(
    754     DeviceListListener* listener) {
    755   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    756   DeviceListListeners::iterator it = std::find(
    757       device_list_listeners_.begin(), device_list_listeners_.end(), listener);
    758   DCHECK(it != device_list_listeners_.end());
    759   device_list_listeners_.erase(it);
    760   if (!NeedsDeviceListPolling())
    761     StopDeviceListPolling();
    762 }
    763 
    764 void DevToolsAndroidBridge::AddDeviceCountListener(
    765     DeviceCountListener* listener) {
    766   device_count_listeners_.push_back(listener);
    767   if (device_count_listeners_.size() == 1)
    768     StartDeviceCountPolling();
    769 }
    770 
    771 void DevToolsAndroidBridge::RemoveDeviceCountListener(
    772     DeviceCountListener* listener) {
    773   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    774   DeviceCountListeners::iterator it = std::find(
    775       device_count_listeners_.begin(), device_count_listeners_.end(), listener);
    776   DCHECK(it != device_count_listeners_.end());
    777   device_count_listeners_.erase(it);
    778   if (device_count_listeners_.empty())
    779     StopDeviceCountPolling();
    780 }
    781 
    782 void DevToolsAndroidBridge::AddPortForwardingListener(
    783     PortForwardingListener* listener) {
    784   bool polling_was_off = !NeedsDeviceListPolling();
    785   port_forwarding_listeners_.push_back(listener);
    786   if (polling_was_off)
    787     StartDeviceListPolling();
    788 }
    789 
    790 void DevToolsAndroidBridge::RemovePortForwardingListener(
    791     PortForwardingListener* listener) {
    792   PortForwardingListeners::iterator it = std::find(
    793       port_forwarding_listeners_.begin(),
    794       port_forwarding_listeners_.end(),
    795       listener);
    796   DCHECK(it != port_forwarding_listeners_.end());
    797   port_forwarding_listeners_.erase(it);
    798   if (!NeedsDeviceListPolling())
    799     StopDeviceListPolling();
    800 }
    801 
    802 // static
    803 bool DevToolsAndroidBridge::HasDevToolsWindow(const std::string& agent_id) {
    804   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    805   return g_host_delegates.Get().find(agent_id) != g_host_delegates.Get().end();
    806 }
    807 
    808 DevToolsAndroidBridge::~DevToolsAndroidBridge() {
    809   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    810   DCHECK(device_list_listeners_.empty());
    811   DCHECK(device_count_listeners_.empty());
    812   DCHECK(port_forwarding_listeners_.empty());
    813 }
    814 
    815 void DevToolsAndroidBridge::StartDeviceListPolling() {
    816   device_list_callback_.Reset(
    817     base::Bind(&DevToolsAndroidBridge::ReceivedDeviceList, this));
    818   RequestDeviceList(device_list_callback_.callback());
    819 }
    820 
    821 void DevToolsAndroidBridge::StopDeviceListPolling() {
    822   device_list_callback_.Cancel();
    823   devices_.clear();
    824 }
    825 
    826 bool DevToolsAndroidBridge::NeedsDeviceListPolling() {
    827   return !device_list_listeners_.empty() || !port_forwarding_listeners_.empty();
    828 }
    829 
    830 void DevToolsAndroidBridge::RequestDeviceList(
    831     const base::Callback<void(const RemoteDevices&)>& callback) {
    832   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    833 
    834   if (!NeedsDeviceListPolling() ||
    835       !callback.Equals(device_list_callback_.callback()))
    836     return;
    837 
    838   new DiscoveryRequest(device_manager_.get(), callback);
    839 }
    840 
    841 void DevToolsAndroidBridge::ReceivedDeviceList(const RemoteDevices& devices) {
    842   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    843 
    844   DeviceListListeners copy(device_list_listeners_);
    845   for (DeviceListListeners::iterator it = copy.begin(); it != copy.end(); ++it)
    846     (*it)->DeviceListChanged(devices);
    847 
    848   DevicesStatus status =
    849       port_forwarding_controller_->DeviceListChanged(devices);
    850   PortForwardingListeners forwarding_listeners(port_forwarding_listeners_);
    851   for (PortForwardingListeners::iterator it = forwarding_listeners.begin();
    852        it != forwarding_listeners.end(); ++it) {
    853     (*it)->PortStatusChanged(status);
    854   }
    855 
    856   if (!NeedsDeviceListPolling())
    857     return;
    858 
    859   devices_ = devices;
    860 
    861   task_scheduler_.Run(
    862       base::Bind(&DevToolsAndroidBridge::RequestDeviceList,
    863                  this, device_list_callback_.callback()));
    864 }
    865 
    866 void DevToolsAndroidBridge::StartDeviceCountPolling() {
    867   device_count_callback_.Reset(
    868       base::Bind(&DevToolsAndroidBridge::ReceivedDeviceCount, this));
    869   RequestDeviceCount(device_count_callback_.callback());
    870 }
    871 
    872 void DevToolsAndroidBridge::StopDeviceCountPolling() {
    873   device_count_callback_.Cancel();
    874 }
    875 
    876 void DevToolsAndroidBridge::RequestDeviceCount(
    877     const base::Callback<void(int)>& callback) {
    878   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    879 
    880   if (device_count_listeners_.empty() ||
    881       !callback.Equals(device_count_callback_.callback()))
    882     return;
    883 
    884   UsbDeviceProvider::CountDevices(callback);
    885 }
    886 
    887 void DevToolsAndroidBridge::ReceivedDeviceCount(int count) {
    888   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    889 
    890   DeviceCountListeners copy(device_count_listeners_);
    891   for (DeviceCountListeners::iterator it = copy.begin(); it != copy.end(); ++it)
    892     (*it)->DeviceCountChanged(count);
    893 
    894   if (device_count_listeners_.empty())
    895      return;
    896 
    897   task_scheduler_.Run(
    898       base::Bind(&DevToolsAndroidBridge::RequestDeviceCount,
    899                  this, device_count_callback_.callback()));
    900 }
    901 
    902 // static
    903 void DevToolsAndroidBridge::ScheduleTaskDefault(const base::Closure& task) {
    904   BrowserThread::PostDelayedTask(
    905       BrowserThread::UI,
    906       FROM_HERE,
    907       task,
    908       base::TimeDelta::FromMilliseconds(kAdbPollingIntervalMs));
    909 }
    910 
    911 void DevToolsAndroidBridge::CreateDeviceProviders() {
    912   AndroidDeviceManager::DeviceProviders device_providers;
    913 #if defined(DEBUG_DEVTOOLS)
    914   BrowserListTabContentsProvider::EnableTethering();
    915   // We cannot rely on command line switch here as we might want to connect
    916   // to another instance of Chrome. Using hard-coded port number instead.
    917   const int kDefaultDebuggingPort = 9222;
    918   device_providers.push_back(new SelfAsDeviceProvider(kDefaultDebuggingPort));
    919 #endif
    920   device_providers.push_back(new AdbDeviceProvider());
    921 
    922   PrefService* service = profile_->GetPrefs();
    923   const PrefService::Preference* pref =
    924       service->FindPreference(prefs::kDevToolsDiscoverUsbDevicesEnabled);
    925   const base::Value* pref_value = pref->GetValue();
    926 
    927   bool enabled;
    928   if (pref_value->GetAsBoolean(&enabled) && enabled) {
    929     device_providers.push_back(new UsbDeviceProvider(profile_));
    930   }
    931   device_manager_->SetDeviceProviders(device_providers);
    932   if (NeedsDeviceListPolling()) {
    933     StopDeviceListPolling();
    934     StartDeviceListPolling();
    935   }
    936 }
    937