adb_impl.cc revision 868fa2fe829687343ffae624259930155e16dbd8
1// Copyright 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/adb_impl.h"
6
7#include "base/bind.h"
8#include "base/bind_helpers.h"
9#include "base/logging.h"
10#include "base/memory/ref_counted.h"
11#include "base/message_loop.h"
12#include "base/message_loop/message_loop_proxy.h"
13#include "base/strings/string_number_conversions.h"
14#include "base/strings/string_split.h"
15#include "base/strings/string_tokenizer.h"
16#include "base/strings/stringprintf.h"
17#include "base/synchronization/waitable_event.h"
18#include "base/time.h"
19#include "chrome/test/chromedriver/chrome/log.h"
20#include "chrome/test/chromedriver/chrome/status.h"
21#include "chrome/test/chromedriver/net/adb_client_socket.h"
22
23namespace {
24
25// This class is bound in the callback to AdbQuery and isn't freed until the
26// callback is run, even if the function that creates the buffer times out.
27class ResponseBuffer : public base::RefCountedThreadSafe<ResponseBuffer> {
28 public:
29  ResponseBuffer() : ready_(true, false) {}
30
31  void OnResponse(int result, const std::string& response) {
32    response_ = response;
33    result_ = result;
34    ready_.Signal();
35  }
36
37  Status GetResponse(
38      std::string* response, const base::TimeDelta& timeout) {
39    base::TimeTicks deadline = base::TimeTicks::Now() + timeout;
40    while (!ready_.IsSignaled()) {
41      base::TimeDelta delta = deadline - base::TimeTicks::Now();
42      if (delta <= base::TimeDelta())
43        return Status(kTimeout, base::StringPrintf(
44            "Adb command timed out after %d seconds",
45            static_cast<int>(timeout.InSeconds())));
46      ready_.TimedWait(timeout);
47    }
48    if (result_ < 0)
49      return Status(kUnknownError,
50          "Failed to run adb command, is the adb server running?");
51    *response = response_;
52    return Status(kOk);
53  }
54
55 private:
56  friend class base::RefCountedThreadSafe<ResponseBuffer>;
57  ~ResponseBuffer() {}
58
59  std::string response_;
60  int result_;
61  base::WaitableEvent ready_;
62};
63
64void ExecuteCommandOnIOThread(
65    const std::string& command, scoped_refptr<ResponseBuffer> response_buffer) {
66  CHECK(base::MessageLoop::current()->IsType(base::MessageLoop::TYPE_IO));
67  AdbClientSocket::AdbQuery(5037, command,
68      base::Bind(&ResponseBuffer::OnResponse, response_buffer));
69}
70
71}  // namespace
72
73AdbImpl::AdbImpl(
74    const scoped_refptr<base::MessageLoopProxy>& io_message_loop_proxy,
75    Log* log)
76    : io_message_loop_proxy_(io_message_loop_proxy), log_(log) {
77  CHECK(io_message_loop_proxy_);
78}
79
80AdbImpl::~AdbImpl() {}
81
82Status AdbImpl::GetDevices(std::vector<std::string>* devices) {
83  std::string response;
84  Status status = ExecuteCommand("host:devices", &response);
85  if (!status.IsOk())
86    return status;
87  base::StringTokenizer lines(response, "\n");
88  while (lines.GetNext()) {
89    std::vector<std::string> fields;
90    base::SplitStringAlongWhitespace(lines.token(), &fields);
91    if (fields.size() == 2 && fields[1] == "device") {
92      devices->push_back(fields[0]);
93    }
94  }
95  return Status(kOk);
96}
97
98Status AdbImpl::ForwardPort(
99    const std::string& device_serial, int local_port,
100    const std::string& remote_abstract) {
101  std::string response;
102  Status status = ExecuteHostCommand(
103      device_serial,
104      "forward:tcp:" + base::IntToString(local_port) + ";localabstract:" +
105          remote_abstract,
106      &response);
107  if (!status.IsOk())
108    return status;
109  if (response == "OKAY")
110    return Status(kOk);
111  return Status(kUnknownError, "Failed to forward ports to device " +
112                device_serial + ": " + response);
113}
114
115Status AdbImpl::SetChromeFlags(const std::string& device_serial) {
116  std::string response;
117  Status status = ExecuteHostShellCommand(
118      device_serial,
119      "echo chrome --disable-fre --metrics-recording-only "
120          "--enable-remote-debugging > /data/local/chrome-command-line;"
121          "echo $?",
122      &response);
123  if (!status.IsOk())
124    return status;
125  if (response.find("0") == std::string::npos)
126    return Status(kUnknownError, "Failed to set Chrome flags on device " +
127                  device_serial);
128  return Status(kOk);
129}
130
131Status AdbImpl::CheckAppInstalled(
132    const std::string& device_serial, const std::string& package) {
133  std::string response;
134  std::string command = "pm path " + package;
135  Status status = ExecuteHostShellCommand(device_serial, command, &response);
136  if (!status.IsOk())
137    return status;
138  if (response.find("package") == std::string::npos)
139    return Status(kUnknownError, package + " is not installed on device " +
140                  device_serial);
141  return Status(kOk);
142}
143
144Status AdbImpl::ClearAppData(
145    const std::string& device_serial, const std::string& package) {
146  std::string response;
147  std::string command = "pm clear " + package;
148  Status status = ExecuteHostShellCommand(device_serial, command, &response);
149  if (!status.IsOk())
150    return status;
151  if (response.find("Success") == std::string::npos)
152    return Status(kUnknownError, "Failed to clear data for " + package +
153                  " on device " + device_serial + ": " + response);
154  return Status(kOk);
155}
156
157Status AdbImpl::Launch(
158    const std::string& device_serial, const std::string& package,
159    const std::string& activity) {
160  std::string response;
161  Status status = ExecuteHostShellCommand(
162      device_serial,
163      "am start -a android.intent.action.VIEW -S -W -n " +
164          package + "/" + activity + " -d \"data:text/html;charset=utf-8,\"",
165      &response);
166  if (!status.IsOk())
167    return status;
168  if (response.find("Complete") == std::string::npos)
169    return Status(kUnknownError,
170                  "Failed to start " + package + " on device " + device_serial +
171                  ": " + response);
172  return Status(kOk);
173}
174
175Status AdbImpl::ForceStop(
176    const std::string& device_serial, const std::string& package) {
177  std::string response;
178  return ExecuteHostShellCommand(
179      device_serial, "am force-stop " + package, &response);
180}
181
182Status AdbImpl::ExecuteCommand(
183    const std::string& command, std::string* response) {
184  scoped_refptr<ResponseBuffer> response_buffer = new ResponseBuffer;
185  log_->AddEntry(Log::kDebug, "Sending adb command: " + command);
186  io_message_loop_proxy_->PostTask(
187      FROM_HERE,
188      base::Bind(&ExecuteCommandOnIOThread, command, response_buffer));
189  Status status = response_buffer->GetResponse(
190      response, base::TimeDelta::FromSeconds(30));
191  if (status.IsOk())
192    log_->AddEntry(Log::kDebug, "Received adb response: " + *response);
193  return status;
194}
195
196Status AdbImpl::ExecuteHostCommand(
197    const std::string& device_serial,
198    const std::string& host_command, std::string* response) {
199  return ExecuteCommand(
200      "host-serial:" + device_serial + ":" + host_command, response);
201}
202
203Status AdbImpl::ExecuteHostShellCommand(
204    const std::string& device_serial,
205    const std::string& shell_command,
206    std::string* response) {
207  return ExecuteCommand(
208      "host:transport:" + device_serial + "|shell:" + shell_command,
209      response);
210}
211
212