adb: implement compression for file sync.
This improves performance when syncing by up to 2x (remote cuttlefish
goes from 11.9 MB/s to 21.3 MB/s, blueline over USB 2.0 from 36 MB/s
to 70 MB/s).
This results in a slight drop in push speeds over USB 3.0 (125 -> 115
MB/s on blueline), presumably because we're compressing and extracting
on only a single thread, but the gains over lower bandwidth transports
make this worth it to submit this now and parallelize later.
Bug: https://issuetracker.google.com/150827486
Test: ADB_COMPRESSION={0, 1} test_device.py (with new/old adbd)
Change-Id: Ic2a0c974f1b6efecda115f87d336e3caac810035
diff --git a/adb/client/adb_install.cpp b/adb/client/adb_install.cpp
index 21b8f49..fe9182e 100644
--- a/adb/client/adb_install.cpp
+++ b/adb/client/adb_install.cpp
@@ -286,7 +286,7 @@
}
}
- if (do_sync_push(apk_file, apk_dest.c_str(), false)) {
+ if (do_sync_push(apk_file, apk_dest.c_str(), false, true)) {
result = pm_command(argc, argv);
delete_device_file(apk_dest);
}
diff --git a/adb/client/commandline.cpp b/adb/client/commandline.cpp
index 0c96104..04b250d 100644
--- a/adb/client/commandline.cpp
+++ b/adb/client/commandline.cpp
@@ -129,15 +129,21 @@
" reverse --remove-all remove all reverse socket connections from device\n"
"\n"
"file transfer:\n"
- " push [--sync] LOCAL... REMOTE\n"
+ " push [--sync] [-zZ] LOCAL... REMOTE\n"
" copy local files/directories to device\n"
" --sync: only push files that are newer on the host than the device\n"
- " pull [-a] REMOTE... LOCAL\n"
+ " -z: enable compression\n"
+ " -Z: disable compression\n"
+ " pull [-azZ] REMOTE... LOCAL\n"
" copy files/dirs from device\n"
" -a: preserve file timestamp and mode\n"
- " sync [all|data|odm|oem|product|system|system_ext|vendor]\n"
+ " -z: enable compression\n"
+ " -Z: disable compression\n"
+ " sync [-lzZ] [all|data|odm|oem|product|system|system_ext|vendor]\n"
" sync a local build from $ANDROID_PRODUCT_OUT to the device (default all)\n"
" -l: list files that would be copied, but don't copy them\n"
+ " -z: enable compression\n"
+ " -Z: disable compression\n"
"\n"
"shell:\n"
" shell [-e ESCAPE] [-n] [-Tt] [-x] [COMMAND...]\n"
@@ -1309,8 +1315,12 @@
}
static void parse_push_pull_args(const char** arg, int narg, std::vector<const char*>* srcs,
- const char** dst, bool* copy_attrs, bool* sync) {
+ const char** dst, bool* copy_attrs, bool* sync, bool* compressed) {
*copy_attrs = false;
+ const char* adb_compression = getenv("ADB_COMPRESSION");
+ if (adb_compression && strcmp(adb_compression, "0") == 0) {
+ *compressed = false;
+ }
srcs->clear();
bool ignore_flags = false;
@@ -1322,6 +1332,14 @@
// Silently ignore for backwards compatibility.
} else if (!strcmp(*arg, "-a")) {
*copy_attrs = true;
+ } else if (!strcmp(*arg, "-z")) {
+ if (compressed != nullptr) {
+ *compressed = true;
+ }
+ } else if (!strcmp(*arg, "-Z")) {
+ if (compressed != nullptr) {
+ *compressed = false;
+ }
} else if (!strcmp(*arg, "--sync")) {
if (sync != nullptr) {
*sync = true;
@@ -1876,20 +1894,22 @@
} else if (!strcmp(argv[0], "push")) {
bool copy_attrs = false;
bool sync = false;
+ bool compressed = true;
std::vector<const char*> srcs;
const char* dst = nullptr;
- parse_push_pull_args(&argv[1], argc - 1, &srcs, &dst, ©_attrs, &sync);
+ parse_push_pull_args(&argv[1], argc - 1, &srcs, &dst, ©_attrs, &sync, &compressed);
if (srcs.empty() || !dst) error_exit("push requires an argument");
- return do_sync_push(srcs, dst, sync) ? 0 : 1;
+ return do_sync_push(srcs, dst, sync, compressed) ? 0 : 1;
} else if (!strcmp(argv[0], "pull")) {
bool copy_attrs = false;
+ bool compressed = true;
std::vector<const char*> srcs;
const char* dst = ".";
- parse_push_pull_args(&argv[1], argc - 1, &srcs, &dst, ©_attrs, nullptr);
+ parse_push_pull_args(&argv[1], argc - 1, &srcs, &dst, ©_attrs, nullptr, &compressed);
if (srcs.empty()) error_exit("pull requires an argument");
- return do_sync_pull(srcs, dst, copy_attrs) ? 0 : 1;
+ return do_sync_pull(srcs, dst, copy_attrs, compressed) ? 0 : 1;
} else if (!strcmp(argv[0], "install")) {
if (argc < 2) error_exit("install requires an argument");
return install_app(argc, argv);
@@ -1905,18 +1925,38 @@
} else if (!strcmp(argv[0], "sync")) {
std::string src;
bool list_only = false;
- if (argc < 2) {
- // No partition specified: sync all of them.
- } else if (argc >= 2 && strcmp(argv[1], "-l") == 0) {
- list_only = true;
- if (argc == 3) src = argv[2];
- } else if (argc == 2) {
- src = argv[1];
- } else {
- error_exit("usage: adb sync [-l] [PARTITION]");
+ bool compressed = true;
+
+ const char* adb_compression = getenv("ADB_COMPRESSION");
+ if (adb_compression && strcmp(adb_compression, "0") == 0) {
+ compressed = false;
}
- if (src.empty()) src = "all";
+ int opt;
+ while ((opt = getopt(argc, const_cast<char**>(argv), "lzZ")) != -1) {
+ switch (opt) {
+ case 'l':
+ list_only = true;
+ break;
+ case 'z':
+ compressed = true;
+ break;
+ case 'Z':
+ compressed = false;
+ break;
+ default:
+ error_exit("usage: adb sync [-lzZ] [PARTITION]");
+ }
+ }
+
+ if (optind == argc) {
+ src = "all";
+ } else if (optind + 1 == argc) {
+ src = argv[optind];
+ } else {
+ error_exit("usage: adb sync [-lzZ] [PARTITION]");
+ }
+
std::vector<std::string> partitions{"data", "odm", "oem", "product",
"system", "system_ext", "vendor"};
bool found = false;
@@ -1925,7 +1965,7 @@
std::string src_dir{product_file(partition)};
if (!directory_exists(src_dir)) continue;
found = true;
- if (!do_sync_sync(src_dir, "/" + partition, list_only)) return 1;
+ if (!do_sync_sync(src_dir, "/" + partition, list_only, compressed)) return 1;
}
}
if (!found) error_exit("don't know how to sync %s partition", src.c_str());
diff --git a/adb/client/fastdeploy.cpp b/adb/client/fastdeploy.cpp
index c5fc12f..de82e14 100644
--- a/adb/client/fastdeploy.cpp
+++ b/adb/client/fastdeploy.cpp
@@ -112,7 +112,7 @@
// but can't be removed until after the push.
unix_close(tf.release());
- if (!do_sync_push(srcs, dst, sync)) {
+ if (!do_sync_push(srcs, dst, sync, true)) {
error_exit("Failed to push fastdeploy agent to device.");
}
}
diff --git a/adb/client/file_sync_client.cpp b/adb/client/file_sync_client.cpp
index 599a3e3..56568c2 100644
--- a/adb/client/file_sync_client.cpp
+++ b/adb/client/file_sync_client.cpp
@@ -42,6 +42,7 @@
#include "adb_client.h"
#include "adb_io.h"
#include "adb_utils.h"
+#include "brotli_utils.h"
#include "file_sync_protocol.h"
#include "line_printer.h"
#include "sysdeps/errno.h"
@@ -233,6 +234,8 @@
} else {
have_stat_v2_ = CanUseFeature(features_, kFeatureStat2);
have_ls_v2_ = CanUseFeature(features_, kFeatureLs2);
+ have_sendrecv_v2_ = CanUseFeature(features_, kFeatureSendRecv2);
+ have_sendrecv_v2_brotli_ = CanUseFeature(features_, kFeatureSendRecv2Brotli);
fd.reset(adb_connect("sync:", &error));
if (fd < 0) {
Error("connect failed: %s", error.c_str());
@@ -256,6 +259,9 @@
line_printer_.KeepInfoLine();
}
+ bool HaveSendRecv2() const { return have_sendrecv_v2_; }
+ bool HaveSendRecv2Brotli() const { return have_sendrecv_v2_brotli_; }
+
const FeatureSet& Features() const { return features_; }
bool IsValid() { return fd >= 0; }
@@ -314,6 +320,62 @@
req->path_length = path.length();
char* data = reinterpret_cast<char*>(req + 1);
memcpy(data, path.data(), path.length());
+ return WriteFdExactly(fd, buf.data(), buf.size());
+ }
+
+ bool SendSend2(std::string_view path, mode_t mode, bool compressed) {
+ if (path.length() > 1024) {
+ Error("SendRequest failed: path too long: %zu", path.length());
+ errno = ENAMETOOLONG;
+ return false;
+ }
+
+ Block buf;
+
+ SyncRequest req;
+ req.id = ID_SEND_V2;
+ req.path_length = path.length();
+
+ syncmsg msg;
+ msg.send_v2_setup.id = ID_SEND_V2;
+ msg.send_v2_setup.mode = mode;
+ msg.send_v2_setup.flags = compressed ? kSyncFlagBrotli : kSyncFlagNone;
+
+ buf.resize(sizeof(SyncRequest) + path.length() + sizeof(msg.send_v2_setup));
+
+ void* p = buf.data();
+
+ p = mempcpy(p, &req, sizeof(SyncRequest));
+ p = mempcpy(p, path.data(), path.length());
+ p = mempcpy(p, &msg.send_v2_setup, sizeof(msg.send_v2_setup));
+
+ return WriteFdExactly(fd, buf.data(), buf.size());
+ }
+
+ bool SendRecv2(const std::string& path) {
+ if (path.length() > 1024) {
+ Error("SendRequest failed: path too long: %zu", path.length());
+ errno = ENAMETOOLONG;
+ return false;
+ }
+
+ Block buf;
+
+ SyncRequest req;
+ req.id = ID_RECV_V2;
+ req.path_length = path.length();
+
+ syncmsg msg;
+ msg.recv_v2_setup.id = ID_RECV_V2;
+ msg.recv_v2_setup.flags = kSyncFlagBrotli;
+
+ buf.resize(sizeof(SyncRequest) + path.length() + sizeof(msg.recv_v2_setup));
+
+ void* p = buf.data();
+
+ p = mempcpy(p, &req, sizeof(SyncRequest));
+ p = mempcpy(p, path.data(), path.length());
+ p = mempcpy(p, &msg.recv_v2_setup, sizeof(msg.recv_v2_setup));
return WriteFdExactly(fd, buf.data(), buf.size());
}
@@ -370,8 +432,8 @@
}
if (msg.stat_v1.id != ID_LSTAT_V1) {
- PLOG(FATAL) << "protocol fault: stat response has wrong message id: "
- << msg.stat_v1.id;
+ LOG(FATAL) << "protocol fault: stat response has wrong message id: "
+ << msg.stat_v1.id;
}
if (msg.stat_v1.mode == 0 && msg.stat_v1.size == 0 && msg.stat_v1.mtime == 0) {
@@ -445,7 +507,7 @@
char* p = &buf[0];
SyncRequest* req_send = reinterpret_cast<SyncRequest*>(p);
- req_send->id = ID_SEND;
+ req_send->id = ID_SEND_V1;
req_send->path_length = path_and_mode.length();
p += sizeof(SyncRequest);
memcpy(p, path_and_mode.data(), path_and_mode.size());
@@ -471,11 +533,92 @@
return true;
}
+ bool SendLargeFileCompressed(const std::string& path, mode_t mode, const std::string& lpath,
+ const std::string& rpath, unsigned mtime) {
+ if (!SendSend2(path, mode, true)) {
+ Error("failed to send ID_SEND_V2 message '%s': %s", path.c_str(), strerror(errno));
+ return false;
+ }
+
+ struct stat st;
+ if (stat(lpath.c_str(), &st) == -1) {
+ Error("cannot stat '%s': %s", lpath.c_str(), strerror(errno));
+ return false;
+ }
+
+ uint64_t total_size = st.st_size;
+ uint64_t bytes_copied = 0;
+
+ unique_fd lfd(adb_open(lpath.c_str(), O_RDONLY | O_CLOEXEC));
+ if (lfd < 0) {
+ Error("opening '%s' locally failed: %s", lpath.c_str(), strerror(errno));
+ return false;
+ }
+
+ syncsendbuf sbuf;
+ sbuf.id = ID_DATA;
+
+ BrotliEncoder<SYNC_DATA_MAX> encoder;
+ bool sending = true;
+ while (sending) {
+ Block input(SYNC_DATA_MAX);
+ int r = adb_read(lfd.get(), input.data(), input.size());
+ if (r < 0) {
+ Error("reading '%s' locally failed: %s", lpath.c_str(), strerror(errno));
+ return false;
+ }
+
+ if (r == 0) {
+ encoder.Finish();
+ } else {
+ input.resize(r);
+ encoder.Append(std::move(input));
+ RecordBytesTransferred(r);
+ bytes_copied += r;
+ ReportProgress(rpath, bytes_copied, total_size);
+ }
+
+ while (true) {
+ Block output;
+ BrotliEncodeResult result = encoder.Encode(&output);
+ if (result == BrotliEncodeResult::Error) {
+ Error("compressing '%s' locally failed", lpath.c_str());
+ return false;
+ }
+
+ if (!output.empty()) {
+ sbuf.size = output.size();
+ memcpy(sbuf.data, output.data(), output.size());
+ WriteOrDie(lpath, rpath, &sbuf, sizeof(SyncRequest) + output.size());
+ }
+
+ if (result == BrotliEncodeResult::Done) {
+ sending = false;
+ break;
+ } else if (result == BrotliEncodeResult::NeedInput) {
+ break;
+ } else if (result == BrotliEncodeResult::MoreOutput) {
+ continue;
+ }
+ }
+ }
+
+ syncmsg msg;
+ msg.data.id = ID_DONE;
+ msg.data.size = mtime;
+ RecordFileSent(lpath, rpath);
+ return WriteOrDie(lpath, rpath, &msg.data, sizeof(msg.data));
+ }
+
bool SendLargeFile(const std::string& path, mode_t mode, const std::string& lpath,
- const std::string& rpath, unsigned mtime) {
+ const std::string& rpath, unsigned mtime, bool compressed) {
+ if (compressed && HaveSendRecv2Brotli()) {
+ return SendLargeFileCompressed(path, mode, lpath, rpath, mtime);
+ }
+
std::string path_and_mode = android::base::StringPrintf("%s,%d", path.c_str(), mode);
- if (!SendRequest(ID_SEND, path_and_mode)) {
- Error("failed to send ID_SEND message '%s': %s", path_and_mode.c_str(),
+ if (!SendRequest(ID_SEND_V1, path_and_mode.c_str())) {
+ Error("failed to send ID_SEND_V1 message '%s': %s", path_and_mode.c_str(),
strerror(errno));
return false;
}
@@ -489,7 +632,7 @@
uint64_t total_size = st.st_size;
uint64_t bytes_copied = 0;
- unique_fd lfd(adb_open(lpath.c_str(), O_RDONLY));
+ unique_fd lfd(adb_open(lpath.c_str(), O_RDONLY | O_CLOEXEC));
if (lfd < 0) {
Error("opening '%s' locally failed: %s", lpath.c_str(), strerror(errno));
return false;
@@ -497,8 +640,9 @@
syncsendbuf sbuf;
sbuf.id = ID_DATA;
+
while (true) {
- int bytes_read = adb_read(lfd, sbuf.data, max - sizeof(SyncRequest));
+ int bytes_read = adb_read(lfd, sbuf.data, max);
if (bytes_read == -1) {
Error("reading '%s' locally failed: %s", lpath.c_str(), strerror(errno));
return false;
@@ -511,7 +655,6 @@
RecordBytesTransferred(bytes_read);
bytes_copied += bytes_read;
-
ReportProgress(rpath, bytes_copied, total_size);
}
@@ -695,6 +838,8 @@
FeatureSet features_;
bool have_stat_v2_;
bool have_ls_v2_;
+ bool have_sendrecv_v2_;
+ bool have_sendrecv_v2_brotli_;
TransferLedger global_ledger_;
TransferLedger current_ledger_;
@@ -776,7 +921,7 @@
}
static bool sync_send(SyncConnection& sc, const std::string& lpath, const std::string& rpath,
- unsigned mtime, mode_t mode, bool sync) {
+ unsigned mtime, mode_t mode, bool sync, bool compressed) {
if (sync) {
struct stat st;
if (sync_lstat(sc, rpath, &st)) {
@@ -819,16 +964,16 @@
return false;
}
} else {
- if (!sc.SendLargeFile(rpath, mode, lpath, rpath, mtime)) {
+ if (!sc.SendLargeFile(rpath, mode, lpath, rpath, mtime, compressed)) {
return false;
}
}
return sc.ReadAcknowledgements();
}
-static bool sync_recv(SyncConnection& sc, const char* rpath, const char* lpath,
- const char* name, uint64_t expected_size) {
- if (!sc.SendRequest(ID_RECV, rpath)) return false;
+static bool sync_recv_v1(SyncConnection& sc, const char* rpath, const char* lpath, const char* name,
+ uint64_t expected_size) {
+ if (!sc.SendRequest(ID_RECV_V1, rpath)) return false;
adb_unlink(lpath);
unique_fd lfd(adb_creat(lpath, 0644));
@@ -881,6 +1026,114 @@
return true;
}
+static bool sync_recv_v2(SyncConnection& sc, const char* rpath, const char* lpath, const char* name,
+ uint64_t expected_size) {
+ if (!sc.SendRecv2(rpath)) return false;
+
+ adb_unlink(lpath);
+ unique_fd lfd(adb_creat(lpath, 0644));
+ if (lfd < 0) {
+ sc.Error("cannot create '%s': %s", lpath, strerror(errno));
+ return false;
+ }
+
+ uint64_t bytes_copied = 0;
+
+ Block buffer(SYNC_DATA_MAX);
+ BrotliDecoder decoder(std::span(buffer.data(), buffer.size()));
+ bool reading = true;
+ while (reading) {
+ syncmsg msg;
+ if (!ReadFdExactly(sc.fd, &msg.data, sizeof(msg.data))) {
+ adb_unlink(lpath);
+ return false;
+ }
+
+ if (msg.data.id == ID_DONE) {
+ adb_unlink(lpath);
+ sc.Error("unexpected ID_DONE");
+ return false;
+ }
+
+ if (msg.data.id != ID_DATA) {
+ adb_unlink(lpath);
+ sc.ReportCopyFailure(rpath, lpath, msg);
+ return false;
+ }
+
+ if (msg.data.size > sc.max) {
+ sc.Error("msg.data.size too large: %u (max %zu)", msg.data.size, sc.max);
+ adb_unlink(lpath);
+ return false;
+ }
+
+ Block block(msg.data.size);
+ if (!ReadFdExactly(sc.fd, block.data(), msg.data.size)) {
+ adb_unlink(lpath);
+ return false;
+ }
+ decoder.Append(std::move(block));
+
+ while (true) {
+ std::span<char> output;
+ BrotliDecodeResult result = decoder.Decode(&output);
+
+ if (result == BrotliDecodeResult::Error) {
+ sc.Error("decompress failed");
+ adb_unlink(lpath);
+ return false;
+ }
+
+ if (!output.empty()) {
+ if (!WriteFdExactly(lfd, output.data(), output.size())) {
+ sc.Error("cannot write '%s': %s", lpath, strerror(errno));
+ adb_unlink(lpath);
+ return false;
+ }
+ }
+
+ bytes_copied += output.size();
+
+ sc.RecordBytesTransferred(msg.data.size);
+ sc.ReportProgress(name != nullptr ? name : rpath, bytes_copied, expected_size);
+
+ if (result == BrotliDecodeResult::NeedInput) {
+ break;
+ } else if (result == BrotliDecodeResult::MoreOutput) {
+ continue;
+ } else if (result == BrotliDecodeResult::Done) {
+ reading = false;
+ break;
+ } else {
+ LOG(FATAL) << "invalid BrotliDecodeResult: " << static_cast<int>(result);
+ }
+ }
+ }
+
+ syncmsg msg;
+ if (!ReadFdExactly(sc.fd, &msg.data, sizeof(msg.data))) {
+ sc.Error("failed to read ID_DONE");
+ return false;
+ }
+
+ if (msg.data.id != ID_DONE) {
+ sc.Error("unexpected message after transfer: id = %d (expected ID_DONE)", msg.data.id);
+ return false;
+ }
+
+ sc.RecordFilesTransferred(1);
+ return true;
+}
+
+static bool sync_recv(SyncConnection& sc, const char* rpath, const char* lpath, const char* name,
+ uint64_t expected_size, bool compressed) {
+ if (sc.HaveSendRecv2() && compressed) {
+ return sync_recv_v2(sc, rpath, lpath, name, expected_size);
+ } else {
+ return sync_recv_v1(sc, rpath, lpath, name, expected_size);
+ }
+}
+
bool do_sync_ls(const char* path) {
SyncConnection sc;
if (!sc.IsValid()) return false;
@@ -956,9 +1209,8 @@
return true;
}
-static bool copy_local_dir_remote(SyncConnection& sc, std::string lpath,
- std::string rpath, bool check_timestamps,
- bool list_only) {
+static bool copy_local_dir_remote(SyncConnection& sc, std::string lpath, std::string rpath,
+ bool check_timestamps, bool list_only, bool compressed) {
sc.NewTransfer();
// Make sure that both directory paths end in a slash.
@@ -1040,7 +1292,7 @@
if (list_only) {
sc.Println("would push: %s -> %s", ci.lpath.c_str(), ci.rpath.c_str());
} else {
- if (!sync_send(sc, ci.lpath, ci.rpath, ci.time, ci.mode, false)) {
+ if (!sync_send(sc, ci.lpath, ci.rpath, ci.time, ci.mode, false, compressed)) {
return false;
}
}
@@ -1055,7 +1307,8 @@
return success;
}
-bool do_sync_push(const std::vector<const char*>& srcs, const char* dst, bool sync) {
+bool do_sync_push(const std::vector<const char*>& srcs, const char* dst, bool sync,
+ bool compressed) {
SyncConnection sc;
if (!sc.IsValid()) return false;
@@ -1120,7 +1373,7 @@
dst_dir.append(android::base::Basename(src_path));
}
- success &= copy_local_dir_remote(sc, src_path, dst_dir, sync, false);
+ success &= copy_local_dir_remote(sc, src_path, dst_dir, sync, false, compressed);
continue;
} else if (!should_push_file(st.st_mode)) {
sc.Warning("skipping special file '%s' (mode = 0o%o)", src_path, st.st_mode);
@@ -1141,7 +1394,7 @@
sc.NewTransfer();
sc.SetExpectedTotalBytes(st.st_size);
- success &= sync_send(sc, src_path, dst_path, st.st_mtime, st.st_mode, sync);
+ success &= sync_send(sc, src_path, dst_path, st.st_mtime, st.st_mode, sync, compressed);
sc.ReportTransferRate(src_path, TransferDirection::push);
}
@@ -1226,8 +1479,8 @@
return r1 ? r1 : r2;
}
-static bool copy_remote_dir_local(SyncConnection& sc, std::string rpath,
- std::string lpath, bool copy_attrs) {
+static bool copy_remote_dir_local(SyncConnection& sc, std::string rpath, std::string lpath,
+ bool copy_attrs, bool compressed) {
sc.NewTransfer();
// Make sure that both directory paths end in a slash.
@@ -1257,7 +1510,7 @@
continue;
}
- if (!sync_recv(sc, ci.rpath.c_str(), ci.lpath.c_str(), nullptr, ci.size)) {
+ if (!sync_recv(sc, ci.rpath.c_str(), ci.lpath.c_str(), nullptr, ci.size, compressed)) {
return false;
}
@@ -1274,8 +1527,8 @@
return true;
}
-bool do_sync_pull(const std::vector<const char*>& srcs, const char* dst,
- bool copy_attrs, const char* name) {
+bool do_sync_pull(const std::vector<const char*>& srcs, const char* dst, bool copy_attrs,
+ bool compressed, const char* name) {
SyncConnection sc;
if (!sc.IsValid()) return false;
@@ -1349,7 +1602,7 @@
dst_dir.append(android::base::Basename(src_path));
}
- success &= copy_remote_dir_local(sc, src_path, dst_dir, copy_attrs);
+ success &= copy_remote_dir_local(sc, src_path, dst_dir, copy_attrs, compressed);
continue;
} else if (!should_pull_file(src_st.st_mode)) {
sc.Warning("skipping special file '%s' (mode = 0o%o)", src_path, src_st.st_mode);
@@ -1368,7 +1621,7 @@
sc.NewTransfer();
sc.SetExpectedTotalBytes(src_st.st_size);
- if (!sync_recv(sc, src_path, dst_path, name, src_st.st_size)) {
+ if (!sync_recv(sc, src_path, dst_path, name, src_st.st_size, compressed)) {
success = false;
continue;
}
@@ -1384,11 +1637,12 @@
return success;
}
-bool do_sync_sync(const std::string& lpath, const std::string& rpath, bool list_only) {
+bool do_sync_sync(const std::string& lpath, const std::string& rpath, bool list_only,
+ bool compressed) {
SyncConnection sc;
if (!sc.IsValid()) return false;
- bool success = copy_local_dir_remote(sc, lpath, rpath, true, list_only);
+ bool success = copy_local_dir_remote(sc, lpath, rpath, true, list_only, compressed);
if (!list_only) {
sc.ReportOverallTransferRate(TransferDirection::push);
}
diff --git a/adb/client/file_sync_client.h b/adb/client/file_sync_client.h
index df7f14c..de3f192 100644
--- a/adb/client/file_sync_client.h
+++ b/adb/client/file_sync_client.h
@@ -20,8 +20,10 @@
#include <vector>
bool do_sync_ls(const char* path);
-bool do_sync_push(const std::vector<const char*>& srcs, const char* dst, bool sync);
+bool do_sync_push(const std::vector<const char*>& srcs, const char* dst, bool sync,
+ bool compressed);
bool do_sync_pull(const std::vector<const char*>& srcs, const char* dst, bool copy_attrs,
- const char* name = nullptr);
+ bool compressed, const char* name = nullptr);
-bool do_sync_sync(const std::string& lpath, const std::string& rpath, bool list_only);
+bool do_sync_sync(const std::string& lpath, const std::string& rpath, bool list_only,
+ bool compressed);