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. 20const char* kChromeCmdLineFileBeforeM33 = "/data/local/chrome-command-line"; 21const char* kChromeCmdLineFile = "/data/local/tmp/chrome-command-line"; 22 23Device::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 30Device::~Device() { 31 release_callback_.Run(); 32} 33 34Status 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 122Status 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 144Status 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 155DeviceManager::DeviceManager(Adb* adb) : adb_(adb) { 156 CHECK(adb_); 157} 158 159DeviceManager::~DeviceManager() {} 160 161Status 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 184Status 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 206void DeviceManager::ReleaseDevice(const std::string& device_serial) { 207 base::AutoLock lock(devices_lock_); 208 active_devices_.remove(device_serial); 209} 210 211Device* 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 218bool 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