diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2016-07-23 20:50:09 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2016-07-23 20:50:09 +0000 |
commit | f3fbd1c0586ff6ec7895991e6c28f61a503c36a8 (patch) | |
tree | 48d008fd3df8c0e73271a4b18474e0aac6dbfe33 /source/Plugins/Platform/Android | |
parent | 2fc5d2d1dfaf623ce4e24cd8590565902f8c557c (diff) |
Notes
Diffstat (limited to 'source/Plugins/Platform/Android')
7 files changed, 396 insertions, 197 deletions
diff --git a/source/Plugins/Platform/Android/AdbClient.cpp b/source/Plugins/Platform/Android/AdbClient.cpp index 736447fd22d2..1b07ddba59fc 100644 --- a/source/Plugins/Platform/Android/AdbClient.cpp +++ b/source/Plugins/Platform/Android/AdbClient.cpp @@ -8,33 +8,41 @@ //===----------------------------------------------------------------------===// // Other libraries and framework includes +#include "AdbClient.h" + +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Support/FileUtilities.h" + #include "lldb/Core/DataBuffer.h" #include "lldb/Core/DataBufferHeap.h" #include "lldb/Core/DataEncoder.h" #include "lldb/Core/DataExtractor.h" #include "lldb/Core/StreamString.h" +#include "lldb/Host/ConnectionFileDescriptor.h" #include "lldb/Host/FileSpec.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/Support/FileUtilities.h" - -// Project includes -#include "AdbClient.h" #include <limits.h> #include <algorithm> +#include <cstdlib> #include <fstream> #include <sstream> +// On Windows, transitive dependencies pull in <Windows.h>, which defines a +// macro that clashes with a method name. +#ifdef SendMessage +#undef SendMessage +#endif + using namespace lldb; using namespace lldb_private; using namespace lldb_private::platform_android; namespace { -const uint32_t kReadTimeout = 1000000; // 1 second +const std::chrono::seconds kReadTimeout(8); const char * kOKAY = "OKAY"; const char * kFAIL = "FAIL"; const char * kDATA = "DATA"; @@ -53,6 +61,35 @@ const uint32_t kDefaultMode = 0100770; // S_IFREG | S_IRWXU | S_IRWXG const char * kSocketNamespaceAbstract = "localabstract"; const char * kSocketNamespaceFileSystem = "localfilesystem"; +Error +ReadAllBytes (Connection &conn, void *buffer, size_t size) +{ + using namespace std::chrono; + + Error error; + ConnectionStatus status; + char *read_buffer = static_cast<char*>(buffer); + + auto now = steady_clock::now(); + const auto deadline = now + kReadTimeout; + size_t total_read_bytes = 0; + while (total_read_bytes < size && now < deadline) + { + uint32_t timeout_usec = duration_cast<microseconds>(deadline - now).count(); + auto read_bytes = + conn.Read(read_buffer + total_read_bytes, size - total_read_bytes, timeout_usec, status, &error); + if (error.Fail ()) + return error; + total_read_bytes += read_bytes; + if (status != eConnectionStatusSuccess) + break; + now = steady_clock::now(); + } + if (total_read_bytes < size) + error = Error("Unable to read requested number of bytes. Connection status: %d.", status); + return error; +} + } // namespace Error @@ -63,30 +100,39 @@ AdbClient::CreateByDeviceID(const std::string &device_id, AdbClient &adb) if (error.Fail()) return error; - if (device_id.empty()) + std::string android_serial; + if (!device_id.empty()) + android_serial = device_id; + else if (const char *env_serial = std::getenv("ANDROID_SERIAL")) + android_serial = env_serial; + + if (android_serial.empty()) { if (connect_devices.size() != 1) - return Error("Expected a single connected device, got instead %" PRIu64, - static_cast<uint64_t>(connect_devices.size())); - + return Error("Expected a single connected device, got instead %zu - try setting 'ANDROID_SERIAL'", + connect_devices.size()); adb.SetDeviceID(connect_devices.front()); } else { - auto find_it = std::find(connect_devices.begin(), connect_devices.end(), device_id); + auto find_it = std::find(connect_devices.begin(), connect_devices.end(), android_serial); if (find_it == connect_devices.end()) - return Error("Device \"%s\" not found", device_id.c_str()); + return Error("Device \"%s\" not found", android_serial.c_str()); adb.SetDeviceID(*find_it); } return error; } +AdbClient::AdbClient () {} + AdbClient::AdbClient (const std::string &device_id) : m_device_id (device_id) { } +AdbClient::~AdbClient() {} + void AdbClient::SetDeviceID (const std::string &device_id) { @@ -103,7 +149,8 @@ Error AdbClient::Connect () { Error error; - m_conn.Connect ("connect://localhost:5037", &error); + m_conn.reset (new ConnectionFileDescriptor); + m_conn->Connect ("connect://localhost:5037", &error); return error; } @@ -131,6 +178,9 @@ AdbClient::GetDevices (DeviceIDList &device_list) for (const auto device: devices) device_list.push_back (device.split ('\t').first); + // Force disconnect since ADB closes connection after host:devices + // response is sent. + m_conn.reset (); return error; } @@ -184,7 +234,7 @@ Error AdbClient::SendMessage (const std::string &packet, const bool reconnect) { Error error; - if (reconnect) + if (!m_conn || reconnect) { error = Connect (); if (error.Fail ()) @@ -196,11 +246,11 @@ AdbClient::SendMessage (const std::string &packet, const bool reconnect) ConnectionStatus status; - m_conn.Write (length_buffer, 4, status, &error); + m_conn->Write (length_buffer, 4, status, &error); if (error.Fail ()) return error; - m_conn.Write (packet.c_str (), packet.size (), status, &error); + m_conn->Write (packet.c_str (), packet.size (), status, &error); return error; } @@ -251,7 +301,7 @@ AdbClient::ReadMessageStream (std::vector<char>& message, uint32_t timeout_ms) if (elapsed_time >= timeout_ms) return Error("Timed out"); - size_t n = m_conn.Read(buffer, sizeof(buffer), 1000 * (timeout_ms - elapsed_time), status, &error); + size_t n = m_conn->Read(buffer, sizeof(buffer), 1000 * (timeout_ms - elapsed_time), status, &error); if (n > 0) message.insert(message.end(), &buffer[0], &buffer[n]); } @@ -304,12 +354,118 @@ AdbClient::SwitchDeviceTransport () } Error -AdbClient::PullFile (const FileSpec &remote_file, const FileSpec &local_file) +AdbClient::StartSync () +{ + auto error = SwitchDeviceTransport (); + if (error.Fail ()) + return Error ("Failed to switch to device transport: %s", error.AsCString ()); + + error = Sync (); + if (error.Fail ()) + return Error ("Sync failed: %s", error.AsCString ()); + + return error; +} + +Error +AdbClient::Sync () { - auto error = StartSync (); + auto error = SendMessage ("sync:", false); if (error.Fail ()) return error; + return ReadResponseStatus (); +} + +Error +AdbClient::ReadAllBytes (void *buffer, size_t size) +{ + return ::ReadAllBytes (*m_conn, buffer, size); +} + +Error +AdbClient::internalShell(const char *command, uint32_t timeout_ms, std::vector<char> &output_buf) +{ + output_buf.clear(); + + auto error = SwitchDeviceTransport(); + if (error.Fail()) + return Error("Failed to switch to device transport: %s", error.AsCString()); + + StreamString adb_command; + adb_command.Printf("shell:%s", command); + error = SendMessage(adb_command.GetData(), false); + if (error.Fail()) + return error; + + error = ReadResponseStatus(); + if (error.Fail()) + return error; + + error = ReadMessageStream(output_buf, timeout_ms); + if (error.Fail()) + return error; + + // ADB doesn't propagate return code of shell execution - if + // output starts with /system/bin/sh: most likely command failed. + static const char *kShellPrefix = "/system/bin/sh:"; + if (output_buf.size() > strlen(kShellPrefix)) + { + if (!memcmp(&output_buf[0], kShellPrefix, strlen(kShellPrefix))) + return Error("Shell command %s failed: %s", command, + std::string(output_buf.begin(), output_buf.end()).c_str()); + } + + return Error(); +} + +Error +AdbClient::Shell(const char *command, uint32_t timeout_ms, std::string *output) +{ + std::vector<char> output_buffer; + auto error = internalShell(command, timeout_ms, output_buffer); + if (error.Fail()) + return error; + + if (output) + output->assign(output_buffer.begin(), output_buffer.end()); + return error; +} + +Error +AdbClient::ShellToFile(const char *command, uint32_t timeout_ms, const FileSpec &output_file_spec) +{ + std::vector<char> output_buffer; + auto error = internalShell(command, timeout_ms, output_buffer); + if (error.Fail()) + return error; + + const auto output_filename = output_file_spec.GetPath(); + std::ofstream dst(output_filename, std::ios::out | std::ios::binary); + if (!dst.is_open()) + return Error("Unable to open local file %s", output_filename.c_str()); + + dst.write(&output_buffer[0], output_buffer.size()); + dst.close(); + if (!dst) + return Error("Failed to write file %s", output_filename.c_str()); + return Error(); +} + +std::unique_ptr<AdbClient::SyncService> +AdbClient::GetSyncService (Error &error) +{ + std::unique_ptr<SyncService> sync_service; + error = StartSync (); + if (error.Success ()) + sync_service.reset (new SyncService(std::move(m_conn))); + + return sync_service; +} + +Error +AdbClient::SyncService::internalPullFile (const FileSpec &remote_file, const FileSpec &local_file) +{ const auto local_file_path = local_file.GetPath (); llvm::FileRemover local_file_remover (local_file_path.c_str ()); @@ -318,7 +474,7 @@ AdbClient::PullFile (const FileSpec &remote_file, const FileSpec &local_file) return Error ("Unable to open local file %s", local_file_path.c_str()); const auto remote_file_path = remote_file.GetPath (false); - error = SendSyncRequest (kRECV, remote_file_path.length (), remote_file_path.c_str ()); + auto error = SendSyncRequest (kRECV, remote_file_path.length (), remote_file_path.c_str ()); if (error.Fail ()) return error; @@ -338,12 +494,8 @@ AdbClient::PullFile (const FileSpec &remote_file, const FileSpec &local_file) } Error -AdbClient::PushFile (const FileSpec &local_file, const FileSpec &remote_file) +AdbClient::SyncService::internalPushFile (const FileSpec &local_file, const FileSpec &remote_file) { - auto error = StartSync (); - if (error.Fail ()) - return error; - const auto local_file_path (local_file.GetPath ()); std::ifstream src (local_file_path.c_str(), std::ios::in | std::ios::binary); if (!src.is_open ()) @@ -352,7 +504,7 @@ AdbClient::PushFile (const FileSpec &local_file, const FileSpec &remote_file) std::stringstream file_description; file_description << remote_file.GetPath(false).c_str() << "," << kDefaultMode; std::string file_description_str = file_description.str(); - error = SendSyncRequest (kSEND, file_description_str.length(), file_description_str.c_str()); + auto error = SendSyncRequest (kSEND, file_description_str.length(), file_description_str.c_str()); if (error.Fail ()) return error; @@ -392,67 +544,89 @@ AdbClient::PushFile (const FileSpec &local_file, const FileSpec &remote_file) } Error -AdbClient::StartSync () +AdbClient::SyncService::internalStat (const FileSpec &remote_file, uint32_t &mode, uint32_t &size, uint32_t &mtime) { - auto error = SwitchDeviceTransport (); + const std::string remote_file_path (remote_file.GetPath (false)); + auto error = SendSyncRequest (kSTAT, remote_file_path.length (), remote_file_path.c_str ()); if (error.Fail ()) - return Error ("Failed to switch to device transport: %s", error.AsCString ()); + return Error ("Failed to send request: %s", error.AsCString ()); - error = Sync (); + static const size_t stat_len = strlen (kSTAT); + static const size_t response_len = stat_len + (sizeof (uint32_t) * 3); + + std::vector<char> buffer (response_len); + error = ReadAllBytes (&buffer[0], buffer.size ()); if (error.Fail ()) - return Error ("Sync failed: %s", error.AsCString ()); + return Error ("Failed to read response: %s", error.AsCString ()); - return error; + DataExtractor extractor (&buffer[0], buffer.size (), eByteOrderLittle, sizeof (void*)); + offset_t offset = 0; + + const void* command = extractor.GetData (&offset, stat_len); + if (!command) + return Error ("Failed to get response command"); + const char* command_str = static_cast<const char*> (command); + if (strncmp (command_str, kSTAT, stat_len)) + return Error ("Got invalid stat command: %s", command_str); + + mode = extractor.GetU32 (&offset); + size = extractor.GetU32 (&offset); + mtime = extractor.GetU32 (&offset); + return Error (); } Error -AdbClient::Sync () +AdbClient::SyncService::PullFile (const FileSpec &remote_file, const FileSpec &local_file) { - auto error = SendMessage ("sync:", false); - if (error.Fail ()) - return error; + return executeCommand ([this, &remote_file, &local_file]() { + return internalPullFile (remote_file, local_file); + }); +} - return ReadResponseStatus (); +Error +AdbClient::SyncService::PushFile (const FileSpec &local_file, const FileSpec &remote_file) +{ + return executeCommand ([this, &local_file, &remote_file]() { + return internalPushFile (local_file, remote_file); + }); } Error -AdbClient::PullFileChunk (std::vector<char> &buffer, bool &eof) +AdbClient::SyncService::Stat (const FileSpec &remote_file, uint32_t &mode, uint32_t &size, uint32_t &mtime) { - buffer.clear (); + return executeCommand ([this, &remote_file, &mode, &size, &mtime]() { + return internalStat (remote_file, mode, size, mtime); + }); +} - std::string response_id; - uint32_t data_len; - auto error = ReadSyncHeader (response_id, data_len); - if (error.Fail ()) - return error; +bool +AdbClient::SyncService::IsConnected () const +{ + return m_conn && m_conn->IsConnected (); +} - if (response_id == kDATA) - { - buffer.resize (data_len, 0); - error = ReadAllBytes (&buffer[0], data_len); - if (error.Fail ()) - buffer.clear (); - } - else if (response_id == kDONE) - { - eof = true; - } - else if (response_id == kFAIL) - { - std::string error_message (data_len, 0); - error = ReadAllBytes (&error_message[0], data_len); - if (error.Fail ()) - return Error ("Failed to read pull error message: %s", error.AsCString ()); - return Error ("Failed to pull file: %s", error_message.c_str ()); - } - else - return Error ("Pull failed with unknown response: %s", response_id.c_str ()); +AdbClient::SyncService::SyncService(std::unique_ptr<Connection> &&conn): +m_conn(std::move(conn)) +{ +} - return Error (); +Error +AdbClient::SyncService::executeCommand (const std::function<Error()> &cmd) +{ + if (!m_conn) + return Error ("SyncService is disconnected"); + + const auto error = cmd (); + if (error.Fail ()) + m_conn.reset (); + + return error; } +AdbClient::SyncService::~SyncService () {} + Error -AdbClient::SendSyncRequest (const char *request_id, const uint32_t data_len, const void *data) +AdbClient::SyncService::SendSyncRequest (const char *request_id, const uint32_t data_len, const void *data) { const DataBufferSP data_sp (new DataBufferHeap (kSyncPacketLen, 0)); DataEncoder encoder (data_sp, eByteOrderLittle, sizeof (void*)); @@ -461,17 +635,17 @@ AdbClient::SendSyncRequest (const char *request_id, const uint32_t data_len, con Error error; ConnectionStatus status; - m_conn.Write (data_sp->GetBytes (), kSyncPacketLen, status, &error); + m_conn->Write (data_sp->GetBytes (), kSyncPacketLen, status, &error); if (error.Fail ()) return error; if (data) - m_conn.Write (data, data_len, status, &error); + m_conn->Write (data, data_len, status, &error); return error; } Error -AdbClient::ReadSyncHeader (std::string &response_id, uint32_t &data_len) +AdbClient::SyncService::ReadSyncHeader (std::string &response_id, uint32_t &data_len) { char buffer[kSyncPacketLen]; @@ -488,82 +662,44 @@ AdbClient::ReadSyncHeader (std::string &response_id, uint32_t &data_len) } Error -AdbClient::ReadAllBytes (void *buffer, size_t size) +AdbClient::SyncService::PullFileChunk (std::vector<char> &buffer, bool &eof) { - Error error; - ConnectionStatus status; - char *read_buffer = static_cast<char*>(buffer); - - size_t tota_read_bytes = 0; - while (tota_read_bytes < size) - { - auto read_bytes = m_conn.Read (read_buffer + tota_read_bytes, size - tota_read_bytes, kReadTimeout, status, &error); - if (error.Fail ()) - return error; - tota_read_bytes += read_bytes; - } - return error; -} + buffer.clear (); -Error -AdbClient::Stat (const FileSpec &remote_file, uint32_t &mode, uint32_t &size, uint32_t &mtime) -{ - auto error = StartSync (); + std::string response_id; + uint32_t data_len; + auto error = ReadSyncHeader (response_id, data_len); if (error.Fail ()) return error; - const std::string remote_file_path (remote_file.GetPath (false)); - error = SendSyncRequest (kSTAT, remote_file_path.length (), remote_file_path.c_str ()); - if (error.Fail ()) - return Error ("Failed to send request: %s", error.AsCString ()); - - static const size_t stat_len = strlen (kSTAT); - static const size_t response_len = stat_len + (sizeof (uint32_t) * 3); - - std::vector<char> buffer (response_len); - error = ReadAllBytes (&buffer[0], buffer.size ()); - if (error.Fail ()) - return Error ("Failed to read response: %s", error.AsCString ()); - - DataExtractor extractor (&buffer[0], buffer.size (), eByteOrderLittle, sizeof (void*)); - offset_t offset = 0; - - const void* command = extractor.GetData (&offset, stat_len); - if (!command) - return Error ("Failed to get response command"); - const char* command_str = static_cast<const char*> (command); - if (strncmp (command_str, kSTAT, stat_len)) - return Error ("Got invalid stat command: %s", command_str); + if (response_id == kDATA) + { + buffer.resize (data_len, 0); + error = ReadAllBytes (&buffer[0], data_len); + if (error.Fail ()) + buffer.clear (); + } + else if (response_id == kDONE) + { + eof = true; + } + else if (response_id == kFAIL) + { + std::string error_message (data_len, 0); + error = ReadAllBytes (&error_message[0], data_len); + if (error.Fail ()) + return Error ("Failed to read pull error message: %s", error.AsCString ()); + return Error ("Failed to pull file: %s", error_message.c_str ()); + } + else + return Error ("Pull failed with unknown response: %s", response_id.c_str ()); - mode = extractor.GetU32 (&offset); - size = extractor.GetU32 (&offset); - mtime = extractor.GetU32 (&offset); return Error (); } Error -AdbClient::Shell (const char* command, uint32_t timeout_ms, std::string* output) +AdbClient::SyncService::ReadAllBytes (void *buffer, size_t size) { - auto error = SwitchDeviceTransport (); - if (error.Fail ()) - return Error ("Failed to switch to device transport: %s", error.AsCString ()); - - StreamString adb_command; - adb_command.Printf("shell:%s", command); - error = SendMessage (adb_command.GetData(), false); - if (error.Fail ()) - return error; - - error = ReadResponseStatus (); - if (error.Fail ()) - return error; - - std::vector<char> in_buffer; - error = ReadMessageStream (in_buffer, timeout_ms); - if (error.Fail()) - return error; - - if (output) - output->assign(in_buffer.begin(), in_buffer.end()); - return error; + return ::ReadAllBytes (*m_conn, buffer, size); } + diff --git a/source/Plugins/Platform/Android/AdbClient.h b/source/Plugins/Platform/Android/AdbClient.h index 4ec411d1411d..37973bbdccf8 100644 --- a/source/Plugins/Platform/Android/AdbClient.h +++ b/source/Plugins/Platform/Android/AdbClient.h @@ -14,7 +14,9 @@ // C++ Includes +#include <functional> #include <list> +#include <memory> #include <string> #include <vector> @@ -22,7 +24,6 @@ // Project includes #include "lldb/Core/Error.h" -#include "lldb/Host/ConnectionFileDescriptor.h" namespace lldb_private { @@ -41,12 +42,63 @@ public: using DeviceIDList = std::list<std::string>; + class SyncService + { + friend class AdbClient; + + public: + ~SyncService (); + + Error + PullFile (const FileSpec &remote_file, const FileSpec &local_file); + + Error + PushFile (const FileSpec &local_file, const FileSpec &remote_file); + + Error + Stat (const FileSpec &remote_file, uint32_t &mode, uint32_t &size, uint32_t &mtime); + + bool + IsConnected () const; + + private: + explicit SyncService (std::unique_ptr<Connection> &&conn); + + Error + SendSyncRequest (const char *request_id, const uint32_t data_len, const void *data); + + Error + ReadSyncHeader (std::string &response_id, uint32_t &data_len); + + Error + PullFileChunk (std::vector<char> &buffer, bool &eof); + + Error + ReadAllBytes (void *buffer, size_t size); + + Error + internalPullFile (const FileSpec &remote_file, const FileSpec &local_file); + + Error + internalPushFile (const FileSpec &local_file, const FileSpec &remote_file); + + Error + internalStat (const FileSpec &remote_file, uint32_t &mode, uint32_t &size, uint32_t &mtime); + + Error + executeCommand (const std::function<Error()> &cmd); + + std::unique_ptr<Connection> m_conn; + }; + static Error CreateByDeviceID(const std::string &device_id, AdbClient &adb); - AdbClient () = default; + AdbClient (); explicit AdbClient (const std::string &device_id); + ~AdbClient(); + const std::string& GetDeviceID() const; @@ -65,16 +117,16 @@ public: DeletePortForwarding (const uint16_t local_port); Error - PullFile (const FileSpec &remote_file, const FileSpec &local_file); + Shell (const char* command, uint32_t timeout_ms, std::string* output); Error - PushFile (const FileSpec &local_file, const FileSpec &remote_file); + ShellToFile(const char *command, uint32_t timeout_ms, const FileSpec &output_file_spec); - Error - Stat (const FileSpec &remote_file, uint32_t &mode, uint32_t &size, uint32_t &mtime); + std::unique_ptr<SyncService> + GetSyncService (Error &error); Error - Shell (const char* command, uint32_t timeout_ms, std::string* output); + SwitchDeviceTransport (); private: Error @@ -90,12 +142,6 @@ private: SendDeviceMessage (const std::string &packet); Error - SendSyncRequest (const char *request_id, const uint32_t data_len, const void *data); - - Error - ReadSyncHeader (std::string &response_id, uint32_t &data_len); - - Error ReadMessage (std::vector<char> &message); Error @@ -108,25 +154,23 @@ private: ReadResponseStatus (); Error - SwitchDeviceTransport (); - - Error Sync (); Error StartSync (); Error - PullFileChunk (std::vector<char> &buffer, bool &eof); + internalShell(const char *command, uint32_t timeout_ms, std::vector<char> &output_buf); Error - ReadAllBytes (void *buffer, size_t size); + ReadAllBytes(void *buffer, size_t size); std::string m_device_id; - ConnectionFileDescriptor m_conn; + std::unique_ptr<Connection> m_conn; }; } // namespace platform_android } // namespace lldb_private #endif // liblldb_AdbClient_h_ + diff --git a/source/Plugins/Platform/Android/Makefile b/source/Plugins/Platform/Android/Makefile deleted file mode 100644 index aa186f924e66..000000000000 --- a/source/Plugins/Platform/Android/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -##===- source/Plugins/Platform/Android/Makefile ------------*- Makefile -*-===## -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open Source -# License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## - -LLDB_LEVEL := ../../../.. -LIBRARYNAME := lldbPluginPlatformAndroid -BUILD_ARCHIVE = 1 - -include $(LLDB_LEVEL)/Makefile diff --git a/source/Plugins/Platform/Android/PlatformAndroid.cpp b/source/Plugins/Platform/Android/PlatformAndroid.cpp index e842884c046a..381795171d36 100644 --- a/source/Plugins/Platform/Android/PlatformAndroid.cpp +++ b/source/Plugins/Platform/Android/PlatformAndroid.cpp @@ -225,8 +225,36 @@ PlatformAndroid::GetFile (const FileSpec& source, if (source_spec.IsRelative()) source_spec = GetRemoteWorkingDirectory ().CopyByAppendingPathComponent (source_spec.GetCString (false)); - AdbClient adb (m_device_id); - return adb.PullFile (source_spec, destination); + Error error; + auto sync_service = GetSyncService (error); + if (error.Fail ()) + return error; + + uint32_t mode = 0, size = 0, mtime = 0; + error = sync_service->Stat(source_spec, mode, size, mtime); + if (error.Fail()) + return error; + + if (mode != 0) + return sync_service->PullFile(source_spec, destination); + + auto source_file = source_spec.GetCString(false); + + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); + if (log) + log->Printf("Got mode == 0 on '%s': try to get file via 'shell cat'", source_file); + + if (strchr(source_file, '\'') != nullptr) + return Error("Doesn't support single-quotes in filenames"); + + // mode == 0 can signify that adbd cannot access the file + // due security constraints - try "cat ..." as a fallback. + AdbClient adb(m_device_id); + + char cmd[PATH_MAX]; + snprintf(cmd, sizeof(cmd), "cat '%s'", source_file); + + return adb.ShellToFile(cmd, 60000 /* ms */, destination); } Error @@ -242,9 +270,12 @@ PlatformAndroid::PutFile (const FileSpec& source, if (destination_spec.IsRelative()) destination_spec = GetRemoteWorkingDirectory ().CopyByAppendingPathComponent (destination_spec.GetCString (false)); - AdbClient adb (m_device_id); // TODO: Set correct uid and gid on remote file. - return adb.PushFile(source, destination_spec); + Error error; + auto sync_service = GetSyncService (error); + if (error.Fail ()) + return error; + return sync_service->PushFile(source, destination_spec); } const char * @@ -315,8 +346,9 @@ PlatformAndroid::DownloadSymbolFile (const lldb::ModuleSP& module_sp, const FileSpec& dst_file_spec) { // For oat file we can try to fetch additional debug info from the device - if (module_sp->GetFileSpec().GetFileNameExtension() != ConstString("oat")) - return Error("Symbol file downloading only supported for oat files"); + ConstString extension = module_sp->GetFileSpec().GetFileNameExtension(); + if (extension != ConstString("oat") && extension != ConstString("odex")) + return Error("Symbol file downloading only supported for oat and odex files"); // If we have no information about the platform file we can't execute oatdump if (!module_sp->GetPlatformFileSpec()) @@ -331,7 +363,6 @@ PlatformAndroid::DownloadSymbolFile (const lldb::ModuleSP& module_sp, return Error("Symtab already available in the module"); AdbClient adb(m_device_id); - std::string tmpdir; Error error = adb.Shell("mktemp --directory --tmpdir /data/local/tmp", 5000 /* ms */, &tmpdir); if (error.Fail() || tmpdir.empty()) @@ -387,3 +418,15 @@ PlatformAndroid::GetLibdlFunctionDeclarations() const extern "C" char* dlerror(void) asm("__dl_dlerror"); )"; } + +AdbClient::SyncService* +PlatformAndroid::GetSyncService (Error &error) +{ + if (m_adb_sync_svc && m_adb_sync_svc->IsConnected ()) + return m_adb_sync_svc.get (); + + AdbClient adb (m_device_id); + m_adb_sync_svc = adb.GetSyncService (error); + return (error.Success ()) ? m_adb_sync_svc.get () : nullptr; +} + diff --git a/source/Plugins/Platform/Android/PlatformAndroid.h b/source/Plugins/Platform/Android/PlatformAndroid.h index 119d0a0bdf04..6f7a87ca9fef 100644 --- a/source/Plugins/Platform/Android/PlatformAndroid.h +++ b/source/Plugins/Platform/Android/PlatformAndroid.h @@ -12,12 +12,15 @@ // C Includes // C++ Includes +#include <memory> #include <string> // Other libraries and framework includes // Project includes #include "Plugins/Platform/Linux/PlatformLinux.h" +#include "AdbClient.h" + namespace lldb_private { namespace platform_android { @@ -102,6 +105,9 @@ namespace platform_android { GetLibdlFunctionDeclarations() const override; private: + AdbClient::SyncService* GetSyncService (Error &error); + + std::unique_ptr<AdbClient::SyncService> m_adb_sync_svc; std::string m_device_id; uint32_t m_sdk_version; diff --git a/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp b/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp index 3d91dd6b7a32..f11f2874e356 100644 --- a/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp +++ b/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp @@ -11,6 +11,8 @@ #include "lldb/Core/Error.h" #include "lldb/Core/Log.h" #include "lldb/Host/common/TCPSocket.h" +#include "lldb/Host/ConnectionFileDescriptor.h" + #include "PlatformAndroidRemoteGDBServer.h" #include "Utility/UriParser.h" @@ -258,18 +260,3 @@ PlatformAndroidRemoteGDBServer::ConnectProcess(const char* connect_url, target, error); } - -size_t -PlatformAndroidRemoteGDBServer::ConnectToWaitingProcesses(Debugger& debugger, Error& error) -{ - std::vector<std::string> connection_urls; - GetPendingGdbServerList(connection_urls); - - for (size_t i = 0; i < connection_urls.size(); ++i) - { - ConnectProcess(connection_urls[i].c_str(), nullptr, debugger, nullptr, error); - if (error.Fail()) - return i; // We already connected to i process succsessfully - } - return connection_urls.size(); -} diff --git a/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.h b/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.h index 3d2653812ded..79e273c665eb 100644 --- a/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.h +++ b/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.h @@ -46,9 +46,6 @@ public: lldb_private::Target *target, lldb_private::Error &error) override; - size_t - ConnectToWaitingProcesses(lldb_private::Debugger& debugger, lldb_private::Error& error) override; - protected: std::string m_device_id; std::map<lldb::pid_t, uint16_t> m_port_forwards; |