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.
5 #include "chrome/test/chromedriver/chrome/device_manager.h"
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"
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";
24 const std::string& device_serial, Adb* adb,
25 base::Callback<void()> release_callback)
26 : serial_(device_serial),
28 release_callback_(release_callback) {}
31 release_callback_.Run();
34 Status Device::SetUp(const std::string& package,
35 const std::string& activity,
36 const std::string& process,
37 const std::string& args,
40 if (!active_package_.empty())
41 return Status(kUnknownError,
42 active_package_ + " was launched and has not been quit");
44 Status status = adb_->CheckAppInstalled(serial_, package);
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) {
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) {
67 known_activity = "com.google.android.apps.chrome.Main";
68 device_socket = "chrome_devtools_remote";
69 command_line_file = kChromeCmdLineFileBeforeM33;
71 status = adb_->SetDebugApp(serial_, package);
76 if (!use_running_app) {
77 status = adb_->ClearAppData(serial_, package);
81 if (!known_activity.empty()) {
82 if (!activity.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");
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_);
103 status = adb_->SetCommandLineFile(
104 serial_, command_line_file, exec_name, args);
105 if (status.IsError())
110 status = adb_->Launch(serial_, package,
111 known_activity.empty() ? activity : known_activity);
112 if (status.IsError())
115 active_package_ = package;
117 this->ForwardDevtoolsPort(package, process, port, &device_socket);
122 Status Device::ForwardDevtoolsPort(const std::string& package,
123 const std::string& process,
125 std::string* device_socket) {
126 if (device_socket->empty()) {
127 // Assume this is a WebView app.
129 Status status = adb_->GetPidByName(serial_,
130 process.empty() ? package : process,
132 if (status.IsError()) {
135 "process name must be specified if not equal to package name");
138 *device_socket = base::StringPrintf("webview_devtools_remote_%d", pid);
141 return adb_->ForwardPort(serial_, port, *device_socket);
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())
150 active_package_ = "";
155 DeviceManager::DeviceManager(Adb* adb) : adb_(adb) {
159 DeviceManager::~DeviceManager() {}
161 Status DeviceManager::AcquireDevice(scoped_ptr<Device>* device) {
162 std::vector<std::string> devices;
163 Status status = adb_->GetDevices(&devices);
164 if (status.IsError())
168 return Status(kUnknownError, "There are no devices online");
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);
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())
191 if (std::find(devices.begin(), devices.end(), device_serial) == devices.end())
192 return Status(kUnknownError,
193 "Device " + device_serial + " is not online");
195 base::AutoLock lock(devices_lock_);
196 if (IsDeviceLocked(device_serial)) {
197 status = Status(kUnknownError,
198 "Device " + device_serial + " is already in use");
200 device->reset(LockDevice(device_serial));
201 status = Status(kOk);
206 void DeviceManager::ReleaseDevice(const std::string& device_serial) {
207 base::AutoLock lock(devices_lock_);
208 active_devices_.remove(device_serial);
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),
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();