Loading adb/client/file_sync_client.cpp +50 −27 Original line number Diff line number Diff line Loading @@ -52,6 +52,8 @@ #include <android-base/strings.h> #include <android-base/stringprintf.h> typedef void(sync_ls_cb)(unsigned mode, uint64_t size, uint64_t time, const char* name); struct syncsendbuf { unsigned id; unsigned size; Loading Loading @@ -210,6 +212,7 @@ class SyncConnection { Error("failed to get feature set: %s", error.c_str()); } else { have_stat_v2_ = CanUseFeature(features_, kFeatureStat2); have_ls_v2_ = CanUseFeature(features_, kFeatureLs2); fd.reset(adb_connect("sync:", &error)); if (fd < 0) { Error("connect failed: %s", error.c_str()); Loading Loading @@ -357,7 +360,7 @@ class SyncConnection { << msg.stat_v1.id; } if (msg.stat_v1.mode == 0 && msg.stat_v1.size == 0 && msg.stat_v1.time == 0) { if (msg.stat_v1.mode == 0 && msg.stat_v1.size == 0 && msg.stat_v1.mtime == 0) { // There's no way for us to know what the error was. errno = ENOPROTOOPT; return false; Loading @@ -365,13 +368,52 @@ class SyncConnection { st->st_mode = msg.stat_v1.mode; st->st_size = msg.stat_v1.size; st->st_ctime = msg.stat_v1.time; st->st_mtime = msg.stat_v1.time; st->st_ctime = msg.stat_v1.mtime; st->st_mtime = msg.stat_v1.mtime; } return true; } bool SendLs(const char* path) { return SendRequest(have_ls_v2_ ? ID_LIST_V2 : ID_LIST_V1, path); } private: template <bool v2> static bool FinishLsImpl(borrowed_fd fd, const std::function<sync_ls_cb>& callback) { using dent_type = std::conditional_t<v2, decltype(syncmsg::dent_v2), decltype(syncmsg::dent_v1)>; while (true) { dent_type dent; if (!ReadFdExactly(fd, &dent, sizeof(dent))) return false; uint32_t expected_id = v2 ? ID_DENT_V2 : ID_DENT_V1; if (dent.id == ID_DONE) return true; if (dent.id != expected_id) return false; // Maximum length of a file name excluding null terminator (NAME_MAX) on Linux is 255. char buf[256]; size_t len = dent.namelen; if (len > 255) return false; if (!ReadFdExactly(fd, buf, len)) return false; buf[len] = 0; callback(dent.mode, dent.size, dent.mtime, buf); } } public: bool FinishLs(const std::function<sync_ls_cb>& callback) { if (have_ls_v2_) { return FinishLsImpl<true>(this->fd, callback); } else { return FinishLsImpl<false>(this->fd, callback); } } // Sending header, payload, and footer in a single write makes a huge // difference to "adb sync" performance. bool SendSmallFile(const char* path_and_mode, Loading Loading @@ -578,6 +620,7 @@ class SyncConnection { bool expect_done_; FeatureSet features_; bool have_stat_v2_; bool have_ls_v2_; TransferLedger global_ledger_; TransferLedger current_ledger_; Loading Loading @@ -609,28 +652,9 @@ class SyncConnection { } }; typedef void (sync_ls_cb)(unsigned mode, unsigned size, unsigned time, const char* name); static bool sync_ls(SyncConnection& sc, const char* path, const std::function<sync_ls_cb>& func) { if (!sc.SendRequest(ID_LIST, path)) return false; while (true) { syncmsg msg; if (!ReadFdExactly(sc.fd, &msg.dent, sizeof(msg.dent))) return false; if (msg.dent.id == ID_DONE) return true; if (msg.dent.id != ID_DENT) return false; size_t len = msg.dent.namelen; if (len > 256) return false; // TODO: resize buffer? continue? char buf[257]; if (!ReadFdExactly(sc.fd, buf, len)) return false; buf[len] = 0; func(msg.dent.mode, msg.dent.size, msg.dent.time, buf); } return sc.SendLs(path) && sc.FinishLs(func); } static bool sync_stat(SyncConnection& sc, const char* path, struct stat* st) { Loading Loading @@ -787,9 +811,8 @@ bool do_sync_ls(const char* path) { SyncConnection sc; if (!sc.IsValid()) return false; return sync_ls(sc, path, [](unsigned mode, unsigned size, unsigned time, const char* name) { printf("%08x %08x %08x %s\n", mode, size, time, name); return sync_ls(sc, path, [](unsigned mode, uint64_t size, uint64_t time, const char* name) { printf("%08x %08" PRIx64 " %08" PRIx64 " %s\n", mode, size, time, name); }); } Loading Loading @@ -1062,7 +1085,7 @@ static bool remote_build_list(SyncConnection& sc, std::vector<copyinfo>* file_li file_list->push_back(ci); // Put the files/dirs in rpath on the lists. auto callback = [&](unsigned mode, unsigned size, unsigned time, const char* name) { auto callback = [&](unsigned mode, uint64_t size, uint64_t time, const char* name) { if (IsDotOrDotDot(name)) { return; } Loading adb/daemon/file_sync_service.cpp +60 −22 Original line number Diff line number Diff line Loading @@ -139,7 +139,7 @@ static bool do_lstat_v1(int s, const char* path) { lstat(path, &st); msg.stat_v1.mode = st.st_mode; msg.stat_v1.size = st.st_size; msg.stat_v1.time = st.st_mtime; msg.stat_v1.mtime = st.st_mtime; return WriteFdExactly(s, &msg.stat_v1, sizeof(msg.stat_v1)); } Loading Loading @@ -174,40 +174,73 @@ static bool do_stat_v2(int s, uint32_t id, const char* path) { return WriteFdExactly(s, &msg.stat_v2, sizeof(msg.stat_v2)); } template <bool v2> static bool do_list(int s, const char* path) { dirent* de; syncmsg msg; msg.dent.id = ID_DENT; using MessageType = std::conditional_t<v2, decltype(syncmsg::dent_v2), decltype(syncmsg::dent_v1)>; MessageType msg; uint32_t msg_id; if constexpr (v2) { msg_id = ID_DENT_V2; } else { msg_id = ID_DENT_V1; } std::unique_ptr<DIR, int(*)(DIR*)> d(opendir(path), closedir); if (!d) goto done; while ((de = readdir(d.get()))) { memset(&msg, 0, sizeof(msg)); msg.id = msg_id; std::string filename(StringPrintf("%s/%s", path, de->d_name)); struct stat st; if (lstat(filename.c_str(), &st) == 0) { msg.mode = st.st_mode; msg.size = st.st_size; msg.mtime = st.st_mtime; if constexpr (v2) { msg.dev = st.st_dev; msg.ino = st.st_ino; msg.nlink = st.st_nlink; msg.uid = st.st_uid; msg.gid = st.st_gid; msg.atime = st.st_atime; msg.ctime = st.st_ctime; } } else { if constexpr (v2) { msg.error = errno; } else { continue; } } size_t d_name_length = strlen(de->d_name); msg.dent.mode = st.st_mode; msg.dent.size = st.st_size; msg.dent.time = st.st_mtime; msg.dent.namelen = d_name_length; msg.namelen = d_name_length; if (!WriteFdExactly(s, &msg.dent, sizeof(msg.dent)) || if (!WriteFdExactly(s, &msg, sizeof(msg)) || !WriteFdExactly(s, de->d_name, d_name_length)) { return false; } } } done: msg.dent.id = ID_DONE; msg.dent.mode = 0; msg.dent.size = 0; msg.dent.time = 0; msg.dent.namelen = 0; return WriteFdExactly(s, &msg.dent, sizeof(msg.dent)); memset(&msg, 0, sizeof(msg)); msg.id = ID_DONE; return WriteFdExactly(s, &msg, sizeof(msg)); } static bool do_list_v1(int s, const char* path) { return do_list<false>(s, path); } static bool do_list_v2(int s, const char* path) { return do_list<true>(s, path); } // Make sure that SendFail from adb_io.cpp isn't accidentally used in this file. Loading Loading @@ -499,8 +532,10 @@ static const char* sync_id_to_name(uint32_t id) { return "lstat_v2"; case ID_STAT_V2: return "stat_v2"; case ID_LIST: return "list"; case ID_LIST_V1: return "list_v1"; case ID_LIST_V2: return "list_v2"; case ID_SEND: return "send"; case ID_RECV: Loading Loading @@ -546,8 +581,11 @@ static bool handle_sync_command(int fd, std::vector<char>& buffer) { case ID_STAT_V2: if (!do_stat_v2(fd, request.id, name)) return false; break; case ID_LIST: if (!do_list(fd, name)) return false; case ID_LIST_V1: if (!do_list_v1(fd, name)) return false; break; case ID_LIST_V2: if (!do_list_v2(fd, name)) return false; break; case ID_SEND: if (!do_send(fd, name, buffer)) return false; Loading adb/file_sync_protocol.h +26 −7 Original line number Diff line number Diff line Loading @@ -21,10 +21,14 @@ #define ID_LSTAT_V1 MKID('S', 'T', 'A', 'T') #define ID_STAT_V2 MKID('S', 'T', 'A', '2') #define ID_LSTAT_V2 MKID('L', 'S', 'T', '2') #define ID_LIST MKID('L', 'I', 'S', 'T') #define ID_LIST_V1 MKID('L', 'I', 'S', 'T') #define ID_LIST_V2 MKID('L', 'I', 'S', '2') #define ID_DENT_V1 MKID('D', 'E', 'N', 'T') #define ID_DENT_V2 MKID('D', 'N', 'T', '2') #define ID_SEND MKID('S', 'E', 'N', 'D') #define ID_RECV MKID('R', 'E', 'C', 'V') #define ID_DENT MKID('D', 'E', 'N', 'T') #define ID_DONE MKID('D', 'O', 'N', 'E') #define ID_DATA MKID('D', 'A', 'T', 'A') #define ID_OKAY MKID('O', 'K', 'A', 'Y') Loading @@ -42,7 +46,7 @@ union syncmsg { uint32_t id; uint32_t mode; uint32_t size; uint32_t time; uint32_t mtime; } stat_v1; struct __attribute__((packed)) { uint32_t id; Loading @@ -62,17 +66,32 @@ union syncmsg { uint32_t id; uint32_t mode; uint32_t size; uint32_t time; uint32_t mtime; uint32_t namelen; } dent_v1; // followed by `namelen` bytes of the name. struct __attribute__((packed)) { uint32_t id; uint32_t error; uint64_t dev; uint64_t ino; uint32_t mode; uint32_t nlink; uint32_t uid; uint32_t gid; uint64_t size; int64_t atime; int64_t mtime; int64_t ctime; uint32_t namelen; } dent; } dent_v2; // followed by `namelen` bytes of the name. struct __attribute__((packed)) { uint32_t id; uint32_t size; } data; } data; // followed by `size` bytes of data. struct __attribute__((packed)) { uint32_t id; uint32_t msglen; } status; } status; // followed by `msglen` bytes of error message, if id == ID_FAIL. }; #define SYNC_DATA_MAX (64 * 1024) adb/transport.cpp +2 −0 Original line number Diff line number Diff line Loading @@ -66,6 +66,7 @@ static auto& transport_lock = *new std::recursive_mutex(); const char* const kFeatureShell2 = "shell_v2"; const char* const kFeatureCmd = "cmd"; const char* const kFeatureStat2 = "stat_v2"; const char* const kFeatureLs2 = "ls_v2"; const char* const kFeatureLibusb = "libusb"; const char* const kFeaturePushSync = "push_sync"; const char* const kFeatureApex = "apex"; Loading Loading @@ -1035,6 +1036,7 @@ const FeatureSet& supported_features() { kFeatureShell2, kFeatureCmd, kFeatureStat2, kFeatureLs2, kFeatureFixedPushMkdir, kFeatureApex, kFeatureAbb, Loading adb/transport.h +1 −0 Original line number Diff line number Diff line Loading @@ -57,6 +57,7 @@ extern const char* const kFeatureShell2; // The 'cmd' command is available extern const char* const kFeatureCmd; extern const char* const kFeatureStat2; extern const char* const kFeatureLs2; // The server is running with libusb enabled. extern const char* const kFeatureLibusb; // adbd supports `push --sync`. Loading Loading
adb/client/file_sync_client.cpp +50 −27 Original line number Diff line number Diff line Loading @@ -52,6 +52,8 @@ #include <android-base/strings.h> #include <android-base/stringprintf.h> typedef void(sync_ls_cb)(unsigned mode, uint64_t size, uint64_t time, const char* name); struct syncsendbuf { unsigned id; unsigned size; Loading Loading @@ -210,6 +212,7 @@ class SyncConnection { Error("failed to get feature set: %s", error.c_str()); } else { have_stat_v2_ = CanUseFeature(features_, kFeatureStat2); have_ls_v2_ = CanUseFeature(features_, kFeatureLs2); fd.reset(adb_connect("sync:", &error)); if (fd < 0) { Error("connect failed: %s", error.c_str()); Loading Loading @@ -357,7 +360,7 @@ class SyncConnection { << msg.stat_v1.id; } if (msg.stat_v1.mode == 0 && msg.stat_v1.size == 0 && msg.stat_v1.time == 0) { if (msg.stat_v1.mode == 0 && msg.stat_v1.size == 0 && msg.stat_v1.mtime == 0) { // There's no way for us to know what the error was. errno = ENOPROTOOPT; return false; Loading @@ -365,13 +368,52 @@ class SyncConnection { st->st_mode = msg.stat_v1.mode; st->st_size = msg.stat_v1.size; st->st_ctime = msg.stat_v1.time; st->st_mtime = msg.stat_v1.time; st->st_ctime = msg.stat_v1.mtime; st->st_mtime = msg.stat_v1.mtime; } return true; } bool SendLs(const char* path) { return SendRequest(have_ls_v2_ ? ID_LIST_V2 : ID_LIST_V1, path); } private: template <bool v2> static bool FinishLsImpl(borrowed_fd fd, const std::function<sync_ls_cb>& callback) { using dent_type = std::conditional_t<v2, decltype(syncmsg::dent_v2), decltype(syncmsg::dent_v1)>; while (true) { dent_type dent; if (!ReadFdExactly(fd, &dent, sizeof(dent))) return false; uint32_t expected_id = v2 ? ID_DENT_V2 : ID_DENT_V1; if (dent.id == ID_DONE) return true; if (dent.id != expected_id) return false; // Maximum length of a file name excluding null terminator (NAME_MAX) on Linux is 255. char buf[256]; size_t len = dent.namelen; if (len > 255) return false; if (!ReadFdExactly(fd, buf, len)) return false; buf[len] = 0; callback(dent.mode, dent.size, dent.mtime, buf); } } public: bool FinishLs(const std::function<sync_ls_cb>& callback) { if (have_ls_v2_) { return FinishLsImpl<true>(this->fd, callback); } else { return FinishLsImpl<false>(this->fd, callback); } } // Sending header, payload, and footer in a single write makes a huge // difference to "adb sync" performance. bool SendSmallFile(const char* path_and_mode, Loading Loading @@ -578,6 +620,7 @@ class SyncConnection { bool expect_done_; FeatureSet features_; bool have_stat_v2_; bool have_ls_v2_; TransferLedger global_ledger_; TransferLedger current_ledger_; Loading Loading @@ -609,28 +652,9 @@ class SyncConnection { } }; typedef void (sync_ls_cb)(unsigned mode, unsigned size, unsigned time, const char* name); static bool sync_ls(SyncConnection& sc, const char* path, const std::function<sync_ls_cb>& func) { if (!sc.SendRequest(ID_LIST, path)) return false; while (true) { syncmsg msg; if (!ReadFdExactly(sc.fd, &msg.dent, sizeof(msg.dent))) return false; if (msg.dent.id == ID_DONE) return true; if (msg.dent.id != ID_DENT) return false; size_t len = msg.dent.namelen; if (len > 256) return false; // TODO: resize buffer? continue? char buf[257]; if (!ReadFdExactly(sc.fd, buf, len)) return false; buf[len] = 0; func(msg.dent.mode, msg.dent.size, msg.dent.time, buf); } return sc.SendLs(path) && sc.FinishLs(func); } static bool sync_stat(SyncConnection& sc, const char* path, struct stat* st) { Loading Loading @@ -787,9 +811,8 @@ bool do_sync_ls(const char* path) { SyncConnection sc; if (!sc.IsValid()) return false; return sync_ls(sc, path, [](unsigned mode, unsigned size, unsigned time, const char* name) { printf("%08x %08x %08x %s\n", mode, size, time, name); return sync_ls(sc, path, [](unsigned mode, uint64_t size, uint64_t time, const char* name) { printf("%08x %08" PRIx64 " %08" PRIx64 " %s\n", mode, size, time, name); }); } Loading Loading @@ -1062,7 +1085,7 @@ static bool remote_build_list(SyncConnection& sc, std::vector<copyinfo>* file_li file_list->push_back(ci); // Put the files/dirs in rpath on the lists. auto callback = [&](unsigned mode, unsigned size, unsigned time, const char* name) { auto callback = [&](unsigned mode, uint64_t size, uint64_t time, const char* name) { if (IsDotOrDotDot(name)) { return; } Loading
adb/daemon/file_sync_service.cpp +60 −22 Original line number Diff line number Diff line Loading @@ -139,7 +139,7 @@ static bool do_lstat_v1(int s, const char* path) { lstat(path, &st); msg.stat_v1.mode = st.st_mode; msg.stat_v1.size = st.st_size; msg.stat_v1.time = st.st_mtime; msg.stat_v1.mtime = st.st_mtime; return WriteFdExactly(s, &msg.stat_v1, sizeof(msg.stat_v1)); } Loading Loading @@ -174,40 +174,73 @@ static bool do_stat_v2(int s, uint32_t id, const char* path) { return WriteFdExactly(s, &msg.stat_v2, sizeof(msg.stat_v2)); } template <bool v2> static bool do_list(int s, const char* path) { dirent* de; syncmsg msg; msg.dent.id = ID_DENT; using MessageType = std::conditional_t<v2, decltype(syncmsg::dent_v2), decltype(syncmsg::dent_v1)>; MessageType msg; uint32_t msg_id; if constexpr (v2) { msg_id = ID_DENT_V2; } else { msg_id = ID_DENT_V1; } std::unique_ptr<DIR, int(*)(DIR*)> d(opendir(path), closedir); if (!d) goto done; while ((de = readdir(d.get()))) { memset(&msg, 0, sizeof(msg)); msg.id = msg_id; std::string filename(StringPrintf("%s/%s", path, de->d_name)); struct stat st; if (lstat(filename.c_str(), &st) == 0) { msg.mode = st.st_mode; msg.size = st.st_size; msg.mtime = st.st_mtime; if constexpr (v2) { msg.dev = st.st_dev; msg.ino = st.st_ino; msg.nlink = st.st_nlink; msg.uid = st.st_uid; msg.gid = st.st_gid; msg.atime = st.st_atime; msg.ctime = st.st_ctime; } } else { if constexpr (v2) { msg.error = errno; } else { continue; } } size_t d_name_length = strlen(de->d_name); msg.dent.mode = st.st_mode; msg.dent.size = st.st_size; msg.dent.time = st.st_mtime; msg.dent.namelen = d_name_length; msg.namelen = d_name_length; if (!WriteFdExactly(s, &msg.dent, sizeof(msg.dent)) || if (!WriteFdExactly(s, &msg, sizeof(msg)) || !WriteFdExactly(s, de->d_name, d_name_length)) { return false; } } } done: msg.dent.id = ID_DONE; msg.dent.mode = 0; msg.dent.size = 0; msg.dent.time = 0; msg.dent.namelen = 0; return WriteFdExactly(s, &msg.dent, sizeof(msg.dent)); memset(&msg, 0, sizeof(msg)); msg.id = ID_DONE; return WriteFdExactly(s, &msg, sizeof(msg)); } static bool do_list_v1(int s, const char* path) { return do_list<false>(s, path); } static bool do_list_v2(int s, const char* path) { return do_list<true>(s, path); } // Make sure that SendFail from adb_io.cpp isn't accidentally used in this file. Loading Loading @@ -499,8 +532,10 @@ static const char* sync_id_to_name(uint32_t id) { return "lstat_v2"; case ID_STAT_V2: return "stat_v2"; case ID_LIST: return "list"; case ID_LIST_V1: return "list_v1"; case ID_LIST_V2: return "list_v2"; case ID_SEND: return "send"; case ID_RECV: Loading Loading @@ -546,8 +581,11 @@ static bool handle_sync_command(int fd, std::vector<char>& buffer) { case ID_STAT_V2: if (!do_stat_v2(fd, request.id, name)) return false; break; case ID_LIST: if (!do_list(fd, name)) return false; case ID_LIST_V1: if (!do_list_v1(fd, name)) return false; break; case ID_LIST_V2: if (!do_list_v2(fd, name)) return false; break; case ID_SEND: if (!do_send(fd, name, buffer)) return false; Loading
adb/file_sync_protocol.h +26 −7 Original line number Diff line number Diff line Loading @@ -21,10 +21,14 @@ #define ID_LSTAT_V1 MKID('S', 'T', 'A', 'T') #define ID_STAT_V2 MKID('S', 'T', 'A', '2') #define ID_LSTAT_V2 MKID('L', 'S', 'T', '2') #define ID_LIST MKID('L', 'I', 'S', 'T') #define ID_LIST_V1 MKID('L', 'I', 'S', 'T') #define ID_LIST_V2 MKID('L', 'I', 'S', '2') #define ID_DENT_V1 MKID('D', 'E', 'N', 'T') #define ID_DENT_V2 MKID('D', 'N', 'T', '2') #define ID_SEND MKID('S', 'E', 'N', 'D') #define ID_RECV MKID('R', 'E', 'C', 'V') #define ID_DENT MKID('D', 'E', 'N', 'T') #define ID_DONE MKID('D', 'O', 'N', 'E') #define ID_DATA MKID('D', 'A', 'T', 'A') #define ID_OKAY MKID('O', 'K', 'A', 'Y') Loading @@ -42,7 +46,7 @@ union syncmsg { uint32_t id; uint32_t mode; uint32_t size; uint32_t time; uint32_t mtime; } stat_v1; struct __attribute__((packed)) { uint32_t id; Loading @@ -62,17 +66,32 @@ union syncmsg { uint32_t id; uint32_t mode; uint32_t size; uint32_t time; uint32_t mtime; uint32_t namelen; } dent_v1; // followed by `namelen` bytes of the name. struct __attribute__((packed)) { uint32_t id; uint32_t error; uint64_t dev; uint64_t ino; uint32_t mode; uint32_t nlink; uint32_t uid; uint32_t gid; uint64_t size; int64_t atime; int64_t mtime; int64_t ctime; uint32_t namelen; } dent; } dent_v2; // followed by `namelen` bytes of the name. struct __attribute__((packed)) { uint32_t id; uint32_t size; } data; } data; // followed by `size` bytes of data. struct __attribute__((packed)) { uint32_t id; uint32_t msglen; } status; } status; // followed by `msglen` bytes of error message, if id == ID_FAIL. }; #define SYNC_DATA_MAX (64 * 1024)
adb/transport.cpp +2 −0 Original line number Diff line number Diff line Loading @@ -66,6 +66,7 @@ static auto& transport_lock = *new std::recursive_mutex(); const char* const kFeatureShell2 = "shell_v2"; const char* const kFeatureCmd = "cmd"; const char* const kFeatureStat2 = "stat_v2"; const char* const kFeatureLs2 = "ls_v2"; const char* const kFeatureLibusb = "libusb"; const char* const kFeaturePushSync = "push_sync"; const char* const kFeatureApex = "apex"; Loading Loading @@ -1035,6 +1036,7 @@ const FeatureSet& supported_features() { kFeatureShell2, kFeatureCmd, kFeatureStat2, kFeatureLs2, kFeatureFixedPushMkdir, kFeatureApex, kFeatureAbb, Loading
adb/transport.h +1 −0 Original line number Diff line number Diff line Loading @@ -57,6 +57,7 @@ extern const char* const kFeatureShell2; // The 'cmd' command is available extern const char* const kFeatureCmd; extern const char* const kFeatureStat2; extern const char* const kFeatureLs2; // The server is running with libusb enabled. extern const char* const kFeatureLibusb; // adbd supports `push --sync`. Loading