Home | History | Annotate | Download | only in chrome
      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/json/string_escape.h"
     10 #include "base/logging.h"
     11 #include "base/memory/ref_counted.h"
     12 #include "base/message_loop/message_loop.h"
     13 #include "base/single_thread_task_runner.h"
     14 #include "base/strings/string_number_conversions.h"
     15 #include "base/strings/string_split.h"
     16 #include "base/strings/string_tokenizer.h"
     17 #include "base/strings/stringprintf.h"
     18 #include "base/synchronization/waitable_event.h"
     19 #include "base/time/time.h"
     20 #include "chrome/test/chromedriver/chrome/status.h"
     21 #include "chrome/test/chromedriver/net/adb_client_socket.h"
     22 
     23 namespace {
     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.
     27 class 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 
     64 void ExecuteCommandOnIOThread(
     65     const std::string& command, scoped_refptr<ResponseBuffer> response_buffer,
     66     int port) {
     67   CHECK(base::MessageLoopForIO::IsCurrent());
     68   AdbClientSocket::AdbQuery(port, command,
     69       base::Bind(&ResponseBuffer::OnResponse, response_buffer));
     70 }
     71 
     72 }  // namespace
     73 
     74 AdbImpl::AdbImpl(
     75     const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner,
     76     int port)
     77     : io_task_runner_(io_task_runner), port_(port) {
     78   CHECK(io_task_runner_.get());
     79 }
     80 
     81 AdbImpl::~AdbImpl() {}
     82 
     83 Status AdbImpl::GetDevices(std::vector<std::string>* devices) {
     84   std::string response;
     85   Status status = ExecuteCommand("host:devices", &response);
     86   if (!status.IsOk())
     87     return status;
     88   base::StringTokenizer lines(response, "\n");
     89   while (lines.GetNext()) {
     90     std::vector<std::string> fields;
     91     base::SplitStringAlongWhitespace(lines.token(), &fields);
     92     if (fields.size() == 2 && fields[1] == "device") {
     93       devices->push_back(fields[0]);
     94     }
     95   }
     96   return Status(kOk);
     97 }
     98 
     99 Status AdbImpl::ForwardPort(
    100     const std::string& device_serial, int local_port,
    101     const std::string& remote_abstract) {
    102   std::string response;
    103   Status status = ExecuteHostCommand(
    104       device_serial,
    105       "forward:tcp:" + base::IntToString(local_port) + ";localabstract:" +
    106           remote_abstract,
    107       &response);
    108   if (!status.IsOk())
    109     return status;
    110   if (response == "OKAY")
    111     return Status(kOk);
    112   return Status(kUnknownError, "Failed to forward ports to device " +
    113                 device_serial + ": " + response);
    114 }
    115 
    116 Status AdbImpl::SetCommandLineFile(const std::string& device_serial,
    117                                    const std::string& command_line_file,
    118                                    const std::string& exec_name,
    119                                    const std::string& args) {
    120   std::string response;
    121   std::string quoted_command =
    122       base::GetQuotedJSONString(exec_name + " " + args);
    123   Status status = ExecuteHostShellCommand(
    124       device_serial,
    125       base::StringPrintf("echo %s > %s; echo $?",
    126                          quoted_command.c_str(),
    127                          command_line_file.c_str()),
    128       &response);
    129   if (!status.IsOk())
    130     return status;
    131   if (response.find("0") == std::string::npos)
    132     return Status(kUnknownError, "Failed to set command line file " +
    133                   command_line_file + " on device " + device_serial);
    134   return Status(kOk);
    135 }
    136 
    137 Status AdbImpl::CheckAppInstalled(
    138     const std::string& device_serial, const std::string& package) {
    139   std::string response;
    140   std::string command = "pm path " + package;
    141   Status status = ExecuteHostShellCommand(device_serial, command, &response);
    142   if (!status.IsOk())
    143     return status;
    144   if (response.find("package") == std::string::npos)
    145     return Status(kUnknownError, package + " is not installed on device " +
    146                   device_serial);
    147   return Status(kOk);
    148 }
    149 
    150 Status AdbImpl::ClearAppData(
    151     const std::string& device_serial, const std::string& package) {
    152   std::string response;
    153   std::string command = "pm clear " + package;
    154   Status status = ExecuteHostShellCommand(device_serial, command, &response);
    155   if (!status.IsOk())
    156     return status;
    157   if (response.find("Success") == std::string::npos)
    158     return Status(kUnknownError, "Failed to clear data for " + package +
    159                   " on device " + device_serial + ": " + response);
    160   return Status(kOk);
    161 }
    162 
    163 Status AdbImpl::SetDebugApp(
    164     const std::string& device_serial, const std::string& package) {
    165   std::string response;
    166   return ExecuteHostShellCommand(
    167       device_serial, "am set-debug-app --persistent " + package, &response);
    168 }
    169 
    170 Status AdbImpl::Launch(
    171     const std::string& device_serial, const std::string& package,
    172     const std::string& activity) {
    173   std::string response;
    174   Status status = ExecuteHostShellCommand(
    175       device_serial,
    176       "am start -W -n " + package + "/" + activity + " -d data:,",
    177       &response);
    178   if (!status.IsOk())
    179     return status;
    180   if (response.find("Complete") == std::string::npos)
    181     return Status(kUnknownError,
    182                   "Failed to start " + package + " on device " + device_serial +
    183                   ": " + response);
    184   return Status(kOk);
    185 }
    186 
    187 Status AdbImpl::ForceStop(
    188     const std::string& device_serial, const std::string& package) {
    189   std::string response;
    190   return ExecuteHostShellCommand(
    191       device_serial, "am force-stop " + package, &response);
    192 }
    193 
    194 Status AdbImpl::GetPidByName(const std::string& device_serial,
    195                              const std::string& process_name,
    196                              int* pid) {
    197   std::string response;
    198   Status status = ExecuteHostShellCommand(device_serial, "ps", &response);
    199   if (!status.IsOk())
    200     return status;
    201 
    202   std::vector<std::string> lines;
    203   base::SplitString(response, '\n', &lines);
    204   for (size_t i = 0; i < lines.size(); ++i) {
    205     std::string line = lines[i];
    206     if (line.empty())
    207       continue;
    208     std::vector<std::string> tokens;
    209     base::SplitStringAlongWhitespace(line, &tokens);
    210     if (tokens.size() != 9)
    211       continue;
    212     if (tokens[8].compare(process_name) == 0) {
    213       if (base::StringToInt(tokens[1], pid)) {
    214         return Status(kOk);
    215       } else {
    216         break;
    217       }
    218     }
    219   }
    220 
    221   return Status(kUnknownError,
    222                 "Failed to get PID for the following process: " + process_name);
    223 }
    224 
    225 Status AdbImpl::ExecuteCommand(
    226     const std::string& command, std::string* response) {
    227   scoped_refptr<ResponseBuffer> response_buffer = new ResponseBuffer;
    228   VLOG(1) << "Sending adb command: " << command;
    229   io_task_runner_->PostTask(
    230       FROM_HERE,
    231       base::Bind(&ExecuteCommandOnIOThread, command, response_buffer, port_));
    232   Status status = response_buffer->GetResponse(
    233       response, base::TimeDelta::FromSeconds(30));
    234   if (status.IsOk()) {
    235     VLOG(1) << "Received adb response: " << *response;
    236   }
    237   return status;
    238 }
    239 
    240 Status AdbImpl::ExecuteHostCommand(
    241     const std::string& device_serial,
    242     const std::string& host_command, std::string* response) {
    243   return ExecuteCommand(
    244       "host-serial:" + device_serial + ":" + host_command, response);
    245 }
    246 
    247 Status AdbImpl::ExecuteHostShellCommand(
    248     const std::string& device_serial,
    249     const std::string& shell_command,
    250     std::string* response) {
    251   return ExecuteCommand(
    252       "host:transport:" + device_serial + "|shell:" + shell_command,
    253       response);
    254 }
    255 
    256