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 19Device::Device( 20 const std::string& device_serial, Adb* adb, 21 base::Callback<void()> release_callback) 22 : serial_(device_serial), 23 adb_(adb), 24 release_callback_(release_callback) {} 25 26Device::~Device() { 27 release_callback_.Run(); 28} 29 30Status Device::SetUp(const std::string& package, 31 const std::string& activity, 32 const std::string& process, 33 const std::string& args, 34 bool use_running_app, 35 int port) { 36 if (!active_package_.empty()) 37 return Status(kUnknownError, 38 active_package_ + " was launched and has not been quit"); 39 40 Status status = adb_->CheckAppInstalled(serial_, package); 41 if (!status.IsOk()) 42 return status; 43 44 std::string known_activity; 45 std::string command_line_file; 46 std::string device_socket; 47 std::string exec_name; 48 if (package.compare("org.chromium.content_shell_apk") == 0) { 49 known_activity = ".ContentShellActivity"; 50 device_socket = "content_shell_devtools_remote"; 51 command_line_file = "/data/local/tmp/content-shell-command-line"; 52 exec_name = "content_shell"; 53 } else if (package.compare("org.chromium.chrome.testshell") == 0) { 54 known_activity = ".ChromiumTestShellActivity"; 55 device_socket = "chromium_testshell_devtools_remote"; 56 command_line_file = "/data/local/tmp/chromium-testshell-command-line"; 57 exec_name = "chromium_testshell"; 58 } else if (package.find("chrome") != std::string::npos && 59 package.find("webview") == std::string::npos) { 60 known_activity = "com.google.android.apps.chrome.Main"; 61 device_socket = "chrome_devtools_remote"; 62 command_line_file = "/data/local/chrome-command-line"; 63 exec_name = "chrome"; 64 } 65 66 if (!use_running_app) { 67 status = adb_->ClearAppData(serial_, package); 68 if (!status.IsOk()) 69 return status; 70 71 if (!known_activity.empty()) { 72 if (!activity.empty() || 73 !process.empty()) 74 return Status(kUnknownError, "known package " + package + 75 " does not accept activity/process"); 76 } else if (activity.empty()) { 77 return Status(kUnknownError, "WebView apps require activity name"); 78 } 79 80 if (!command_line_file.empty()) { 81 status = adb_->SetCommandLineFile(serial_, command_line_file, exec_name, 82 args); 83 if (!status.IsOk()) 84 return status; 85 } 86 87 status = adb_->Launch(serial_, package, 88 known_activity.empty() ? activity : known_activity); 89 if (!status.IsOk()) 90 return status; 91 92 active_package_ = package; 93 } 94 this->ForwardDevtoolsPort(package, process, device_socket, port); 95 96 return status; 97} 98 99Status Device::ForwardDevtoolsPort(const std::string& package, 100 const std::string& process, 101 std::string& device_socket, 102 int port) { 103 if (device_socket.empty()) { 104 // Assume this is a WebView app. 105 int pid; 106 Status status = adb_->GetPidByName(serial_, 107 process.empty() ? package : process, 108 &pid); 109 if (!status.IsOk()) { 110 if (process.empty()) 111 status.AddDetails( 112 "process name must be specified if not equal to package name"); 113 return status; 114 } 115 device_socket = base::StringPrintf("webview_devtools_remote_%d", pid); 116 } 117 118 return adb_->ForwardPort(serial_, port, device_socket); 119} 120 121Status Device::TearDown() { 122 if (!active_package_.empty()) { 123 std::string response; 124 Status status = adb_->ForceStop(serial_, active_package_); 125 if (!status.IsOk()) 126 return status; 127 active_package_ = ""; 128 } 129 return Status(kOk); 130} 131 132DeviceManager::DeviceManager(Adb* adb) : adb_(adb) { 133 CHECK(adb_); 134} 135 136DeviceManager::~DeviceManager() {} 137 138Status DeviceManager::AcquireDevice(scoped_ptr<Device>* device) { 139 std::vector<std::string> devices; 140 Status status = adb_->GetDevices(&devices); 141 if (!status.IsOk()) 142 return status; 143 144 if (devices.empty()) 145 return Status(kUnknownError, "There are no devices online"); 146 147 base::AutoLock lock(devices_lock_); 148 status = Status(kUnknownError, "All devices are in use (" + 149 base::IntToString(devices.size()) + " online)"); 150 std::vector<std::string>::iterator iter; 151 for (iter = devices.begin(); iter != devices.end(); iter++) { 152 if (!IsDeviceLocked(*iter)) { 153 device->reset(LockDevice(*iter)); 154 status = Status(kOk); 155 break; 156 } 157 } 158 return status; 159} 160 161Status DeviceManager::AcquireSpecificDevice( 162 const std::string& device_serial, scoped_ptr<Device>* device) { 163 std::vector<std::string> devices; 164 Status status = adb_->GetDevices(&devices); 165 if (!status.IsOk()) 166 return status; 167 168 if (std::find(devices.begin(), devices.end(), device_serial) == devices.end()) 169 return Status(kUnknownError, 170 "Device " + device_serial + " is not online"); 171 172 base::AutoLock lock(devices_lock_); 173 if (IsDeviceLocked(device_serial)) { 174 status = Status(kUnknownError, 175 "Device " + device_serial + " is already in use"); 176 } else { 177 device->reset(LockDevice(device_serial)); 178 status = Status(kOk); 179 } 180 return status; 181} 182 183void DeviceManager::ReleaseDevice(const std::string& device_serial) { 184 base::AutoLock lock(devices_lock_); 185 active_devices_.remove(device_serial); 186} 187 188Device* DeviceManager::LockDevice(const std::string& device_serial) { 189 active_devices_.push_back(device_serial); 190 return new Device(device_serial, adb_, 191 base::Bind(&DeviceManager::ReleaseDevice, base::Unretained(this), 192 device_serial)); 193} 194 195bool DeviceManager::IsDeviceLocked(const std::string& device_serial) { 196 return std::find(active_devices_.begin(), active_devices_.end(), 197 device_serial) != active_devices_.end(); 198} 199 200