Home | History | Annotate | Download | only in devtools
      1 // Copyright (c) 2013 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/devtools_adb_bridge.h"
      6 
      7 #include <map>
      8 #include <vector>
      9 
     10 #include "base/base64.h"
     11 #include "base/bind.h"
     12 #include "base/command_line.h"
     13 #include "base/compiler_specific.h"
     14 #include "base/json/json_reader.h"
     15 #include "base/lazy_instance.h"
     16 #include "base/logging.h"
     17 #include "base/memory/singleton.h"
     18 #include "base/message_loop/message_loop.h"
     19 #include "base/strings/string_number_conversions.h"
     20 #include "base/strings/string_util.h"
     21 #include "base/strings/stringprintf.h"
     22 #include "base/strings/utf_string_conversions.h"
     23 #include "base/threading/thread.h"
     24 #include "base/values.h"
     25 #include "chrome/browser/devtools/adb/android_rsa.h"
     26 #include "chrome/browser/devtools/adb_client_socket.h"
     27 #include "chrome/browser/devtools/adb_web_socket.h"
     28 #include "chrome/browser/devtools/devtools_protocol.h"
     29 #include "chrome/browser/devtools/devtools_target_impl.h"
     30 #include "chrome/browser/devtools/devtools_window.h"
     31 #include "chrome/browser/profiles/profile.h"
     32 #include "components/browser_context_keyed_service/browser_context_dependency_manager.h"
     33 #include "content/public/browser/devtools_agent_host.h"
     34 #include "content/public/browser/devtools_client_host.h"
     35 #include "content/public/browser/devtools_external_agent_proxy.h"
     36 #include "content/public/browser/devtools_external_agent_proxy_delegate.h"
     37 #include "content/public/browser/devtools_manager.h"
     38 #include "content/public/browser/user_metrics.h"
     39 #include "crypto/rsa_private_key.h"
     40 #include "net/base/escape.h"
     41 #include "net/base/net_errors.h"
     42 
     43 using content::BrowserThread;
     44 
     45 namespace {
     46 
     47 const char kDeviceModelCommand[] = "shell:getprop ro.product.model";
     48 const char kInstalledChromePackagesCommand[] = "shell:pm list packages";
     49 const char kOpenedUnixSocketsCommand[] = "shell:cat /proc/net/unix";
     50 const char kListProcessesCommand[] = "shell:ps";
     51 const char kDumpsysCommand[] = "shell:dumpsys window policy";
     52 const char kDumpsysScreenSizePrefix[] = "mStable=";
     53 
     54 const char kUnknownModel[] = "Offline";
     55 
     56 const char kPageListRequest[] = "GET /json HTTP/1.1\r\n\r\n";
     57 const char kVersionRequest[] = "GET /json/version HTTP/1.1\r\n\r\n";
     58 const char kClosePageRequest[] = "GET /json/close/%s HTTP/1.1\r\n\r\n";
     59 const char kNewPageRequest[] = "GET /json/new HTTP/1.1\r\n\r\n";
     60 const char kNewPageRequestWithURL[] = "GET /json/new?%s HTTP/1.1\r\n\r\n";
     61 const char kActivatePageRequest[] =
     62     "GET /json/activate/%s HTTP/1.1\r\n\r\n";
     63 const int kAdbPollingIntervalMs = 1000;
     64 
     65 const char kUrlParam[] = "url";
     66 const char kPageReloadCommand[] = "Page.reload";
     67 const char kPageNavigateCommand[] = "Page.navigate";
     68 
     69 const char kChromeDefaultName[] = "Chrome";
     70 const char kChromeDefaultActivity[] = "com.google.android.apps.chrome.Main";
     71 const char kChromeDefaultSocket[] = "chrome_devtools_remote";
     72 const int kMinVersionNewWithURL = 32;
     73 const int kNewPageNavigateDelayMs = 500;
     74 
     75 const char kWebViewSocketPrefix[] = "webview_devtools_remote";
     76 const char kWebViewNameTemplate[] = "WebView in %s";
     77 
     78 #if defined(DEBUG_DEVTOOLS)
     79 const char kLocalChrome[] = "Local Chrome";
     80 #endif  // defined(DEBUG_DEVTOOLS)
     81 
     82 typedef DevToolsAdbBridge::Callback Callback;
     83 typedef std::vector<scoped_refptr<AndroidDevice> >
     84     AndroidDevices;
     85 typedef base::Callback<void(const AndroidDevices&)> AndroidDevicesCallback;
     86 
     87 
     88 struct BrowserDescriptor {
     89   const char* package;
     90   const char* launch_activity;
     91   const char* socket;
     92   const char* display_name;
     93 };
     94 
     95 const BrowserDescriptor kBrowserDescriptors[] = {
     96   {
     97     "com.android.chrome",
     98     kChromeDefaultActivity,
     99     kChromeDefaultSocket,
    100     kChromeDefaultName
    101   },
    102   {
    103     "com.chrome.beta",
    104     kChromeDefaultActivity,
    105     kChromeDefaultSocket,
    106     "Chrome Beta"
    107   },
    108   {
    109     "com.google.android.apps.chrome_dev",
    110     kChromeDefaultActivity,
    111     kChromeDefaultSocket,
    112     "Chrome Dev"
    113   },
    114   {
    115     "com.google.android.apps.chrome",
    116     kChromeDefaultActivity,
    117     kChromeDefaultSocket,
    118     "Chromium"
    119   },
    120   {
    121     "org.chromium.content_shell_apk",
    122     "org.chromium.content_shell_apk.ContentShellActivity",
    123     "content_shell_devtools_remote",
    124     "Content Shell"
    125   },
    126   {
    127     "org.chromium.chrome.testshell",
    128     "org.chromium.chrome.testshell.ChromiumTestShellActivity",
    129     "chromium_testshell_devtools_remote",
    130     "Chromium Test Shell"
    131   },
    132   {
    133     "org.chromium.android_webview.shell",
    134     "org.chromium.android_webview.shell.AwShellActivity",
    135     "webview_devtools_remote",
    136     "WebView Test Shell"
    137   }
    138 };
    139 
    140 const BrowserDescriptor* FindBrowserDescriptor(const std::string& package) {
    141   int count = sizeof(kBrowserDescriptors) / sizeof(kBrowserDescriptors[0]);
    142   for (int i = 0; i < count; i++)
    143     if (kBrowserDescriptors[i].package == package)
    144       return &kBrowserDescriptors[i];
    145   return NULL;
    146 }
    147 
    148 typedef std::map<std::string, const BrowserDescriptor*> DescriptorMap;
    149 
    150 static DescriptorMap FindInstalledBrowserPackages(
    151     const std::string& response) {
    152   // Parse 'pm list packages' output which on Android looks like this:
    153   //
    154   // package:com.android.chrome
    155   // package:com.chrome.beta
    156   // package:com.example.app
    157   //
    158   DescriptorMap package_to_descriptor;
    159   const std::string package_prefix = "package:";
    160   std::vector<std::string> entries;
    161   Tokenize(response, "'\r\n", &entries);
    162   for (size_t i = 0; i < entries.size(); ++i) {
    163     if (entries[i].find(package_prefix) != 0)
    164       continue;
    165     std::string package = entries[i].substr(package_prefix.size());
    166     const BrowserDescriptor* descriptor = FindBrowserDescriptor(package);
    167     if (!descriptor)
    168       continue;
    169     package_to_descriptor[descriptor->package] = descriptor;
    170   }
    171   return package_to_descriptor;
    172 }
    173 
    174 typedef std::map<std::string, std::string> StringMap;
    175 
    176 static void MapProcessesToPackages(const std::string& response,
    177                                    StringMap& pid_to_package,
    178                                    StringMap& package_to_pid) {
    179   // Parse 'ps' output which on Android looks like this:
    180   //
    181   // USER PID PPID VSIZE RSS WCHAN PC ? NAME
    182   //
    183   std::vector<std::string> entries;
    184   Tokenize(response, "\n", &entries);
    185   for (size_t i = 1; i < entries.size(); ++i) {
    186     std::vector<std::string> fields;
    187     Tokenize(entries[i], " \r", &fields);
    188     if (fields.size() < 9)
    189       continue;
    190     std::string pid = fields[1];
    191     std::string package = fields[8];
    192     pid_to_package[pid] = package;
    193     package_to_pid[package] = pid;
    194   }
    195 }
    196 
    197 typedef std::map<std::string,
    198                  scoped_refptr<DevToolsAdbBridge::RemoteBrowser> > BrowserMap;
    199 
    200 static StringMap MapSocketsToProcesses(const std::string& response,
    201                                        const std::string& channel_pattern) {
    202   // Parse 'cat /proc/net/unix' output which on Android looks like this:
    203   //
    204   // Num       RefCount Protocol Flags    Type St Inode Path
    205   // 00000000: 00000002 00000000 00010000 0001 01 331813 /dev/socket/zygote
    206   // 00000000: 00000002 00000000 00010000 0001 01 358606 @xxx_devtools_remote
    207   // 00000000: 00000002 00000000 00010000 0001 01 347300 @yyy_devtools_remote
    208   //
    209   // We need to find records with paths starting from '@' (abstract socket)
    210   // and containing the channel pattern ("_devtools_remote").
    211   StringMap socket_to_pid;
    212   std::vector<std::string> entries;
    213   Tokenize(response, "\n", &entries);
    214   for (size_t i = 1; i < entries.size(); ++i) {
    215     std::vector<std::string> fields;
    216     Tokenize(entries[i], " \r", &fields);
    217     if (fields.size() < 8)
    218       continue;
    219     if (fields[3] != "00010000" || fields[5] != "01")
    220       continue;
    221     std::string path_field = fields[7];
    222     if (path_field.size() < 1 || path_field[0] != '@')
    223       continue;
    224     size_t socket_name_pos = path_field.find(channel_pattern);
    225     if (socket_name_pos == std::string::npos)
    226       continue;
    227 
    228     std::string socket = path_field.substr(1);
    229 
    230     std::string pid;
    231     size_t socket_name_end = socket_name_pos + channel_pattern.size();
    232     if (socket_name_end < path_field.size() &&
    233         path_field[socket_name_end] == '_') {
    234       pid = path_field.substr(socket_name_end + 1);
    235     }
    236     socket_to_pid[socket] = pid;
    237   }
    238   return socket_to_pid;
    239 }
    240 
    241 // AdbPagesCommand ------------------------------------------------------------
    242 
    243 class AdbPagesCommand : public base::RefCountedThreadSafe<
    244     AdbPagesCommand,
    245     BrowserThread::DeleteOnUIThread> {
    246  public:
    247   typedef base::Callback<void(DevToolsAdbBridge::RemoteDevices*)> Callback;
    248 
    249   AdbPagesCommand(
    250       scoped_refptr<RefCountedAdbThread> adb_thread,
    251       const DevToolsAdbBridge::DeviceProviders& device_providers,
    252       const Callback& callback);
    253 
    254  private:
    255   friend struct BrowserThread::DeleteOnThread<
    256       BrowserThread::UI>;
    257   friend class base::DeleteHelper<AdbPagesCommand>;
    258 
    259   virtual ~AdbPagesCommand();
    260   void ProcessDeviceProviders();
    261   void ReceivedDevices(const AndroidDevices& devices);
    262 
    263   void ProcessSerials();
    264   void ReceivedModel(int result, const std::string& response);
    265   void ReceivedDumpsys(int result, const std::string& response);
    266   void ReceivedPackages(int result, const std::string& response);
    267   void ReceivedProcesses(
    268       const std::string& packages_response,
    269       int result,
    270       const std::string& processes_response);
    271   void ReceivedSockets(
    272       const std::string& packages_response,
    273       const std::string& processes_response,
    274       int result,
    275       const std::string& sockets_response);
    276   void ProcessSockets();
    277   void ReceivedVersion(int result, const std::string& response);
    278   void ReceivedPages(int result, const std::string& response);
    279 
    280   scoped_refptr<AndroidDevice> current_device() const {
    281     return devices_.back();
    282   }
    283 
    284   scoped_refptr<DevToolsAdbBridge::RemoteBrowser> current_browser() const {
    285     return browsers_.back();
    286   }
    287 
    288   void NextBrowser();
    289   void NextDevice();
    290 
    291   void Respond();
    292 
    293   void CreateBrowsers(const std::string& packages_response,
    294                       const std::string& processes_response,
    295                       const std::string& sockets_response);
    296 
    297   void ParseDumpsysResponse(const std::string& response);
    298   void ParseScreenSize(const std::string& str);
    299 
    300   scoped_refptr<RefCountedAdbThread> adb_thread_;
    301   Callback callback_;
    302   AndroidDevices devices_;
    303   DevToolsAdbBridge::RemoteBrowsers browsers_;
    304   scoped_ptr<DevToolsAdbBridge::RemoteDevices> remote_devices_;
    305   DevToolsAdbBridge::DeviceProviders device_providers_;
    306 };
    307 
    308 AdbPagesCommand::AdbPagesCommand(
    309     scoped_refptr<RefCountedAdbThread> adb_thread,
    310     const DevToolsAdbBridge::DeviceProviders& device_providers,
    311     const Callback& callback)
    312     : adb_thread_(adb_thread),
    313       callback_(callback),
    314       device_providers_(device_providers){
    315   remote_devices_.reset(new DevToolsAdbBridge::RemoteDevices());
    316 
    317   ProcessDeviceProviders();
    318 }
    319 
    320 AdbPagesCommand::~AdbPagesCommand() {
    321   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    322 }
    323 
    324 void AdbPagesCommand::ProcessDeviceProviders() {
    325   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    326   if (device_providers_.empty()) {
    327     adb_thread_->message_loop()->PostTask(
    328               FROM_HERE, base::Bind(&AdbPagesCommand::ProcessSerials, this));
    329     return;
    330   }
    331 
    332   const scoped_refptr<AndroidDeviceProvider>& device_provider =
    333       device_providers_.back();
    334 
    335   device_provider->QueryDevices(
    336       base::Bind(&AdbPagesCommand::ReceivedDevices, this));
    337 }
    338 
    339 void AdbPagesCommand::ReceivedDevices(const AndroidDevices& devices) {
    340   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    341   DCHECK(!device_providers_.empty());
    342   device_providers_.pop_back();
    343 
    344   devices_.insert(devices_.end(), devices.begin(), devices.end());
    345 
    346   if (!device_providers_.empty()) {
    347     ProcessDeviceProviders();
    348   } else {
    349     adb_thread_->message_loop()->PostTask(
    350           FROM_HERE, base::Bind(&AdbPagesCommand::ProcessSerials, this));
    351   }
    352 }
    353 
    354 void AdbPagesCommand::ProcessSerials() {
    355   DCHECK_EQ(adb_thread_->message_loop(), base::MessageLoop::current());
    356   if (devices_.size() == 0) {
    357     BrowserThread::PostTask(
    358         BrowserThread::UI, FROM_HERE,
    359         base::Bind(&AdbPagesCommand::Respond, this));
    360     return;
    361   }
    362 
    363   scoped_refptr<AndroidDevice> device = current_device();
    364 #if defined(DEBUG_DEVTOOLS)
    365   // For desktop remote debugging.
    366   if (device->serial().empty()) {
    367     device->set_model(kLocalChrome);
    368     remote_devices_->push_back(
    369         new DevToolsAdbBridge::RemoteDevice(device));
    370     scoped_refptr<DevToolsAdbBridge::RemoteBrowser> remote_browser =
    371         new DevToolsAdbBridge::RemoteBrowser(
    372             adb_thread_, device, std::string());
    373     remote_browser->set_display_name(kChromeDefaultName);
    374     remote_devices_->back()->AddBrowser(remote_browser);
    375     browsers_.push_back(remote_browser);
    376     device->HttpQuery(
    377         std::string(), kVersionRequest,
    378         base::Bind(&AdbPagesCommand::ReceivedVersion, this));
    379     return;
    380   }
    381 #endif  // defined(DEBUG_DEVTOOLS)
    382 
    383   if (device->is_connected()) {
    384     device->RunCommand(kDeviceModelCommand,
    385                        base::Bind(&AdbPagesCommand::ReceivedModel, this));
    386   } else {
    387     device->set_model(kUnknownModel);
    388     remote_devices_->push_back(new DevToolsAdbBridge::RemoteDevice(device));
    389     NextDevice();
    390   }
    391 }
    392 
    393 void AdbPagesCommand::ReceivedModel(int result, const std::string& response) {
    394   DCHECK_EQ(adb_thread_->message_loop(), base::MessageLoop::current());
    395   if (result < 0) {
    396     NextDevice();
    397     return;
    398   }
    399   scoped_refptr<AndroidDevice> device = current_device();
    400   device->set_model(response);
    401   remote_devices_->push_back(new DevToolsAdbBridge::RemoteDevice(device));
    402   device->RunCommand(kDumpsysCommand,
    403                      base::Bind(&AdbPagesCommand::ReceivedDumpsys, this));
    404 }
    405 
    406 void AdbPagesCommand::ReceivedDumpsys(int result,
    407                                       const std::string& response) {
    408   DCHECK_EQ(adb_thread_->message_loop(), base::MessageLoop::current());
    409   if (result >= 0)
    410     ParseDumpsysResponse(response);
    411 
    412   current_device()->RunCommand(
    413       kInstalledChromePackagesCommand,
    414       base::Bind(&AdbPagesCommand::ReceivedPackages, this));
    415 }
    416 
    417 void AdbPagesCommand::ReceivedPackages(int result,
    418                                        const std::string& packages_response) {
    419   DCHECK_EQ(adb_thread_->message_loop(), base::MessageLoop::current());
    420   if (result < 0) {
    421     NextDevice();
    422     return;
    423   }
    424   current_device()->RunCommand(
    425       kListProcessesCommand,
    426       base::Bind(&AdbPagesCommand::ReceivedProcesses, this, packages_response));
    427 }
    428 
    429 void AdbPagesCommand::ReceivedProcesses(
    430     const std::string& packages_response,
    431     int result,
    432     const std::string& processes_response) {
    433   DCHECK_EQ(adb_thread_->message_loop(), base::MessageLoop::current());
    434   if (result < 0) {
    435     NextDevice();
    436     return;
    437   }
    438   current_device()->RunCommand(
    439       kOpenedUnixSocketsCommand,
    440       base::Bind(&AdbPagesCommand::ReceivedSockets,
    441                  this,
    442                  packages_response,
    443                  processes_response));
    444 }
    445 
    446 void AdbPagesCommand::ReceivedSockets(
    447     const std::string& packages_response,
    448     const std::string& processes_response,
    449     int result,
    450     const std::string& sockets_response) {
    451   DCHECK_EQ(adb_thread_->message_loop(), base::MessageLoop::current());
    452   if (result >= 0)
    453     CreateBrowsers(packages_response, processes_response, sockets_response);
    454   ProcessSockets();
    455 }
    456 
    457 void AdbPagesCommand::ProcessSockets() {
    458   DCHECK_EQ(adb_thread_->message_loop(), base::MessageLoop::current());
    459   if (browsers_.size() == 0) {
    460     NextDevice();
    461     return;
    462   }
    463 
    464   if (!current_device()->serial().empty() &&
    465      current_browser()->socket().empty()) {
    466     NextBrowser();
    467     return;
    468   }
    469   current_device()->HttpQuery(
    470       current_browser()->socket(),
    471       kVersionRequest,
    472       base::Bind(&AdbPagesCommand::ReceivedVersion, this));
    473 }
    474 
    475 void AdbPagesCommand::ReceivedVersion(int result,
    476                                       const std::string& response) {
    477   DCHECK_EQ(adb_thread_->message_loop(), base::MessageLoop::current());
    478   if (result < 0) {
    479     NextBrowser();
    480     return;
    481   }
    482 
    483   // Parse version, append to package name if available,
    484   scoped_ptr<base::Value> value(base::JSONReader::Read(response));
    485   base::DictionaryValue* dict;
    486   if (value && value->GetAsDictionary(&dict)) {
    487     std::string browser;
    488     if (dict->GetString("Browser", &browser)) {
    489       std::vector<std::string> parts;
    490       Tokenize(browser, "/", &parts);
    491       if (parts.size() == 2)
    492         current_browser()->set_version(parts[1]);
    493       else
    494         current_browser()->set_version(browser);
    495     }
    496     std::string package;
    497     if (dict->GetString("Android-Package", &package)) {
    498       const BrowserDescriptor* descriptor = FindBrowserDescriptor(package);
    499       if (descriptor)
    500         current_browser()->set_display_name(descriptor->display_name);
    501     }
    502   }
    503 
    504   current_device()->HttpQuery(
    505       current_browser()->socket(),
    506       kPageListRequest,
    507       base::Bind(&AdbPagesCommand::ReceivedPages, this));
    508 }
    509 
    510 void AdbPagesCommand::ReceivedPages(int result,
    511                                     const std::string& response) {
    512   DCHECK_EQ(adb_thread_->message_loop(), base::MessageLoop::current());
    513   if (result >= 0) {
    514     scoped_ptr<base::Value> value(base::JSONReader::Read(response));
    515     base::ListValue* list_value;
    516     if (value && value->GetAsList(&list_value))
    517       current_browser()->SetPageDescriptors(*list_value);
    518   }
    519   NextBrowser();
    520 }
    521 
    522 void AdbPagesCommand::NextBrowser() {
    523   browsers_.pop_back();
    524   ProcessSockets();
    525 }
    526 
    527 void AdbPagesCommand::NextDevice() {
    528   devices_.pop_back();
    529   ProcessSerials();
    530 }
    531 
    532 void AdbPagesCommand::Respond() {
    533   callback_.Run(remote_devices_.release());
    534 }
    535 
    536 void AdbPagesCommand::CreateBrowsers(
    537     const std::string& packages_response,
    538     const std::string& processes_response,
    539     const std::string& sockets_response) {
    540   DescriptorMap package_to_descriptor =
    541       FindInstalledBrowserPackages(packages_response);
    542 
    543   StringMap pid_to_package;
    544   StringMap package_to_pid;
    545   MapProcessesToPackages(processes_response, pid_to_package, package_to_pid);
    546 
    547   const std::string channel_pattern =
    548       base::StringPrintf(kDevToolsChannelNameFormat, "");
    549 
    550   StringMap socket_to_pid = MapSocketsToProcesses(sockets_response,
    551                                                   channel_pattern);
    552 
    553   scoped_refptr<DevToolsAdbBridge::RemoteDevice> remote_device =
    554       remote_devices_->back();
    555 
    556   // Create RemoteBrowser instances.
    557   BrowserMap package_to_running_browser;
    558   BrowserMap socket_to_unnamed_browser;
    559   for (StringMap::iterator it = socket_to_pid.begin();
    560       it != socket_to_pid.end(); ++it) {
    561     std::string socket = it->first;
    562     std::string pid = it->second;
    563 
    564     scoped_refptr<DevToolsAdbBridge::RemoteBrowser> browser =
    565         new DevToolsAdbBridge::RemoteBrowser(
    566             adb_thread_, remote_device->device(), socket);
    567 
    568     StringMap::iterator pit = pid_to_package.find(pid);
    569     if (pit != pid_to_package.end()) {
    570       std::string package = pit->second;
    571       package_to_running_browser[package] = browser;
    572       const BrowserDescriptor* descriptor = FindBrowserDescriptor(package);
    573       if (descriptor) {
    574         browser->set_display_name(descriptor->display_name);
    575       } else if (socket.find(kWebViewSocketPrefix) == 0) {
    576         browser->set_display_name(
    577             base::StringPrintf(kWebViewNameTemplate, package.c_str()));
    578       } else {
    579         browser->set_display_name(package);
    580       }
    581     } else {
    582       // Set fallback display name.
    583       std::string name = socket.substr(0, socket.find(channel_pattern));
    584       name[0] = base::ToUpperASCII(name[0]);
    585       browser->set_display_name(name);
    586 
    587       socket_to_unnamed_browser[socket] = browser;
    588     }
    589     remote_device->AddBrowser(browser);
    590   }
    591 
    592   browsers_ = remote_device->browsers();
    593 
    594   // Find installed packages not mapped to browsers.
    595   typedef std::multimap<std::string, const BrowserDescriptor*>
    596       DescriptorMultimap;
    597   DescriptorMultimap socket_to_descriptor;
    598   for (DescriptorMap::iterator it = package_to_descriptor.begin();
    599       it != package_to_descriptor.end(); ++it) {
    600     std::string package = it->first;
    601     const BrowserDescriptor* descriptor = it->second;
    602 
    603     if (package_to_running_browser.find(package) !=
    604         package_to_running_browser.end())
    605       continue;  // This package is already mapped to a browser.
    606 
    607     if (package_to_pid.find(package) != package_to_pid.end()) {
    608       // This package is running but not mapped to a browser.
    609       socket_to_descriptor.insert(
    610           DescriptorMultimap::value_type(descriptor->socket, descriptor));
    611       continue;
    612     }
    613   }
    614 
    615   // Try naming remaining unnamed browsers.
    616   for (DescriptorMultimap::iterator it = socket_to_descriptor.begin();
    617       it != socket_to_descriptor.end(); ++it) {
    618     std::string socket = it->first;
    619     const BrowserDescriptor* descriptor = it->second;
    620 
    621     if (socket_to_descriptor.count(socket) != 1)
    622       continue;  // No definitive match.
    623 
    624     BrowserMap::iterator bit = socket_to_unnamed_browser.find(socket);
    625     if (bit != socket_to_unnamed_browser.end())
    626       bit->second->set_display_name(descriptor->display_name);
    627   }
    628 }
    629 
    630 void AdbPagesCommand::ParseDumpsysResponse(const std::string& response) {
    631   std::vector<std::string> lines;
    632   Tokenize(response, "\r", &lines);
    633   for (size_t i = 0; i < lines.size(); ++i) {
    634     std::string line = lines[i];
    635     size_t pos = line.find(kDumpsysScreenSizePrefix);
    636     if (pos != std::string::npos) {
    637       ParseScreenSize(
    638           line.substr(pos + std::string(kDumpsysScreenSizePrefix).size()));
    639       break;
    640     }
    641   }
    642 }
    643 
    644 void AdbPagesCommand::ParseScreenSize(const std::string& str) {
    645   std::vector<std::string> pairs;
    646   Tokenize(str, "-", &pairs);
    647   if (pairs.size() != 2)
    648     return;
    649 
    650   int width;
    651   int height;
    652   std::vector<std::string> numbers;
    653   Tokenize(pairs[1].substr(1, pairs[1].size() - 2), ",", &numbers);
    654   if (numbers.size() != 2 ||
    655       !base::StringToInt(numbers[0], &width) ||
    656       !base::StringToInt(numbers[1], &height))
    657     return;
    658 
    659   remote_devices_->back()->set_screen_size(gfx::Size(width, height));
    660 }
    661 
    662 
    663 // AdbProtocolCommand ---------------------------------------------------------
    664 
    665 class AdbProtocolCommand : public AdbWebSocket::Delegate {
    666  public:
    667   AdbProtocolCommand(
    668       scoped_refptr<RefCountedAdbThread> adb_thread,
    669       scoped_refptr<AndroidDevice> device,
    670       const std::string& socket_name,
    671       const std::string& debug_url,
    672       const std::string& command);
    673 
    674  private:
    675   virtual void OnSocketOpened() OVERRIDE;
    676   virtual void OnFrameRead(const std::string& message) OVERRIDE;
    677   virtual void OnSocketClosed(bool closed_by_device) OVERRIDE;
    678   virtual bool ProcessIncomingMessage(const std::string& message) OVERRIDE;
    679 
    680   scoped_refptr<RefCountedAdbThread> adb_thread_;
    681   const std::string command_;
    682   scoped_refptr<AdbWebSocket> web_socket_;
    683 
    684   DISALLOW_COPY_AND_ASSIGN(AdbProtocolCommand);
    685 };
    686 
    687 AdbProtocolCommand::AdbProtocolCommand(
    688     scoped_refptr<RefCountedAdbThread> adb_thread,
    689     scoped_refptr<AndroidDevice> device,
    690     const std::string& socket_name,
    691     const std::string& debug_url,
    692     const std::string& command)
    693     : adb_thread_(adb_thread),
    694       command_(command) {
    695   web_socket_ = new AdbWebSocket(
    696       device, socket_name, debug_url, adb_thread_->message_loop(), this);
    697 }
    698 
    699 void AdbProtocolCommand::OnSocketOpened() {
    700   web_socket_->SendFrame(command_);
    701   web_socket_->Disconnect();
    702 }
    703 
    704 void AdbProtocolCommand::OnFrameRead(const std::string& message) {}
    705 
    706 void AdbProtocolCommand::OnSocketClosed(bool closed_by_device) {
    707   delete this;
    708 }
    709 
    710 bool AdbProtocolCommand::ProcessIncomingMessage(const std::string& message) {
    711   return false;
    712 }
    713 
    714 }  // namespace
    715 
    716 const char kDevToolsChannelNameFormat[] = "%s_devtools_remote";
    717 
    718 class AgentHostDelegate;
    719 
    720 typedef std::map<std::string, AgentHostDelegate*> AgentHostDelegates;
    721 
    722 base::LazyInstance<AgentHostDelegates>::Leaky g_host_delegates =
    723     LAZY_INSTANCE_INITIALIZER;
    724 
    725 DevToolsAdbBridge::Wrapper::Wrapper() {
    726   bridge_ = new DevToolsAdbBridge();
    727 }
    728 
    729 DevToolsAdbBridge::Wrapper::~Wrapper() {
    730 }
    731 
    732 DevToolsAdbBridge* DevToolsAdbBridge::Wrapper::Get() {
    733   return bridge_.get();
    734 }
    735 
    736 // static
    737 DevToolsAdbBridge::Factory* DevToolsAdbBridge::Factory::GetInstance() {
    738   return Singleton<DevToolsAdbBridge::Factory>::get();
    739 }
    740 
    741 // static
    742 DevToolsAdbBridge* DevToolsAdbBridge::Factory::GetForProfile(
    743     Profile* profile) {
    744   DevToolsAdbBridge::Wrapper* wrapper =
    745       static_cast<DevToolsAdbBridge::Wrapper*>(GetInstance()->
    746           GetServiceForBrowserContext(profile, true));
    747   return wrapper ? wrapper->Get() : NULL;
    748 }
    749 
    750 DevToolsAdbBridge::Factory::Factory()
    751     : BrowserContextKeyedServiceFactory(
    752           "DevToolsAdbBridge",
    753           BrowserContextDependencyManager::GetInstance()) {}
    754 
    755 DevToolsAdbBridge::Factory::~Factory() {}
    756 
    757 BrowserContextKeyedService*
    758 DevToolsAdbBridge::Factory::BuildServiceInstanceFor(
    759     content::BrowserContext* context) const {
    760   return new DevToolsAdbBridge::Wrapper();
    761 }
    762 
    763 
    764 // AgentHostDelegate ----------------------------------------------------------
    765 
    766 class AgentHostDelegate : public content::DevToolsExternalAgentProxyDelegate,
    767                           public AdbWebSocket::Delegate {
    768  public:
    769    static void Create(const std::string& id,
    770                       scoped_refptr<DevToolsAdbBridge::RemoteBrowser> browser,
    771                       const std::string& debug_url,
    772                       const std::string& frontend_url,
    773                       Profile* profile) {
    774     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    775     AgentHostDelegates::iterator it =
    776         g_host_delegates.Get().find(id);
    777     if (it != g_host_delegates.Get().end()) {
    778       it->second->OpenFrontend();
    779     } else if (!frontend_url.empty()) {
    780       new AgentHostDelegate(
    781           id, browser->device(), browser->socket(), debug_url,
    782           frontend_url, browser->adb_thread()->message_loop(), profile);
    783     }
    784   }
    785 
    786  private:
    787   AgentHostDelegate(
    788       const std::string& id,
    789       scoped_refptr<AndroidDevice> device,
    790       const std::string& socket_name,
    791       const std::string& debug_url,
    792       const std::string& frontend_url,
    793       base::MessageLoop* adb_message_loop,
    794       Profile* profile)
    795       : id_(id),
    796         frontend_url_(frontend_url),
    797         adb_message_loop_(adb_message_loop),
    798         profile_(profile) {
    799     web_socket_ = new AdbWebSocket(
    800         device, socket_name, debug_url, adb_message_loop, this);
    801     g_host_delegates.Get()[id] = this;
    802 
    803     if (socket_name.find(kWebViewSocketPrefix) == 0) {
    804       content::RecordAction(
    805           content::UserMetricsAction("DevTools_InspectAndroidWebView"));
    806     } else {
    807       content::RecordAction(
    808           content::UserMetricsAction("DevTools_InspectAndroidPage"));
    809     }
    810   }
    811 
    812   void OpenFrontend() {
    813     if (!proxy_)
    814       return;
    815     DevToolsWindow::OpenExternalFrontend(
    816         profile_, frontend_url_, proxy_->GetAgentHost().get());
    817   }
    818 
    819   virtual ~AgentHostDelegate() {
    820     g_host_delegates.Get().erase(id_);
    821   }
    822 
    823   virtual void Attach() OVERRIDE {}
    824 
    825   virtual void Detach() OVERRIDE {
    826     web_socket_->Disconnect();
    827   }
    828 
    829   virtual void SendMessageToBackend(const std::string& message) OVERRIDE {
    830     web_socket_->SendFrame(message);
    831   }
    832 
    833   virtual void OnSocketOpened() OVERRIDE {
    834     proxy_.reset(content::DevToolsExternalAgentProxy::Create(this));
    835     OpenFrontend();
    836   }
    837 
    838   virtual void OnFrameRead(const std::string& message) OVERRIDE {
    839     proxy_->DispatchOnClientHost(message);
    840   }
    841 
    842   virtual void OnSocketClosed(bool closed_by_device) OVERRIDE {
    843     if (proxy_ && closed_by_device)
    844       proxy_->ConnectionClosed();
    845     delete this;
    846   }
    847 
    848   virtual bool ProcessIncomingMessage(const std::string& message) OVERRIDE {
    849     return false;
    850   }
    851 
    852   const std::string id_;
    853   const std::string frontend_url_;
    854   base::MessageLoop* adb_message_loop_;
    855   Profile* profile_;
    856 
    857   scoped_ptr<content::DevToolsExternalAgentProxy> proxy_;
    858   scoped_refptr<AdbWebSocket> web_socket_;
    859   DISALLOW_COPY_AND_ASSIGN(AgentHostDelegate);
    860 };
    861 
    862 //// RemotePageTarget ----------------------------------------------
    863 
    864 class RemotePageTarget : public DevToolsTargetImpl {
    865  public:
    866   RemotePageTarget(scoped_refptr<DevToolsAdbBridge::RemoteBrowser> browser,
    867                    const base::DictionaryValue& value);
    868   virtual ~RemotePageTarget();
    869 
    870   // content::DevToolsTarget overrides:
    871   virtual bool IsAttached() const OVERRIDE;
    872   virtual bool Activate() const OVERRIDE;
    873   virtual bool Close() const OVERRIDE;
    874 
    875   // DevToolsTargetImpl overrides:
    876   virtual void Inspect(Profile* profile) const OVERRIDE;
    877   virtual void Reload() const OVERRIDE;
    878 
    879   void Navigate(const std::string& url) const;
    880 
    881  private:
    882   scoped_refptr<DevToolsAdbBridge::RemoteBrowser> browser_;
    883   std::string debug_url_;
    884   std::string frontend_url_;
    885   std::string agent_id_;
    886   DISALLOW_COPY_AND_ASSIGN(RemotePageTarget);
    887 };
    888 
    889 RemotePageTarget::RemotePageTarget(
    890     scoped_refptr<DevToolsAdbBridge::RemoteBrowser> browser,
    891     const base::DictionaryValue& value)
    892     : browser_(browser) {
    893   type_ = "adb_page";
    894   value.GetString("id", &id_);
    895   std::string url;
    896   value.GetString("url", &url);
    897   url_ = GURL(url);
    898   value.GetString("title", &title_);
    899   title_ = UTF16ToUTF8(net::UnescapeForHTML(UTF8ToUTF16(title_)));
    900   value.GetString("description", &description_);
    901   std::string favicon_url;
    902   value.GetString("faviconUrl", &favicon_url);
    903   favicon_url_ = GURL(favicon_url);
    904   value.GetString("webSocketDebuggerUrl", &debug_url_);
    905   value.GetString("devtoolsFrontendUrl", &frontend_url_);
    906 
    907   if (id_.empty() && !debug_url_.empty())  {
    908     // Target id is not available until Chrome 26. Use page id at the end of
    909     // debug_url_ instead. For attached targets the id will remain empty.
    910     std::vector<std::string> parts;
    911     Tokenize(debug_url_, "/", &parts);
    912     id_ = parts[parts.size()-1];
    913   }
    914 
    915   if (debug_url_.find("ws://") == 0)
    916     debug_url_ = debug_url_.substr(5);
    917   else
    918     debug_url_ = "";
    919 
    920   size_t ws_param = frontend_url_.find("?ws");
    921   if (ws_param != std::string::npos)
    922     frontend_url_ = frontend_url_.substr(0, ws_param);
    923   if (frontend_url_.find("http:") == 0)
    924     frontend_url_ = "https:" + frontend_url_.substr(5);
    925 
    926   agent_id_ = base::StringPrintf("%s:%s:%s",
    927       browser_->device()->serial().c_str(),
    928       browser_->socket().c_str(),
    929       id_.c_str());
    930 }
    931 
    932 RemotePageTarget::~RemotePageTarget() {
    933 }
    934 
    935 bool RemotePageTarget::IsAttached() const {
    936   return debug_url_.empty();
    937 }
    938 
    939 void RemotePageTarget::Inspect(Profile* profile) const {
    940   std::string request = base::StringPrintf(kActivatePageRequest, id_.c_str());
    941   base::Closure inspect_callback = base::Bind(&AgentHostDelegate::Create,
    942       id_, browser_, debug_url_, frontend_url_, profile);
    943   browser_->SendJsonRequest(request, inspect_callback);
    944 }
    945 
    946 bool RemotePageTarget::Activate() const {
    947   std::string request = base::StringPrintf(kActivatePageRequest, id_.c_str());
    948   browser_->SendJsonRequest(request, base::Closure());
    949   return true;
    950 }
    951 
    952 bool RemotePageTarget::Close() const {
    953   if (IsAttached())
    954     return false;
    955   std::string request = base::StringPrintf(kClosePageRequest, id_.c_str());
    956   browser_->SendJsonRequest(request, base::Closure());
    957   return true;
    958 }
    959 
    960 void RemotePageTarget::Reload() const {
    961   browser_->SendProtocolCommand(debug_url_, kPageReloadCommand, NULL);
    962 }
    963 
    964 void RemotePageTarget::Navigate(const std::string& url) const {
    965   base::DictionaryValue params;
    966   params.SetString(kUrlParam, url);
    967   browser_->SendProtocolCommand(debug_url_, kPageNavigateCommand, &params);
    968 }
    969 
    970 // DevToolsAdbBridge::RemoteBrowser -------------------------------------------
    971 
    972 DevToolsAdbBridge::RemoteBrowser::RemoteBrowser(
    973     scoped_refptr<RefCountedAdbThread> adb_thread,
    974     scoped_refptr<AndroidDevice> device,
    975     const std::string& socket)
    976     : adb_thread_(adb_thread),
    977       device_(device),
    978       socket_(socket),
    979       page_descriptors_(new base::ListValue()) {
    980 }
    981 
    982 bool DevToolsAdbBridge::RemoteBrowser::IsChrome() const {
    983   return socket_.find(kChromeDefaultSocket) == 0;
    984 }
    985 
    986 DevToolsAdbBridge::RemoteBrowser::ParsedVersion
    987 DevToolsAdbBridge::RemoteBrowser::GetParsedVersion() const {
    988   ParsedVersion result;
    989   std::vector<std::string> parts;
    990   Tokenize(version_, ".", &parts);
    991   for (size_t i = 0; i != parts.size(); ++i) {
    992     int value = 0;
    993     base::StringToInt(parts[i], &value);
    994     result.push_back(value);
    995   }
    996   return result;
    997 }
    998 
    999 std::vector<DevToolsTargetImpl*>
   1000 DevToolsAdbBridge::RemoteBrowser::CreatePageTargets() {
   1001   std::vector<DevToolsTargetImpl*> result;
   1002   for (size_t i = 0; i < page_descriptors_->GetSize(); ++i) {
   1003     base::Value* item;
   1004     page_descriptors_->Get(i, &item);
   1005     if (!item)
   1006       continue;
   1007     base::DictionaryValue* dict;
   1008     if (!item->GetAsDictionary(&dict))
   1009       continue;
   1010     result.push_back(new RemotePageTarget(this, *dict));
   1011   }
   1012   return result;
   1013 }
   1014 
   1015 void DevToolsAdbBridge::RemoteBrowser::SetPageDescriptors(
   1016     const base::ListValue& list) {
   1017   page_descriptors_.reset(list.DeepCopy());
   1018 }
   1019 
   1020 static void RespondOnUIThread(base::Closure callback, int, const std::string&) {
   1021   if (!callback.is_null())
   1022     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback);
   1023 }
   1024 
   1025 void DevToolsAdbBridge::RemoteBrowser::SendJsonRequest(
   1026     const std::string& request, base::Closure callback) {
   1027   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1028   adb_thread_->message_loop()->PostTask(FROM_HERE,
   1029       base::Bind(&AndroidDevice::HttpQuery, device_, socket_, request,
   1030           base::Bind(&RespondOnUIThread, callback)));
   1031 }
   1032 
   1033 void DevToolsAdbBridge::RemoteBrowser::SendProtocolCommand(
   1034     const std::string& debug_url,
   1035     const std::string& method,
   1036     base::DictionaryValue* params) {
   1037   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1038   if (debug_url.empty())
   1039     return;
   1040   DevToolsProtocol::Command command(1, method, params);
   1041   new AdbProtocolCommand(
   1042       adb_thread_, device_, socket_, debug_url, command.Serialize());
   1043 }
   1044 
   1045 static void NoOp(int, const std::string&) {}
   1046 
   1047 void DevToolsAdbBridge::RemoteBrowser::Open(const std::string& input_url) {
   1048   GURL gurl(input_url);
   1049   if (!gurl.is_valid()) {
   1050     gurl = GURL("http://" + input_url);
   1051     if (!gurl.is_valid())
   1052      return;
   1053   }
   1054   std::string url = gurl.spec();
   1055 
   1056   ParsedVersion parsed_version = GetParsedVersion();
   1057   if (IsChrome() &&
   1058       !parsed_version.empty() &&
   1059       parsed_version[0] >= kMinVersionNewWithURL) {
   1060     std::string query = net::EscapeQueryParamValue(url, false /* use_plus */);
   1061     std::string request =
   1062         base::StringPrintf(kNewPageRequestWithURL, query.c_str());
   1063     adb_thread_->message_loop()->PostTask(FROM_HERE,
   1064         base::Bind(&AndroidDevice::HttpQuery,
   1065             device_, socket_, request, base::Bind(&NoOp)));
   1066   } else {
   1067     adb_thread_->message_loop()->PostTask(FROM_HERE,
   1068         base::Bind(&AndroidDevice::HttpQuery,
   1069             device_, socket_, kNewPageRequest,
   1070             base::Bind(&RemoteBrowser::PageCreatedOnHandlerThread, this, url)));
   1071   }
   1072 }
   1073 
   1074 void DevToolsAdbBridge::RemoteBrowser::PageCreatedOnHandlerThread(
   1075     const std::string& url, int result, const std::string& response) {
   1076   if (result < 0)
   1077     return;
   1078   // Navigating too soon after the page creation breaks navigation history
   1079   // (crbug.com/311014). This can be avoided by adding a moderate delay.
   1080   BrowserThread::PostDelayedTask(
   1081       BrowserThread::UI, FROM_HERE,
   1082       base::Bind(&RemoteBrowser::PageCreatedOnUIThread, this, response, url),
   1083       base::TimeDelta::FromMilliseconds(kNewPageNavigateDelayMs));
   1084 }
   1085 
   1086 void DevToolsAdbBridge::RemoteBrowser::PageCreatedOnUIThread(
   1087     const std::string& response, const std::string& url) {
   1088   scoped_ptr<base::Value> value(base::JSONReader::Read(response));
   1089   base::DictionaryValue* dict;
   1090   if (value && value->GetAsDictionary(&dict)) {
   1091     RemotePageTarget new_page(this, *dict);
   1092     new_page.Navigate(url);
   1093   }
   1094 }
   1095 
   1096 DevToolsAdbBridge::RemoteBrowser::~RemoteBrowser() {
   1097 }
   1098 
   1099 
   1100 // DevToolsAdbBridge::RemoteDevice --------------------------------------------
   1101 
   1102 DevToolsAdbBridge::RemoteDevice::RemoteDevice(
   1103     scoped_refptr<AndroidDevice> device)
   1104     : device_(device) {
   1105 }
   1106 
   1107 std::string DevToolsAdbBridge::RemoteDevice::GetSerial() {
   1108   return device_->serial();
   1109 }
   1110 
   1111 std::string DevToolsAdbBridge::RemoteDevice::GetModel() {
   1112   return device_->model();
   1113 }
   1114 
   1115 bool DevToolsAdbBridge::RemoteDevice::IsConnected() {
   1116   return device_->is_connected();
   1117 }
   1118 
   1119 void DevToolsAdbBridge::RemoteDevice::AddBrowser(
   1120     scoped_refptr<RemoteBrowser> browser) {
   1121   browsers_.push_back(browser);
   1122 }
   1123 
   1124 DevToolsAdbBridge::RemoteDevice::~RemoteDevice() {
   1125 }
   1126 
   1127 
   1128 // DevToolsAdbBridge ----------------------------------------------------------
   1129 
   1130 DevToolsAdbBridge::DevToolsAdbBridge()
   1131     : adb_thread_(RefCountedAdbThread::GetInstance()),
   1132       has_message_loop_(adb_thread_->message_loop() != NULL) {
   1133 }
   1134 
   1135 void DevToolsAdbBridge::AddListener(Listener* listener) {
   1136   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1137   if (listeners_.empty())
   1138     RequestRemoteDevices();
   1139   listeners_.push_back(listener);
   1140 }
   1141 
   1142 void DevToolsAdbBridge::RemoveListener(Listener* listener) {
   1143   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1144   Listeners::iterator it =
   1145       std::find(listeners_.begin(), listeners_.end(), listener);
   1146   DCHECK(it != listeners_.end());
   1147   listeners_.erase(it);
   1148 }
   1149 
   1150 bool DevToolsAdbBridge::HasDevToolsWindow(const std::string& agent_id) {
   1151   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1152   return g_host_delegates.Get().find(agent_id) != g_host_delegates.Get().end();
   1153 }
   1154 
   1155 DevToolsAdbBridge::~DevToolsAdbBridge() {
   1156   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1157   DCHECK(listeners_.empty());
   1158 }
   1159 
   1160 void DevToolsAdbBridge::RequestRemoteDevices() {
   1161   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1162   if (!has_message_loop_)
   1163     return;
   1164 
   1165   new AdbPagesCommand(
   1166       adb_thread_, device_providers_,
   1167       base::Bind(&DevToolsAdbBridge::ReceivedRemoteDevices, this));
   1168 }
   1169 
   1170 void DevToolsAdbBridge::ReceivedRemoteDevices(RemoteDevices* devices_ptr) {
   1171   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   1172 
   1173   scoped_ptr<RemoteDevices> devices(devices_ptr);
   1174 
   1175   Listeners copy(listeners_);
   1176   for (Listeners::iterator it = copy.begin(); it != copy.end(); ++it)
   1177     (*it)->RemoteDevicesChanged(devices.get());
   1178 
   1179   if (listeners_.empty())
   1180     return;
   1181 
   1182   BrowserThread::PostDelayedTask(
   1183       BrowserThread::UI,
   1184       FROM_HERE,
   1185       base::Bind(&DevToolsAdbBridge::RequestRemoteDevices, this),
   1186       base::TimeDelta::FromMilliseconds(kAdbPollingIntervalMs));
   1187 }
   1188