Index: source/Plugins/Platform/Android/AdbClient.h =================================================================== --- source/Plugins/Platform/Android/AdbClient.h +++ source/Plugins/Platform/Android/AdbClient.h @@ -15,6 +15,7 @@ // C++ Includes #include +#include #include #include @@ -22,7 +23,6 @@ // Project includes #include "lldb/Core/Error.h" -#include "lldb/Host/ConnectionFileDescriptor.h" namespace lldb_private { @@ -41,12 +41,49 @@ using DeviceIDList = std::list; + 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); + + private: + explicit SyncService (std::unique_ptr &&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 &buffer, bool &eof); + + Error + ReadAllBytes (void *buffer, size_t size); + + + const std::unique_ptr 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 +102,13 @@ DeletePortForwarding (const uint16_t local_port); Error - PullFile (const FileSpec &remote_file, const FileSpec &local_file); - - Error - PushFile (const FileSpec &local_file, const FileSpec &remote_file); + Shell (const char* command, uint32_t timeout_ms, std::string* output); - Error - Stat (const FileSpec &remote_file, uint32_t &mode, uint32_t &size, uint32_t &mtime); + std::unique_ptr + GetSyncService (Error &error); Error - Shell (const char* command, uint32_t timeout_ms, std::string* output); + SwitchDeviceTransport (); private: Error @@ -84,18 +118,12 @@ SetDeviceID (const std::string &device_id); Error - SendMessage (const std::string &packet, const bool reconnect = true); + SendMessage (const std::string &packet); Error 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 &message); Error @@ -108,25 +136,20 @@ ReadResponseStatus (); Error - SwitchDeviceTransport (); - - Error Sync (); Error StartSync (); Error - PullFileChunk (std::vector &buffer, bool &eof); - - Error ReadAllBytes (void *buffer, size_t size); std::string m_device_id; - ConnectionFileDescriptor m_conn; + std::unique_ptr m_conn; }; } // namespace platform_android } // namespace lldb_private #endif // liblldb_AdbClient_h_ + Index: source/Plugins/Platform/Android/AdbClient.cpp =================================================================== --- source/Plugins/Platform/Android/AdbClient.cpp +++ source/Plugins/Platform/Android/AdbClient.cpp @@ -8,19 +8,20 @@ //===----------------------------------------------------------------------===// // 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 @@ -53,6 +54,35 @@ 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(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(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 @@ -82,11 +112,15 @@ 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 +137,8 @@ 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 +166,9 @@ 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; } @@ -181,10 +219,10 @@ } Error -AdbClient::SendMessage (const std::string &packet, const bool reconnect) +AdbClient::SendMessage (const std::string &packet) { Error error; - if (reconnect) + if (!m_conn || !m_conn->IsConnected()) { error = Connect (); if (error.Fail ()) @@ -196,11 +234,11 @@ 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 +289,7 @@ 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 +342,72 @@ } 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 = SendMessage ("sync:"); + if (error.Fail ()) + return error; + + return ReadResponseStatus (); +} + +Error +AdbClient::ReadAllBytes (void *buffer, size_t size) { - auto error = StartSync (); + return ::ReadAllBytes (*m_conn, buffer, size); +} + +Error +AdbClient::Shell (const char* command, uint32_t timeout_ms, std::string* output) +{ + StreamString adb_command; + adb_command.Printf("shell:%s", command); + auto error = SendMessage (adb_command.GetData()); if (error.Fail ()) return error; + error = ReadResponseStatus (); + if (error.Fail ()) + return error; + + std::vector 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; +} + +std::unique_ptr +AdbClient::GetSyncService (Error &error) +{ + std::unique_ptr sync_service; + error = StartSync (); + if (error.Success ()) + sync_service.reset (new SyncService(std::move(m_conn))); + + return sync_service; +} + +Error +AdbClient::SyncService::PullFile (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 +416,7 @@ 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 +436,8 @@ } Error -AdbClient::PushFile (const FileSpec &local_file, const FileSpec &remote_file) +AdbClient::SyncService::PushFile (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 +446,7 @@ 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 +486,46 @@ } Error -AdbClient::StartSync () +AdbClient::SyncService::Stat (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 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; -Error -AdbClient::Sync () -{ - auto error = SendMessage ("sync:", false); - if (error.Fail ()) - return error; + const void* command = extractor.GetData (&offset, stat_len); + if (!command) + return Error ("Failed to get response command"); + const char* command_str = static_cast (command); + if (strncmp (command_str, kSTAT, stat_len)) + return Error ("Got invalid stat command: %s", command_str); - return ReadResponseStatus (); + mode = extractor.GetU32 (&offset); + size = extractor.GetU32 (&offset); + mtime = extractor.GetU32 (&offset); + return Error (); } -Error -AdbClient::PullFileChunk (std::vector &buffer, bool &eof) +AdbClient::SyncService::SyncService(std::unique_ptr &&conn): +m_conn(std::move(conn)) { - buffer.clear (); - - std::string response_id; - uint32_t data_len; - auto error = ReadSyncHeader (response_id, data_len); - if (error.Fail ()) - return error; - - 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 ()); - - 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 +534,17 @@ 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,93 +561,44 @@ } Error -AdbClient::ReadAllBytes (void *buffer, size_t size) +AdbClient::SyncService::PullFileChunk (std::vector &buffer, bool &eof) { - using namespace std::chrono; + buffer.clear (); - Error error; - ConnectionStatus status; - char *read_buffer = static_cast(buffer); + std::string response_id; + uint32_t data_len; + auto error = ReadSyncHeader (response_id, data_len); + if (error.Fail ()) + return error; - auto now = steady_clock::now(); - const auto deadline = now + kReadTimeout; - size_t total_read_bytes = 0; - while (total_read_bytes < size && now < deadline) + if (response_id == kDATA) { - uint32_t timeout_usec = duration_cast(deadline - now).count(); - auto read_bytes = - m_conn.Read(read_buffer + total_read_bytes, size - total_read_bytes, timeout_usec, status, &error); + buffer.resize (data_len, 0); + error = ReadAllBytes (&buffer[0], data_len); if (error.Fail ()) - return error; - total_read_bytes += read_bytes; - if (status != eConnectionStatusSuccess) - break; - now = steady_clock::now(); + buffer.clear (); } - if (total_read_bytes < size) - error = Error("Unable to read requested number of bytes. Connection status: %d.", status); - return error; -} - -Error -AdbClient::Stat (const FileSpec &remote_file, uint32_t &mode, uint32_t &size, uint32_t &mtime) -{ - auto error = StartSync (); - 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 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 (command); - if (strncmp (command_str, kSTAT, stat_len)) - return Error ("Got invalid stat command: %s", command_str); + 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 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); } + Index: source/Plugins/Platform/Android/PlatformAndroid.h =================================================================== --- source/Plugins/Platform/Android/PlatformAndroid.h +++ source/Plugins/Platform/Android/PlatformAndroid.h @@ -12,12 +12,15 @@ // C Includes // C++ Includes +#include #include // 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,8 @@ GetLibdlFunctionDeclarations() const override; private: + std::unique_ptr m_adb; + std::unique_ptr m_adb_sync_svc; std::string m_device_id; uint32_t m_sdk_version; Index: source/Plugins/Platform/Android/PlatformAndroid.cpp =================================================================== --- source/Plugins/Platform/Android/PlatformAndroid.cpp +++ source/Plugins/Platform/Android/PlatformAndroid.cpp @@ -204,12 +204,17 @@ auto error = PlatformLinux::ConnectRemote(args); if (error.Success()) { - AdbClient adb; - error = AdbClient::CreateByDeviceID(m_device_id, adb); + m_adb.reset(new AdbClient); + error = AdbClient::CreateByDeviceID(m_device_id, *m_adb); if (error.Fail()) return error; - m_device_id = adb.GetDeviceID(); + m_device_id = m_adb->GetDeviceID(); + m_adb_sync_svc = m_adb->GetSyncService(error); + if (error.Fail()) + return error; + + error = m_adb->SwitchDeviceTransport(); } return error; } @@ -225,8 +230,7 @@ if (source_spec.IsRelative()) source_spec = GetRemoteWorkingDirectory ().CopyByAppendingPathComponent (source_spec.GetCString (false)); - AdbClient adb (m_device_id); - return adb.PullFile (source_spec, destination); + return m_adb_sync_svc->PullFile (source_spec, destination); } Error @@ -242,9 +246,8 @@ 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); + return m_adb_sync_svc->PushFile(source, destination_spec); } const char * @@ -293,8 +296,7 @@ return m_sdk_version; std::string version_string; - AdbClient adb(m_device_id); - Error error = adb.Shell("getprop ro.build.version.sdk", 5000 /* ms */, &version_string); + Error error = m_adb->Shell("getprop ro.build.version.sdk", 5000 /* ms */, &version_string); version_string = llvm::StringRef(version_string).trim().str(); if (error.Fail() || version_string.empty()) @@ -330,10 +332,8 @@ if (module_sp->GetSectionList()->FindSectionByName(ConstString(".symtab")) != nullptr) 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); + Error error = m_adb->Shell("mktemp --directory --tmpdir /data/local/tmp", 5000 /* ms */, &tmpdir); if (error.Fail() || tmpdir.empty()) return Error("Failed to generate temporary directory on the device (%s)", error.AsCString()); tmpdir = llvm::StringRef(tmpdir).trim().str(); @@ -341,10 +341,10 @@ // Create file remover for the temporary directory created on the device std::unique_ptr> tmpdir_remover( &tmpdir, - [this, &adb](std::string* s) { + [this](std::string* s) { StreamString command; command.Printf("rm -rf %s", s->c_str()); - Error error = adb.Shell(command.GetData(), 5000 /* ms */, nullptr); + Error error = m_adb->Shell(command.GetData(), 5000 /* ms */, nullptr); Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_PLATFORM)); if (error.Fail()) @@ -360,7 +360,7 @@ command.Printf("oatdump --symbolize=%s --output=%s", module_sp->GetPlatformFileSpec().GetCString(false), symfile_platform_filespec.GetCString(false)); - error = adb.Shell(command.GetData(), 60000 /* ms */, nullptr); + error = m_adb->Shell(command.GetData(), 60000 /* ms */, nullptr); if (error.Fail()) return Error("Oatdump failed: %s", error.AsCString()); Index: source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp =================================================================== --- source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp +++ 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"