| //===-- AdbClient.cpp -------------------------------------------*- C++ -*-===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| // Other libraries and framework includes |
| #include "llvm/ADT/SmallVector.h" |
| #include "llvm/ADT/StringRef.h" |
| #include "llvm/ADT/STLExtras.h" |
| |
| // Project includes |
| #include "AdbClient.h" |
| |
| #include <algorithm> |
| #include <sstream> |
| |
| using namespace lldb; |
| using namespace lldb_private; |
| using namespace lldb_private::platform_android; |
| |
| namespace { |
| |
| const uint32_t kConnTimeout = 10000; // 10 ms |
| const char * kOKAY = "OKAY"; |
| const char * kFAIL = "FAIL"; |
| |
| } // namespace |
| |
| Error |
| AdbClient::CreateByDeviceID(const std::string &device_id, AdbClient &adb) |
| { |
| DeviceIDList connect_devices; |
| auto error = adb.GetDevices(connect_devices); |
| if (error.Fail()) |
| return error; |
| |
| if (device_id.empty()) |
| { |
| if (connect_devices.size() != 1) |
| return Error("Expected a single connected device, got instead %" PRIu64, |
| static_cast<uint64_t>(connect_devices.size())); |
| |
| adb.SetDeviceID(connect_devices.front()); |
| } |
| else |
| { |
| auto find_it = std::find(connect_devices.begin(), connect_devices.end(), device_id); |
| if (find_it == connect_devices.end()) |
| return Error("Device \"%s\" not found", device_id.c_str()); |
| |
| adb.SetDeviceID(*find_it); |
| } |
| return error; |
| } |
| |
| AdbClient::AdbClient (const std::string &device_id) |
| : m_device_id (device_id) |
| { |
| } |
| |
| void |
| AdbClient::SetDeviceID (const std::string& device_id) |
| { |
| m_device_id = device_id; |
| } |
| |
| const std::string& |
| AdbClient::GetDeviceID() const |
| { |
| return m_device_id; |
| } |
| |
| Error |
| AdbClient::Connect () |
| { |
| Error error; |
| m_conn.Connect ("connect://localhost:5037", &error); |
| |
| return error; |
| } |
| |
| Error |
| AdbClient::GetDevices (DeviceIDList &device_list) |
| { |
| device_list.clear (); |
| |
| auto error = SendMessage ("host:devices"); |
| if (error.Fail ()) |
| return error; |
| |
| error = ReadResponseStatus (); |
| if (error.Fail ()) |
| return error; |
| |
| std::string in_buffer; |
| error = ReadMessage (in_buffer); |
| |
| llvm::StringRef response (in_buffer); |
| llvm::SmallVector<llvm::StringRef, 4> devices; |
| response.split (devices, "\n", -1, false); |
| |
| for (const auto device: devices) |
| device_list.push_back (device.split ('\t').first); |
| |
| return error; |
| } |
| |
| Error |
| AdbClient::SetPortForwarding (const uint16_t port) |
| { |
| char message[48]; |
| snprintf (message, sizeof (message), "forward:tcp:%d;tcp:%d", port, port); |
| |
| const auto error = SendDeviceMessage (message); |
| if (error.Fail ()) |
| return error; |
| |
| return ReadResponseStatus (); |
| } |
| |
| Error |
| AdbClient::DeletePortForwarding (const uint16_t port) |
| { |
| char message[32]; |
| snprintf (message, sizeof (message), "killforward:tcp:%d", port); |
| |
| const auto error = SendDeviceMessage (message); |
| if (error.Fail ()) |
| return error; |
| |
| return ReadResponseStatus (); |
| } |
| |
| Error |
| AdbClient::SendMessage (const std::string &packet) |
| { |
| auto error = Connect (); |
| if (error.Fail ()) |
| return error; |
| |
| char length_buffer[5]; |
| snprintf (length_buffer, sizeof (length_buffer), "%04x", static_cast<int>(packet.size ())); |
| |
| ConnectionStatus status; |
| |
| m_conn.Write (length_buffer, 4, status, &error); |
| if (error.Fail ()) |
| return error; |
| |
| m_conn.Write (packet.c_str (), packet.size (), status, &error); |
| return error; |
| } |
| |
| Error |
| AdbClient::SendDeviceMessage (const std::string &packet) |
| { |
| std::ostringstream msg; |
| msg << "host-serial:" << m_device_id << ":" << packet; |
| return SendMessage (msg.str ()); |
| } |
| |
| Error |
| AdbClient::ReadMessage (std::string &message) |
| { |
| message.clear (); |
| |
| char buffer[5]; |
| buffer[4] = 0; |
| |
| Error error; |
| ConnectionStatus status; |
| |
| m_conn.Read (buffer, 4, kConnTimeout, status, &error); |
| if (error.Fail ()) |
| return error; |
| |
| int packet_len = 0; |
| sscanf (buffer, "%x", &packet_len); |
| std::string result (packet_len, 0); |
| m_conn.Read (&result[0], packet_len, kConnTimeout, status, &error); |
| if (error.Success ()) |
| result.swap (message); |
| |
| return error; |
| } |
| |
| Error |
| AdbClient::ReadResponseStatus() |
| { |
| char buffer[5]; |
| |
| static const size_t packet_len = 4; |
| buffer[packet_len] = 0; |
| |
| Error error; |
| ConnectionStatus status; |
| |
| m_conn.Read (buffer, packet_len, kConnTimeout, status, &error); |
| if (error.Fail ()) |
| return error; |
| |
| if (strncmp (buffer, kOKAY, packet_len) != 0) |
| { |
| if (strncmp (buffer, kFAIL, packet_len) == 0) |
| { |
| std::string error_message; |
| error = ReadMessage (error_message); |
| if (error.Fail ()) |
| return error; |
| error.SetErrorString (error_message.c_str ()); |
| } |
| else |
| error.SetErrorStringWithFormat ("\"%s\" expected from adb, received: \"%s\"", kOKAY, buffer); |
| } |
| |
| return error; |
| } |