• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
Device(const std::string & device_serial,Adb * adb,base::Callback<void ()> release_callback)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 
~Device()30 Device::~Device() {
31   release_callback_.Run();
32 }
33 
SetUp(const std::string & package,const std::string & activity,const std::string & process,const std::string & args,bool use_running_app,int port)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 
ForwardDevtoolsPort(const std::string & package,const std::string & process,std::string & device_socket,int port)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 
TearDown()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 
DeviceManager(Adb * adb)155 DeviceManager::DeviceManager(Adb* adb) : adb_(adb) {
156   CHECK(adb_);
157 }
158 
~DeviceManager()159 DeviceManager::~DeviceManager() {}
160 
AcquireDevice(scoped_ptr<Device> * device)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 
AcquireSpecificDevice(const std::string & device_serial,scoped_ptr<Device> * device)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 
ReleaseDevice(const std::string & device_serial)206 void DeviceManager::ReleaseDevice(const std::string& device_serial) {
207   base::AutoLock lock(devices_lock_);
208   active_devices_.remove(device_serial);
209 }
210 
LockDevice(const std::string & 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),
215                  device_serial));
216 }
217 
IsDeviceLocked(const std::string & device_serial)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