Home | History | Annotate | Download | only in chrome
      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/test/chromedriver/chrome/device_manager.h"
      6 
      7 #include <algorithm>
      8 #include <vector>
      9 
     10 #include "base/bind.h"
     11 #include "base/bind_helpers.h"
     12 #include "base/callback.h"
     13 #include "base/logging.h"
     14 #include "base/strings/string_number_conversions.h"
     15 #include "base/strings/stringprintf.h"
     16 #include "chrome/test/chromedriver/chrome/adb.h"
     17 #include "chrome/test/chromedriver/chrome/status.h"
     18 
     19 // TODO(craigdh): Remove once Chromedriver no longer supports pre-m33 Chrome.
     20 const char* kChromeCmdLineFileBeforeM33 = "/data/local/chrome-command-line";
     21 const char* kChromeCmdLineFile = "/data/local/tmp/chrome-command-line";
     22 
     23 Device::Device(
     24     const std::string& device_serial, Adb* adb,
     25     base::Callback<void()> release_callback)
     26     : serial_(device_serial),
     27       adb_(adb),
     28       release_callback_(release_callback) {}
     29 
     30 Device::~Device() {
     31   release_callback_.Run();
     32 }
     33 
     34 Status Device::SetUp(const std::string& package,
     35                      const std::string& activity,
     36                      const std::string& process,
     37                      const std::string& args,
     38                      bool use_running_app,
     39                      int port) {
     40   if (!active_package_.empty())
     41     return Status(kUnknownError,
     42         active_package_ + " was launched and has not been quit");
     43 
     44   Status status = adb_->CheckAppInstalled(serial_, package);
     45   if (status.IsError())
     46     return status;
     47 
     48   std::string known_activity;
     49   std::string command_line_file;
     50   std::string device_socket;
     51   std::string exec_name;
     52   if (package.compare("org.chromium.content_shell_apk") == 0) {
     53     // Chromium content shell.
     54     known_activity = ".ContentShellActivity";
     55     device_socket = "content_shell_devtools_remote";
     56     command_line_file = "/data/local/tmp/content-shell-command-line";
     57     exec_name = "content_shell";
     58   } else if (package.compare("org.chromium.chrome.shell") == 0) {
     59     // ChromeShell
     60     known_activity = ".ChromeShellActivity";
     61     device_socket = "chrome_shell_devtools_remote";
     62     command_line_file = "/data/local/tmp/chrome-shell-command-line";
     63     exec_name = "chrome_shell";
     64   } else if (package.find("chrome") != std::string::npos &&
     65              package.find("webview") == std::string::npos) {
     66     // Chrome.
     67     known_activity = "com.google.android.apps.chrome.Main";
     68     device_socket = "chrome_devtools_remote";
     69     command_line_file = kChromeCmdLineFileBeforeM33;
     70     exec_name = "chrome";
     71     status = adb_->SetDebugApp(serial_, package);
     72     if (status.IsError())
     73       return status;
     74   }
     75 
     76   if (!use_running_app) {
     77     status = adb_->ClearAppData(serial_, package);
     78     if (status.IsError())
     79       return status;
     80 
     81     if (!known_activity.empty()) {
     82       if (!activity.empty() ||
     83           !process.empty())
     84         return Status(kUnknownError, "known package " + package +
     85                       " does not accept activity/process");
     86     } else if (activity.empty()) {
     87       return Status(kUnknownError, "WebView apps require activity name");
     88     }
     89 
     90     if (!command_line_file.empty()) {
     91       // If Chrome is set as the debug app it looks in /data/local/tmp/.
     92       // There's no way to know if this is set, so write to both locations.
     93       // This can be removed once support for pre-M33 is no longer needed.
     94       if (command_line_file == kChromeCmdLineFileBeforeM33) {
     95         status = adb_->SetCommandLineFile(
     96             serial_, kChromeCmdLineFileBeforeM33, exec_name, args);
     97         Status status2 = adb_->SetCommandLineFile(
     98             serial_, kChromeCmdLineFile, exec_name, args);
     99         if (status.IsError() && status2.IsError())
    100           return Status(kUnknownError,
    101               "Failed to set Chrome's command line file on device " + serial_);
    102       } else {
    103         status = adb_->SetCommandLineFile(
    104             serial_, command_line_file, exec_name, args);
    105         if (status.IsError())
    106           return status;
    107       }
    108     }
    109 
    110     status = adb_->Launch(serial_, package,
    111                           known_activity.empty() ? activity : known_activity);
    112     if (status.IsError())
    113       return status;
    114 
    115     active_package_ = package;
    116   }
    117   this->ForwardDevtoolsPort(package, process, device_socket, port);
    118 
    119   return status;
    120 }
    121 
    122 Status Device::ForwardDevtoolsPort(const std::string& package,
    123                                    const std::string& process,
    124                                    std::string& device_socket,
    125                                    int port) {
    126   if (device_socket.empty()) {
    127     // Assume this is a WebView app.
    128     int pid;
    129     Status status = adb_->GetPidByName(serial_,
    130                                        process.empty() ? package : process,
    131                                        &pid);
    132     if (status.IsError()) {
    133       if (process.empty())
    134         status.AddDetails(
    135             "process name must be specified if not equal to package name");
    136       return status;
    137     }
    138     device_socket = base::StringPrintf("webview_devtools_remote_%d", pid);
    139   }
    140 
    141   return adb_->ForwardPort(serial_, port, device_socket);
    142 }
    143 
    144 Status Device::TearDown() {
    145   if (!active_package_.empty()) {
    146     std::string response;
    147     Status status = adb_->ForceStop(serial_, active_package_);
    148     if (status.IsError())
    149       return status;
    150     active_package_ = "";
    151   }
    152   return Status(kOk);
    153 }
    154 
    155 DeviceManager::DeviceManager(Adb* adb) : adb_(adb) {
    156   CHECK(adb_);
    157 }
    158 
    159 DeviceManager::~DeviceManager() {}
    160 
    161 Status DeviceManager::AcquireDevice(scoped_ptr<Device>* device) {
    162   std::vector<std::string> devices;
    163   Status status = adb_->GetDevices(&devices);
    164   if (status.IsError())
    165     return status;
    166 
    167   if (devices.empty())
    168     return Status(kUnknownError, "There are no devices online");
    169 
    170   base::AutoLock lock(devices_lock_);
    171   status = Status(kUnknownError, "All devices are in use (" +
    172                   base::IntToString(devices.size()) + " online)");
    173   std::vector<std::string>::iterator iter;
    174   for (iter = devices.begin(); iter != devices.end(); iter++) {
    175     if (!IsDeviceLocked(*iter)) {
    176       device->reset(LockDevice(*iter));
    177       status = Status(kOk);
    178       break;
    179     }
    180   }
    181   return status;
    182 }
    183 
    184 Status DeviceManager::AcquireSpecificDevice(
    185     const std::string& device_serial, scoped_ptr<Device>* device) {
    186   std::vector<std::string> devices;
    187   Status status = adb_->GetDevices(&devices);
    188   if (status.IsError())
    189     return status;
    190 
    191   if (std::find(devices.begin(), devices.end(), device_serial) == devices.end())
    192     return Status(kUnknownError,
    193         "Device " + device_serial + " is not online");
    194 
    195   base::AutoLock lock(devices_lock_);
    196   if (IsDeviceLocked(device_serial)) {
    197     status = Status(kUnknownError,
    198         "Device " + device_serial + " is already in use");
    199   } else {
    200     device->reset(LockDevice(device_serial));
    201     status = Status(kOk);
    202   }
    203   return status;
    204 }
    205 
    206 void DeviceManager::ReleaseDevice(const std::string& device_serial) {
    207   base::AutoLock lock(devices_lock_);
    208   active_devices_.remove(device_serial);
    209 }
    210 
    211 Device* DeviceManager::LockDevice(const std::string& device_serial) {
    212   active_devices_.push_back(device_serial);
    213   return new Device(device_serial, adb_,
    214       base::Bind(&DeviceManager::ReleaseDevice, base::Unretained(this),
    215                  device_serial));
    216 }
    217 
    218 bool DeviceManager::IsDeviceLocked(const std::string& device_serial) {
    219   return std::find(active_devices_.begin(), active_devices_.end(),
    220                    device_serial) != active_devices_.end();
    221 }
    222 
    223