Index: source/Plugins/Platform/Android/AdbClient.h =================================================================== --- source/Plugins/Platform/Android/AdbClient.h +++ source/Plugins/Platform/Android/AdbClient.h @@ -119,6 +119,9 @@ Error Shell (const char* command, uint32_t timeout_ms, std::string* output); + Error + ShellToFile (const char* command, uint32_t timeout_ms, const FileSpec &output_file_spec); + std::unique_ptr GetSyncService (Error &error); @@ -157,6 +160,9 @@ StartSync (); Error + internalShell (const char* command, uint32_t timeout_ms, std::vector &output_buf); + + Error ReadAllBytes (void *buffer, size_t size); std::string m_device_id; Index: source/Plugins/Platform/Android/AdbClient.cpp =================================================================== --- source/Plugins/Platform/Android/AdbClient.cpp +++ source/Plugins/Platform/Android/AdbClient.cpp @@ -378,8 +378,10 @@ } Error -AdbClient::Shell (const char* command, uint32_t timeout_ms, std::string* output) +AdbClient::internalShell (const char* command, uint32_t timeout_ms, std::vector &output_buf) { + output_buf.clear (); + auto error = SwitchDeviceTransport (); if (error.Fail ()) return Error ("Failed to switch to device transport: %s", error.AsCString ()); @@ -394,16 +396,39 @@ if (error.Fail ()) return error; - std::vector in_buffer; - error = ReadMessageStream (in_buffer, timeout_ms); - if (error.Fail()) + return ReadMessageStream (output_buf, timeout_ms); +} + +Error +AdbClient::Shell (const char* command, uint32_t timeout_ms, std::string* output) +{ + std::vector output_buffer; + auto error = internalShell (command, timeout_ms, output_buffer); + if (error.Fail ()) return error; if (output) - output->assign(in_buffer.begin(), in_buffer.end()); + 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 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 ()); + return Error (); +} + std::unique_ptr AdbClient::GetSyncService (Error &error) { Index: source/Plugins/Platform/Android/PlatformAndroid.cpp =================================================================== --- source/Plugins/Platform/Android/PlatformAndroid.cpp +++ source/Plugins/Platform/Android/PlatformAndroid.cpp @@ -230,6 +230,22 @@ 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) + { + // 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_spec.GetCString (false)); + + return adb.ShellToFile(cmd, 60000 /* ms */, destination); + } + return sync_service->PullFile (source_spec, destination); }