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