684 lines · cpp
1//===-- AdbClient.cpp -----------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "AdbClient.h"10 11#include "lldb/Host/ConnectionFileDescriptor.h"12#include "lldb/Host/FileSystem.h"13#include "lldb/Utility/Connection.h"14#include "lldb/Utility/DataEncoder.h"15#include "lldb/Utility/DataExtractor.h"16#include "lldb/Utility/FileSpec.h"17#include "lldb/Utility/LLDBLog.h"18#include "lldb/Utility/Log.h"19#include "lldb/Utility/Status.h"20#include "lldb/Utility/StreamString.h"21#include "lldb/Utility/Timeout.h"22#include "llvm/ADT/SmallVector.h"23#include "llvm/ADT/StringRef.h"24#include "llvm/Support/FileUtilities.h"25#include <chrono>26 27#include <climits>28#include <cstdlib>29#include <fstream>30#include <sstream>31 32using namespace lldb;33using namespace lldb_private;34using namespace lldb_private::platform_android;35using namespace std::chrono;36using namespace llvm;37 38static const char *kSocketNamespaceAbstract = "localabstract";39static const char *kSocketNamespaceFileSystem = "localfilesystem";40const seconds kReadTimeout(20);41static const char *kOKAY = "OKAY";42static const char *kFAIL = "FAIL";43static const char *kDATA = "DATA";44static const char *kDONE = "DONE";45static const char *kSEND = "SEND";46static const char *kRECV = "RECV";47static const char *kSTAT = "STAT";48static const size_t kSyncPacketLen = 8;49static const size_t kMaxPushData = 2 * 1024;50static const uint32_t kDefaultMode = 0100770;51 52static Status ReadAllBytes(Connection &conn, void *buffer, size_t size) {53 Status error;54 ConnectionStatus status;55 char *read_buffer = static_cast<char *>(buffer);56 57 auto now = steady_clock::now();58 const auto deadline = now + kReadTimeout;59 size_t total_read_bytes = 0;60 while (total_read_bytes < size && now < deadline) {61 auto read_bytes =62 conn.Read(read_buffer + total_read_bytes, size - total_read_bytes,63 duration_cast<microseconds>(deadline - now), status, &error);64 if (error.Fail())65 return error;66 total_read_bytes += read_bytes;67 if (status != eConnectionStatusSuccess)68 break;69 now = steady_clock::now();70 }71 if (total_read_bytes < size)72 error = Status::FromErrorStringWithFormat(73 "Unable to read requested number of bytes. Connection status: %d.",74 status);75 76 return error;77}78 79static Status ReadAdbMessage(Connection &conn, std::vector<char> &message) {80 message.clear();81 82 char buffer[5];83 buffer[4] = 0;84 85 auto error = ReadAllBytes(conn, buffer, 4);86 if (error.Fail())87 return error;88 89 unsigned int packet_len = 0;90 sscanf(buffer, "%x", &packet_len);91 92 message.resize(packet_len, 0);93 error = ReadAllBytes(conn, &message[0], packet_len);94 if (error.Fail())95 message.clear();96 97 return error;98}99 100static Status GetResponseError(Connection &conn, const char *response_id) {101 if (strcmp(response_id, kFAIL) != 0)102 return Status::FromErrorStringWithFormat(103 "Got unexpected response id from adb: \"%s\"", response_id);104 105 std::vector<char> error_message;106 auto error = ReadAdbMessage(conn, error_message);107 if (!error.Success())108 return error;109 110 std::string error_str(&error_message[0], error_message.size());111 Log *log = GetLog(LLDBLog::Platform);112 LLDB_LOGF(log, "ADB error: %s", error_str.c_str());113 return Status(error_str);114}115 116static Status ReadResponseStatus(Connection &conn) {117 char response_id[5];118 119 const size_t packet_len = 4;120 response_id[packet_len] = 0;121 122 auto error = ReadAllBytes(conn, response_id, packet_len);123 if (error.Fail())124 return error;125 126 if (strncmp(response_id, kOKAY, packet_len) != 0)127 return GetResponseError(conn, response_id);128 129 return error;130}131 132static Status SendAdbMessage(Connection &conn, llvm::StringRef packet) {133 Status error;134 135 char length_buffer[5];136 snprintf(length_buffer, sizeof(length_buffer), "%04x",137 static_cast<int>(packet.size()));138 139 ConnectionStatus status;140 141 conn.Write(length_buffer, 4, status, &error);142 if (error.Fail())143 return error;144 145 conn.Write(packet.str().c_str(), packet.size(), status, &error);146 return error;147}148 149static Status ConnectToAdb(Connection &conn) {150 std::string port = "5037";151 if (const char *env_port = std::getenv("ANDROID_ADB_SERVER_PORT"))152 port = env_port;153 std::string uri = "connect://127.0.0.1:" + port;154 155 Log *log = GetLog(LLDBLog::Platform);156 LLDB_LOGF(log, "Connecting to ADB server at %s", uri.c_str());157 158 Status error;159 conn.Connect(uri.c_str(), &error);160 return error;161}162 163static Status EnterSyncMode(Connection &conn) {164 auto error = SendAdbMessage(conn, "sync:");165 if (error.Fail())166 return error;167 168 return ReadResponseStatus(conn);169}170 171static Status SelectTargetDevice(Connection &conn, llvm::StringRef device_id) {172 Log *log = GetLog(LLDBLog::Platform);173 LLDB_LOG(log, "Selecting device: {0}", device_id);174 175 std::ostringstream msg;176 msg << "host:transport:" << device_id.str();177 178 auto error = SendAdbMessage(conn, msg.str());179 if (error.Fail())180 return error;181 182 return ReadResponseStatus(conn);183}184 185Expected<std::string> AdbClient::ResolveDeviceID(StringRef device_id) {186 StringRef preferred_serial;187 if (!device_id.empty())188 preferred_serial = device_id;189 else if (const char *env_serial = std::getenv("ANDROID_SERIAL"))190 preferred_serial = env_serial;191 192 if (preferred_serial.empty()) {193 DeviceIDList connected_devices;194 195 auto GetDevices = [](DeviceIDList &device_list) -> Status {196 device_list.clear();197 198 // Create temporary ADB client for this operation only199 auto temp_conn = std::make_unique<ConnectionFileDescriptor>();200 auto error = ConnectToAdb(*temp_conn);201 if (error.Fail())202 return error;203 204 // NOTE: ADB closes the connection after host:devices response.205 // The connection is no longer valid206 error = SendAdbMessage(*temp_conn, "host:devices");207 if (error.Fail())208 return error;209 210 error = ReadResponseStatus(*temp_conn);211 if (error.Fail())212 return error;213 214 std::vector<char> in_buffer;215 error = ReadAdbMessage(*temp_conn, in_buffer);216 217 StringRef response(&in_buffer[0], in_buffer.size());218 SmallVector<StringRef, 4> devices;219 response.split(devices, "\n", -1, false);220 221 for (const auto &device : devices)222 device_list.push_back(std::string(device.split('\t').first));223 return error;224 };225 226 Status error = GetDevices(connected_devices);227 if (error.Fail())228 return error.ToError();229 230 if (connected_devices.size() != 1)231 return createStringError(232 inconvertibleErrorCode(),233 "Expected a single connected device, got instead %zu - try "234 "setting 'ANDROID_SERIAL'",235 connected_devices.size());236 237 std::string resolved_device_id = std::move(connected_devices.front());238 Log *log = GetLog(LLDBLog::Platform);239 LLDB_LOGF(log, "AdbClient::ResolveDeviceID Resolved device ID: %s",240 resolved_device_id.c_str());241 return resolved_device_id;242 }243 244 std::string resolved_device_id = preferred_serial.str();245 Log *log = GetLog(LLDBLog::Platform);246 LLDB_LOGF(log, "AdbClient::ResolveDeviceID Resolved device ID: %s",247 resolved_device_id.c_str());248 return resolved_device_id;249}250 251AdbClient::AdbClient(llvm::StringRef device_id) : m_device_id(device_id) {252 Log *log = GetLog(LLDBLog::Platform);253 LLDB_LOGF(log,254 "AdbClient::AdbClient(device_id='%s') - Creating AdbClient with "255 "device ID",256 device_id.str().c_str());257 m_conn = std::make_unique<ConnectionFileDescriptor>();258 Connect();259}260 261AdbClient::AdbClient() {262 Log *log = GetLog(LLDBLog::Platform);263 LLDB_LOGF(264 log,265 "AdbClient::AdbClient() - Creating AdbClient with default constructor");266 m_conn = std::make_unique<ConnectionFileDescriptor>();267 Connect();268}269 270AdbClient::~AdbClient() {271 Log *log = GetLog(LLDBLog::Platform);272 LLDB_LOGF(log,273 "AdbClient::~AdbClient() - Destroying AdbClient for device: %s",274 m_device_id.c_str());275}276 277llvm::StringRef AdbClient::GetDeviceID() const { return m_device_id; }278 279Status AdbClient::Connect() {280 if (m_conn->IsConnected())281 return Status();282 283 return ConnectToAdb(*m_conn);284}285 286Status AdbClient::SetPortForwarding(const uint16_t local_port,287 const uint16_t remote_port) {288 char message[48];289 snprintf(message, sizeof(message), "forward:tcp:%d;tcp:%d", local_port,290 remote_port);291 292 Status error = SendDeviceMessage(message);293 if (error.Fail())294 return error;295 296 return ReadResponseStatus(*m_conn);297}298 299Status300AdbClient::SetPortForwarding(const uint16_t local_port,301 llvm::StringRef remote_socket_name,302 const UnixSocketNamespace socket_namespace) {303 char message[PATH_MAX];304 const char *sock_namespace_str =305 (socket_namespace == UnixSocketNamespaceAbstract)306 ? kSocketNamespaceAbstract307 : kSocketNamespaceFileSystem;308 snprintf(message, sizeof(message), "forward:tcp:%d;%s:%s", local_port,309 sock_namespace_str, remote_socket_name.str().c_str());310 311 Status error = SendDeviceMessage(message);312 if (error.Fail())313 return error;314 315 return ReadResponseStatus(*m_conn);316}317 318Status AdbClient::DeletePortForwarding(const uint16_t local_port) {319 char message[32];320 snprintf(message, sizeof(message), "killforward:tcp:%d", local_port);321 322 Status error = SendDeviceMessage(message);323 if (error.Fail())324 return error;325 326 return ReadResponseStatus(*m_conn);327}328 329Status AdbClient::SendDeviceMessage(llvm::StringRef packet) {330 std::ostringstream msg;331 msg << "host-serial:" << m_device_id << ":" << packet.str();332 return SendAdbMessage(*m_conn, msg.str());333}334 335Status AdbClient::ReadMessageStream(std::vector<char> &message,336 milliseconds timeout) {337 auto start = steady_clock::now();338 message.clear();339 340 if (!m_conn)341 return Status::FromErrorString("No connection available");342 343 Status error;344 lldb::ConnectionStatus status = lldb::eConnectionStatusSuccess;345 char buffer[1024];346 while (error.Success() && status == lldb::eConnectionStatusSuccess) {347 auto end = steady_clock::now();348 auto elapsed = end - start;349 if (elapsed >= timeout)350 return Status::FromErrorString("Timed out");351 352 size_t n = m_conn->Read(buffer, sizeof(buffer),353 duration_cast<microseconds>(timeout - elapsed),354 status, &error);355 if (n > 0)356 message.insert(message.end(), &buffer[0], &buffer[n]);357 }358 return error;359}360 361Status AdbClient::internalShell(const char *command, milliseconds timeout,362 std::vector<char> &output_buf) {363 output_buf.clear();364 365 auto error = SelectTargetDevice(*m_conn, m_device_id);366 if (error.Fail())367 return Status::FromErrorStringWithFormat(368 "Failed to select target device: %s", error.AsCString());369 370 StreamString adb_command;371 adb_command.Printf("shell:%s", command);372 error = SendAdbMessage(*m_conn, std::string(adb_command.GetString()));373 if (error.Fail())374 return error;375 376 error = ReadResponseStatus(*m_conn);377 if (error.Fail())378 return error;379 380 error = ReadMessageStream(output_buf, timeout);381 if (error.Fail())382 return error;383 384 // ADB doesn't propagate return code of shell execution - if385 // output starts with /system/bin/sh: most likely command failed.386 static const char *kShellPrefix = "/system/bin/sh:";387 if (output_buf.size() > strlen(kShellPrefix)) {388 if (!memcmp(&output_buf[0], kShellPrefix, strlen(kShellPrefix)))389 return Status::FromErrorStringWithFormat(390 "Shell command %s failed: %s", command,391 std::string(output_buf.begin(), output_buf.end()).c_str());392 }393 394 return Status();395}396 397Status AdbClient::Shell(const char *command, milliseconds timeout,398 std::string *output) {399 std::vector<char> output_buffer;400 auto error = internalShell(command, timeout, output_buffer);401 if (error.Fail())402 return error;403 404 if (output)405 output->assign(output_buffer.begin(), output_buffer.end());406 return error;407}408 409Status AdbClient::ShellToFile(const char *command, milliseconds timeout,410 const FileSpec &output_file_spec) {411 std::vector<char> output_buffer;412 auto error = internalShell(command, timeout, output_buffer);413 if (error.Fail())414 return error;415 416 const auto output_filename = output_file_spec.GetPath();417 std::error_code EC;418 llvm::raw_fd_ostream dst(output_filename, EC, llvm::sys::fs::OF_None);419 if (EC)420 return Status::FromErrorStringWithFormat("Unable to open local file %s",421 output_filename.c_str());422 423 dst.write(&output_buffer[0], output_buffer.size());424 dst.close();425 if (dst.has_error())426 return Status::FromErrorStringWithFormat("Failed to write file %s",427 output_filename.c_str());428 return Status();429}430 431Status AdbSyncService::PullFileImpl(const FileSpec &remote_file,432 const FileSpec &local_file) {433 const auto local_file_path = local_file.GetPath();434 llvm::FileRemover local_file_remover(local_file_path);435 436 std::error_code EC;437 llvm::raw_fd_ostream dst(local_file_path, EC, llvm::sys::fs::OF_None);438 if (EC)439 return Status::FromErrorStringWithFormat("Unable to open local file %s",440 local_file_path.c_str());441 442 const auto remote_file_path = remote_file.GetPath(false);443 auto error = SendSyncRequest(kRECV, remote_file_path.length(),444 remote_file_path.c_str());445 if (error.Fail())446 return error;447 448 std::vector<char> chunk;449 bool eof = false;450 while (!eof) {451 error = PullFileChunk(chunk, eof);452 if (error.Fail())453 return error;454 if (!eof)455 dst.write(&chunk[0], chunk.size());456 }457 dst.close();458 if (dst.has_error())459 return Status::FromErrorStringWithFormat("Failed to write file %s",460 local_file_path.c_str());461 462 local_file_remover.releaseFile();463 return error;464}465 466Status AdbSyncService::PushFileImpl(const FileSpec &local_file,467 const FileSpec &remote_file) {468 const auto local_file_path(local_file.GetPath());469 std::ifstream src(local_file_path.c_str(), std::ios::in | std::ios::binary);470 if (!src.is_open())471 return Status::FromErrorStringWithFormat("Unable to open local file %s",472 local_file_path.c_str());473 474 std::stringstream file_description;475 file_description << remote_file.GetPath(false).c_str() << "," << kDefaultMode;476 std::string file_description_str = file_description.str();477 auto error = SendSyncRequest(kSEND, file_description_str.length(),478 file_description_str.c_str());479 if (error.Fail())480 return error;481 482 char chunk[kMaxPushData];483 while (!src.eof() && !src.read(chunk, kMaxPushData).bad()) {484 size_t chunk_size = src.gcount();485 error = SendSyncRequest(kDATA, chunk_size, chunk);486 if (error.Fail())487 return Status::FromErrorStringWithFormat("Failed to send file chunk: %s",488 error.AsCString());489 }490 error = SendSyncRequest(491 kDONE,492 llvm::sys::toTimeT(493 FileSystem::Instance().GetModificationTime(local_file)),494 nullptr);495 if (error.Fail())496 return error;497 498 std::string response_id;499 uint32_t data_len;500 error = ReadSyncHeader(response_id, data_len);501 if (error.Fail())502 return Status::FromErrorStringWithFormat("Failed to read DONE response: %s",503 error.AsCString());504 if (response_id == kFAIL) {505 std::string error_message(data_len, 0);506 error = ReadAllBytes(*m_conn, &error_message[0], data_len);507 if (error.Fail())508 return Status::FromErrorStringWithFormat(509 "Failed to read DONE error message: %s", error.AsCString());510 return Status::FromErrorStringWithFormat("Failed to push file: %s",511 error_message.c_str());512 } else if (response_id != kOKAY)513 return Status::FromErrorStringWithFormat("Got unexpected DONE response: %s",514 response_id.c_str());515 516 // If there was an error reading the source file, finish the adb file517 // transfer first so that adb isn't expecting any more data.518 if (src.bad())519 return Status::FromErrorStringWithFormat("Failed read on %s",520 local_file_path.c_str());521 return error;522}523 524Status AdbSyncService::StatImpl(const FileSpec &remote_file, uint32_t &mode,525 uint32_t &size, uint32_t &mtime) {526 const std::string remote_file_path(remote_file.GetPath(false));527 auto error = SendSyncRequest(kSTAT, remote_file_path.length(),528 remote_file_path.c_str());529 if (error.Fail())530 return Status::FromErrorStringWithFormat("Failed to send request: %s",531 error.AsCString());532 533 static const size_t stat_len = strlen(kSTAT);534 static const size_t response_len = stat_len + (sizeof(uint32_t) * 3);535 536 std::vector<char> buffer(response_len);537 error = ReadAllBytes(*m_conn, &buffer[0], buffer.size());538 if (error.Fail())539 return Status::FromErrorStringWithFormat("Failed to read response: %s",540 error.AsCString());541 542 DataExtractor extractor(&buffer[0], buffer.size(), eByteOrderLittle,543 sizeof(void *));544 offset_t offset = 0;545 546 const void *command = extractor.GetData(&offset, stat_len);547 if (!command)548 return Status::FromErrorStringWithFormat("Failed to get response command");549 const char *command_str = static_cast<const char *>(command);550 if (strncmp(command_str, kSTAT, stat_len))551 return Status::FromErrorStringWithFormat("Got invalid stat command: %s",552 command_str);553 554 mode = extractor.GetU32(&offset);555 size = extractor.GetU32(&offset);556 mtime = extractor.GetU32(&offset);557 return Status();558}559 560Status AdbSyncService::PullFile(const FileSpec &remote_file,561 const FileSpec &local_file) {562 return ExecuteCommand([this, &remote_file, &local_file]() {563 return PullFileImpl(remote_file, local_file);564 });565}566 567Status AdbSyncService::PushFile(const FileSpec &local_file,568 const FileSpec &remote_file) {569 return ExecuteCommand([this, &local_file, &remote_file]() {570 return PushFileImpl(local_file, remote_file);571 });572}573 574Status AdbSyncService::Stat(const FileSpec &remote_file, uint32_t &mode,575 uint32_t &size, uint32_t &mtime) {576 return ExecuteCommand([this, &remote_file, &mode, &size, &mtime]() {577 return StatImpl(remote_file, mode, size, mtime);578 });579}580 581bool AdbSyncService::IsConnected() const {582 return m_conn && m_conn->IsConnected();583}584 585AdbSyncService::AdbSyncService(const std::string device_id)586 : m_device_id(device_id) {587 m_conn = std::make_unique<ConnectionFileDescriptor>();588 Log *log = GetLog(LLDBLog::Platform);589 LLDB_LOGF(log,590 "AdbSyncService::AdbSyncService() - Creating AdbSyncService for "591 "device: %s",592 m_device_id.c_str());593}594 595Status AdbSyncService::ExecuteCommand(const std::function<Status()> &cmd) {596 Status error = cmd();597 return error;598}599 600AdbSyncService::~AdbSyncService() {601 Log *log = GetLog(LLDBLog::Platform);602 LLDB_LOGF(log,603 "AdbSyncService::~AdbSyncService() - Destroying AdbSyncService for "604 "device: %s",605 m_device_id.c_str());606}607 608Status AdbSyncService::SendSyncRequest(const char *request_id,609 const uint32_t data_len,610 const void *data) {611 DataEncoder encoder(eByteOrderLittle, sizeof(void *));612 encoder.AppendData(llvm::StringRef(request_id));613 encoder.AppendU32(data_len);614 llvm::ArrayRef<uint8_t> bytes = encoder.GetData();615 Status error;616 ConnectionStatus status;617 m_conn->Write(bytes.data(), kSyncPacketLen, status, &error);618 if (error.Fail())619 return error;620 621 if (data)622 m_conn->Write(data, data_len, status, &error);623 return error;624}625 626Status AdbSyncService::ReadSyncHeader(std::string &response_id,627 uint32_t &data_len) {628 char buffer[kSyncPacketLen];629 630 auto error = ReadAllBytes(*m_conn, buffer, kSyncPacketLen);631 if (error.Success()) {632 response_id.assign(&buffer[0], 4);633 DataExtractor extractor(&buffer[4], 4, eByteOrderLittle, sizeof(void *));634 offset_t offset = 0;635 data_len = extractor.GetU32(&offset);636 }637 638 return error;639}640 641Status AdbSyncService::PullFileChunk(std::vector<char> &buffer, bool &eof) {642 buffer.clear();643 644 std::string response_id;645 uint32_t data_len;646 auto error = ReadSyncHeader(response_id, data_len);647 if (error.Fail())648 return error;649 650 if (response_id == kDATA) {651 buffer.resize(data_len, 0);652 error = ReadAllBytes(*m_conn, &buffer[0], data_len);653 if (error.Fail())654 buffer.clear();655 } else if (response_id == kDONE) {656 eof = true;657 } else if (response_id == kFAIL) {658 std::string error_message(data_len, 0);659 error = ReadAllBytes(*m_conn, &error_message[0], data_len);660 if (error.Fail())661 return Status::FromErrorStringWithFormat(662 "Failed to read pull error message: %s", error.AsCString());663 return Status::FromErrorStringWithFormat("Failed to pull file: %s",664 error_message.c_str());665 } else666 return Status::FromErrorStringWithFormat(667 "Pull failed with unknown response: %s", response_id.c_str());668 669 return Status();670}671 672Status AdbSyncService::SetupSyncConnection() {673 Status error = ConnectToAdb(*m_conn);674 if (error.Fail())675 return error;676 677 error = SelectTargetDevice(*m_conn, m_device_id);678 if (error.Fail())679 return error;680 681 error = EnterSyncMode(*m_conn);682 return error;683}684