190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved.
290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// found in the LICENSE file.
490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "chrome/test/chromedriver/chrome/device_manager.h"
690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
7868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include <algorithm>
8868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include <vector>
9868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
1090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/bind.h"
1190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/bind_helpers.h"
12868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/callback.h"
1390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/logging.h"
14d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include "base/strings/string_number_conversions.h"
15d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include "base/strings/stringprintf.h"
16868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "chrome/test/chromedriver/chrome/adb.h"
1790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "chrome/test/chromedriver/chrome/status.h"
1890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// TODO(craigdh): Remove once Chromedriver no longer supports pre-m33 Chrome.
205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char* kChromeCmdLineFileBeforeM33 = "/data/local/chrome-command-line";
215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char* kChromeCmdLineFile = "/data/local/tmp/chrome-command-line";
225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
23868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)Device::Device(
24868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const std::string& device_serial, Adb* adb,
25868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    base::Callback<void()> release_callback)
26868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    : serial_(device_serial),
27868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      adb_(adb),
28868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      release_callback_(release_callback) {}
2990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
30868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)Device::~Device() {
31868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  release_callback_.Run();
32868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
3390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
34a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)Status Device::SetUp(const std::string& package,
35a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                     const std::string& activity,
36a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                     const std::string& process,
37a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                     const std::string& args,
38a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                     bool use_running_app,
39a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                     int port) {
40868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!active_package_.empty())
41868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return Status(kUnknownError,
42868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        active_package_ + " was launched and has not been quit");
43d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
44868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  Status status = adb_->CheckAppInstalled(serial_, package);
455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (status.IsError())
4690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return status;
47d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
48d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  std::string known_activity;
49d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  std::string command_line_file;
50a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  std::string device_socket;
51d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  std::string exec_name;
52d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  if (package.compare("org.chromium.content_shell_apk") == 0) {
535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Chromium content shell.
54d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    known_activity = ".ContentShellActivity";
55d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    device_socket = "content_shell_devtools_remote";
56d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    command_line_file = "/data/local/tmp/content-shell-command-line";
57d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    exec_name = "content_shell";
58a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  } else if (package.compare("org.chromium.chrome.shell") == 0) {
59a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // ChromeShell
60a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    known_activity = ".ChromeShellActivity";
61a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    device_socket = "chrome_shell_devtools_remote";
62a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    command_line_file = "/data/local/tmp/chrome-shell-command-line";
63a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    exec_name = "chrome_shell";
64f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  } else if (package.find("chrome") != std::string::npos &&
65f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)             package.find("webview") == std::string::npos) {
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Chrome.
67d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    known_activity = "com.google.android.apps.chrome.Main";
68d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    device_socket = "chrome_devtools_remote";
695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    command_line_file = kChromeCmdLineFileBeforeM33;
70d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    exec_name = "chrome";
715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    status = adb_->SetDebugApp(serial_, package);
725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (status.IsError())
735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return status;
74d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
75d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
76a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (!use_running_app) {
77a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    status = adb_->ClearAppData(serial_, package);
785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (status.IsError())
79a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      return status;
80d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
81a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    if (!known_activity.empty()) {
82a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      if (!activity.empty() ||
83a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)          !process.empty())
84a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        return Status(kUnknownError, "known package " + package +
85a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                      " does not accept activity/process");
86a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    } else if (activity.empty()) {
87a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      return Status(kUnknownError, "WebView apps require activity name");
88a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    }
89a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
90a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    if (!command_line_file.empty()) {
915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      // If Chrome is set as the debug app it looks in /data/local/tmp/.
925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      // There's no way to know if this is set, so write to both locations.
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      // This can be removed once support for pre-M33 is no longer needed.
945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (command_line_file == kChromeCmdLineFileBeforeM33) {
955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        status = adb_->SetCommandLineFile(
965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            serial_, kChromeCmdLineFileBeforeM33, exec_name, args);
975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        Status status2 = adb_->SetCommandLineFile(
985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            serial_, kChromeCmdLineFile, exec_name, args);
995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        if (status.IsError() && status2.IsError())
1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          return Status(kUnknownError,
1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              "Failed to set Chrome's command line file on device " + serial_);
1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      } else {
1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        status = adb_->SetCommandLineFile(
1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            serial_, command_line_file, exec_name, args);
1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        if (status.IsError())
1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          return status;
1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      }
108a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    }
109a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
110a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    status = adb_->Launch(serial_, package,
111a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                          known_activity.empty() ? activity : known_activity);
1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (status.IsError())
113d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      return status;
114a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
115a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    active_package_ = package;
116d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
117a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  this->ForwardDevtoolsPort(package, process, device_socket, port);
118d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
119a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  return status;
120a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
121d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
122a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)Status Device::ForwardDevtoolsPort(const std::string& package,
123a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                   const std::string& process,
124a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                   std::string& device_socket,
125a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                   int port) {
126d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  if (device_socket.empty()) {
127d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    // Assume this is a WebView app.
128d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    int pid;
129a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    Status status = adb_->GetPidByName(serial_,
130a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                       process.empty() ? package : process,
131a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                       &pid);
1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (status.IsError()) {
133d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      if (process.empty())
134d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        status.AddDetails(
135d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch            "process name must be specified if not equal to package name");
136d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      return status;
137d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    }
138d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    device_socket = base::StringPrintf("webview_devtools_remote_%d", pid);
139d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
140d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
141d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  return adb_->ForwardPort(serial_, port, device_socket);
14290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
14390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
144a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)Status Device::TearDown() {
145d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  if (!active_package_.empty()) {
146d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    std::string response;
147d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    Status status = adb_->ForceStop(serial_, active_package_);
1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (status.IsError())
149d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      return status;
150d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    active_package_ = "";
151d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
152868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return Status(kOk);
15390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
15490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
155868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)DeviceManager::DeviceManager(Adb* adb) : adb_(adb) {
156868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  CHECK(adb_);
15790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
15890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
159868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)DeviceManager::~DeviceManager() {}
160868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
161868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)Status DeviceManager::AcquireDevice(scoped_ptr<Device>* device) {
162868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  std::vector<std::string> devices;
163868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  Status status = adb_->GetDevices(&devices);
1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (status.IsError())
16590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return status;
166868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
1674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (devices.empty())
1684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return Status(kUnknownError, "There are no devices online");
1694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
170868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  base::AutoLock lock(devices_lock_);
1714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  status = Status(kUnknownError, "All devices are in use (" +
1724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                  base::IntToString(devices.size()) + " online)");
173868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  std::vector<std::string>::iterator iter;
174868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  for (iter = devices.begin(); iter != devices.end(); iter++) {
175868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (!IsDeviceLocked(*iter)) {
176868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      device->reset(LockDevice(*iter));
177868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      status = Status(kOk);
178868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      break;
179868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    }
180868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
181868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return status;
18290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
18390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
184868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)Status DeviceManager::AcquireSpecificDevice(
185868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const std::string& device_serial, scoped_ptr<Device>* device) {
186868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  std::vector<std::string> devices;
187868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  Status status = adb_->GetDevices(&devices);
1885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (status.IsError())
18990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return status;
19090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
191868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (std::find(devices.begin(), devices.end(), device_serial) == devices.end())
192868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return Status(kUnknownError,
1934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        "Device " + device_serial + " is not online");
194868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
195868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  base::AutoLock lock(devices_lock_);
196868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (IsDeviceLocked(device_serial)) {
197868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    status = Status(kUnknownError,
1984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        "Device " + device_serial + " is already in use");
199868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  } else {
200868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    device->reset(LockDevice(device_serial));
201868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    status = Status(kOk);
20290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
203868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return status;
20490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
20590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
206868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void DeviceManager::ReleaseDevice(const std::string& device_serial) {
207868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  base::AutoLock lock(devices_lock_);
208868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  active_devices_.remove(device_serial);
20990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
21090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
211868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)Device* DeviceManager::LockDevice(const std::string& device_serial) {
212868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  active_devices_.push_back(device_serial);
213868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return new Device(device_serial, adb_,
214868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      base::Bind(&DeviceManager::ReleaseDevice, base::Unretained(this),
215868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                 device_serial));
21690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
21790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
218868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)bool DeviceManager::IsDeviceLocked(const std::string& device_serial) {
219868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return std::find(active_devices_.begin(), active_devices_.end(),
220868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                   device_serial) != active_devices_.end();
22190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
222868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
223