Merge changes from topic "liblog" into rvc-dev

* changes:
  Whole static link libasync_safe to libbacktrace.a
  libbase uses liblog symbols via dlsym when it is built for APEX
diff --git a/adb/client/file_sync_client.cpp b/adb/client/file_sync_client.cpp
index 922f2ba..cc38926 100644
--- a/adb/client/file_sync_client.cpp
+++ b/adb/client/file_sync_client.cpp
@@ -29,6 +29,7 @@
 #include <utime.h>
 
 #include <chrono>
+#include <deque>
 #include <functional>
 #include <memory>
 #include <sstream>
@@ -203,7 +204,7 @@
 
 class SyncConnection {
   public:
-    SyncConnection() : expect_done_(false) {
+    SyncConnection() {
         max = SYNC_DATA_MAX; // TODO: decide at runtime.
 
         std::string error;
@@ -239,16 +240,6 @@
 
     bool IsValid() { return fd >= 0; }
 
-    bool ReceivedError(const char* from, const char* to) {
-        adb_pollfd pfd = {.fd = fd.get(), .events = POLLIN};
-        int rc = adb_poll(&pfd, 1, 0);
-        if (rc < 0) {
-            Error("failed to poll: %s", strerror(errno));
-            return true;
-        }
-        return rc != 0;
-    }
-
     void NewTransfer() {
         current_ledger_.Reset();
     }
@@ -258,6 +249,11 @@
         global_ledger_.bytes_transferred += bytes;
     }
 
+    void RecordFileSent(std::string from, std::string to) {
+        RecordFilesTransferred(1);
+        deferred_acknowledgements_.emplace_back(std::move(from), std::move(to));
+    }
+
     void RecordFilesTransferred(size_t files) {
         current_ledger_.files_transferred += files;
         global_ledger_.files_transferred += files;
@@ -283,39 +279,38 @@
         }
     }
 
-    bool SendRequest(int id, const char* path_and_mode) {
-        size_t path_length = strlen(path_and_mode);
-        if (path_length > 1024) {
-            Error("SendRequest failed: path too long: %zu", path_length);
+    bool SendRequest(int id, const std::string& path) {
+        if (path.length() > 1024) {
+            Error("SendRequest failed: path too long: %zu", path.length());
             errno = ENAMETOOLONG;
             return false;
         }
 
         // Sending header and payload in a single write makes a noticeable
         // difference to "adb sync" performance.
-        std::vector<char> buf(sizeof(SyncRequest) + path_length);
+        std::vector<char> buf(sizeof(SyncRequest) + path.length());
         SyncRequest* req = reinterpret_cast<SyncRequest*>(&buf[0]);
         req->id = id;
-        req->path_length = path_length;
+        req->path_length = path.length();
         char* data = reinterpret_cast<char*>(req + 1);
-        memcpy(data, path_and_mode, path_length);
+        memcpy(data, path.data(), path.length());
 
-        return WriteFdExactly(fd, &buf[0], buf.size());
+        return WriteFdExactly(fd, buf.data(), buf.size());
     }
 
-    bool SendStat(const char* path_and_mode) {
+    bool SendStat(const std::string& path) {
         if (!have_stat_v2_) {
             errno = ENOTSUP;
             return false;
         }
-        return SendRequest(ID_STAT_V2, path_and_mode);
+        return SendRequest(ID_STAT_V2, path);
     }
 
-    bool SendLstat(const char* path_and_mode) {
+    bool SendLstat(const std::string& path) {
         if (have_stat_v2_) {
-            return SendRequest(ID_LSTAT_V2, path_and_mode);
+            return SendRequest(ID_LSTAT_V2, path);
         } else {
-            return SendRequest(ID_LSTAT_V1, path_and_mode);
+            return SendRequest(ID_LSTAT_V1, path);
         }
     }
 
@@ -374,7 +369,7 @@
         return true;
     }
 
-    bool SendLs(const char* path) {
+    bool SendLs(const std::string& path) {
         return SendRequest(have_ls_v2_ ? ID_LIST_V2 : ID_LIST_V1, path);
     }
 
@@ -415,28 +410,26 @@
 
     // Sending header, payload, and footer in a single write makes a huge
     // difference to "adb sync" performance.
-    bool SendSmallFile(const char* path_and_mode,
-                       const char* lpath, const char* rpath,
-                       unsigned mtime,
-                       const char* data, size_t data_length) {
-        size_t path_length = strlen(path_and_mode);
-        if (path_length > 1024) {
-            Error("SendSmallFile failed: path too long: %zu", path_length);
+    bool SendSmallFile(const std::string& path, mode_t mode, const std::string& lpath,
+                       const std::string& rpath, unsigned mtime, const char* data,
+                       size_t data_length) {
+        std::string path_and_mode = android::base::StringPrintf("%s,%d", path.c_str(), mode);
+        if (path_and_mode.length() > 1024) {
+            Error("SendSmallFile failed: path too long: %zu", path_and_mode.length());
             errno = ENAMETOOLONG;
             return false;
         }
 
-        std::vector<char> buf(sizeof(SyncRequest) + path_length +
-                              sizeof(SyncRequest) + data_length +
-                              sizeof(SyncRequest));
+        std::vector<char> buf(sizeof(SyncRequest) + path_and_mode.length() + sizeof(SyncRequest) +
+                              data_length + sizeof(SyncRequest));
         char* p = &buf[0];
 
         SyncRequest* req_send = reinterpret_cast<SyncRequest*>(p);
         req_send->id = ID_SEND;
-        req_send->path_length = path_length;
+        req_send->path_length = path_and_mode.length();
         p += sizeof(SyncRequest);
-        memcpy(p, path_and_mode, path_length);
-        p += path_length;
+        memcpy(p, path_and_mode.data(), path_and_mode.size());
+        p += path_and_mode.length();
 
         SyncRequest* req_data = reinterpret_cast<SyncRequest*>(p);
         req_data->id = ID_DATA;
@@ -451,34 +444,34 @@
         p += sizeof(SyncRequest);
 
         WriteOrDie(lpath, rpath, &buf[0], (p - &buf[0]));
-        expect_done_ = true;
 
-        // RecordFilesTransferred gets called in CopyDone.
+        RecordFileSent(lpath, rpath);
         RecordBytesTransferred(data_length);
         ReportProgress(rpath, data_length, data_length);
         return true;
     }
 
-    bool SendLargeFile(const char* path_and_mode,
-                       const char* lpath, const char* rpath,
-                       unsigned mtime) {
+    bool SendLargeFile(const std::string& path, mode_t mode, const std::string& lpath,
+                       const std::string& rpath, unsigned 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, strerror(errno));
+            Error("failed to send ID_SEND message '%s': %s", path_and_mode.c_str(),
+                  strerror(errno));
             return false;
         }
 
         struct stat st;
-        if (stat(lpath, &st) == -1) {
-            Error("cannot stat '%s': %s", lpath, strerror(errno));
+        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, O_RDONLY));
+        unique_fd lfd(adb_open(lpath.c_str(), O_RDONLY));
         if (lfd < 0) {
-            Error("opening '%s' locally failed: %s", lpath, strerror(errno));
+            Error("opening '%s' locally failed: %s", lpath.c_str(), strerror(errno));
             return false;
         }
 
@@ -487,7 +480,7 @@
         while (true) {
             int bytes_read = adb_read(lfd, sbuf.data, max - sizeof(SyncRequest));
             if (bytes_read == -1) {
-                Error("reading '%s' locally failed: %s", lpath, strerror(errno));
+                Error("reading '%s' locally failed: %s", lpath.c_str(), strerror(errno));
                 return false;
             } else if (bytes_read == 0) {
                 break;
@@ -499,55 +492,53 @@
             RecordBytesTransferred(bytes_read);
             bytes_copied += bytes_read;
 
-            // Check to see if we've received an error from the other side.
-            if (ReceivedError(lpath, rpath)) {
-                break;
-            }
-
             ReportProgress(rpath, bytes_copied, total_size);
         }
 
         syncmsg msg;
         msg.data.id = ID_DONE;
         msg.data.size = mtime;
-        expect_done_ = true;
-
-        // RecordFilesTransferred gets called in CopyDone.
+        RecordFileSent(lpath, rpath);
         return WriteOrDie(lpath, rpath, &msg.data, sizeof(msg.data));
     }
 
-    bool CopyDone(const char* from, const char* to) {
+    bool ReadAcknowledgments() {
+        bool result = true;
+        while (!deferred_acknowledgements_.empty()) {
+            auto [from, to] = std::move(deferred_acknowledgements_.front());
+            deferred_acknowledgements_.pop_front();
+            result &= CopyDone(from, to);
+        }
+        return result;
+    }
+
+    bool CopyDone(const std::string& from, const std::string& to) {
         syncmsg msg;
         if (!ReadFdExactly(fd, &msg.status, sizeof(msg.status))) {
-            Error("failed to copy '%s' to '%s': couldn't read from device", from, to);
+            Error("failed to copy '%s' to '%s': couldn't read from device", from.c_str(),
+                  to.c_str());
             return false;
         }
         if (msg.status.id == ID_OKAY) {
-            if (expect_done_) {
-                expect_done_ = false;
-                RecordFilesTransferred(1);
-                return true;
-            } else {
-                Error("failed to copy '%s' to '%s': received premature success", from, to);
-                return true;
-            }
+            return true;
         }
         if (msg.status.id != ID_FAIL) {
-            Error("failed to copy '%s' to '%s': unknown reason %d", from, to, msg.status.id);
+            Error("failed to copy '%s' to '%s': unknown reason %d", from.c_str(), to.c_str(),
+                  msg.status.id);
             return false;
         }
         return ReportCopyFailure(from, to, msg);
     }
 
-    bool ReportCopyFailure(const char* from, const char* to, const syncmsg& msg) {
+    bool ReportCopyFailure(const std::string& from, const std::string& to, const syncmsg& msg) {
         std::vector<char> buf(msg.status.msglen + 1);
         if (!ReadFdExactly(fd, &buf[0], msg.status.msglen)) {
-            Error("failed to copy '%s' to '%s'; failed to read reason (!): %s",
-                  from, to, strerror(errno));
+            Error("failed to copy '%s' to '%s'; failed to read reason (!): %s", from.c_str(),
+                  to.c_str(), strerror(errno));
             return false;
         }
         buf[msg.status.msglen] = 0;
-        Error("failed to copy '%s' to '%s': remote %s", from, to, &buf[0]);
+        Error("failed to copy '%s' to '%s': remote %s", from.c_str(), to.c_str(), &buf[0]);
         return false;
     }
 
@@ -616,7 +607,7 @@
     size_t max;
 
   private:
-    bool expect_done_;
+    std::deque<std::pair<std::string, std::string>> deferred_acknowledgements_;
     FeatureSet features_;
     bool have_stat_v2_;
     bool have_ls_v2_;
@@ -629,16 +620,19 @@
         return SendRequest(ID_QUIT, ""); // TODO: add a SendResponse?
     }
 
-    bool WriteOrDie(const char* from, const char* to, const void* data, size_t data_length) {
+    bool WriteOrDie(const std::string& from, const std::string& to, const void* data,
+                    size_t data_length) {
         if (!WriteFdExactly(fd, data, data_length)) {
             if (errno == ECONNRESET) {
                 // Assume adbd told us why it was closing the connection, and
                 // try to read failure reason from adbd.
                 syncmsg msg;
                 if (!ReadFdExactly(fd, &msg.status, sizeof(msg.status))) {
-                    Error("failed to copy '%s' to '%s': no response: %s", from, to, strerror(errno));
+                    Error("failed to copy '%s' to '%s': no response: %s", from.c_str(), to.c_str(),
+                          strerror(errno));
                 } else if (msg.status.id != ID_FAIL) {
-                    Error("failed to copy '%s' to '%s': not ID_FAIL: %d", from, to, msg.status.id);
+                    Error("failed to copy '%s' to '%s': not ID_FAIL: %d", from.c_str(), to.c_str(),
+                          msg.status.id);
                 } else {
                     ReportCopyFailure(from, to, msg);
                 }
@@ -651,20 +645,20 @@
     }
 };
 
-static bool sync_ls(SyncConnection& sc, const char* path,
+static bool sync_ls(SyncConnection& sc, const std::string& path,
                     const std::function<sync_ls_cb>& func) {
     return sc.SendLs(path) && sc.FinishLs(func);
 }
 
-static bool sync_stat(SyncConnection& sc, const char* path, struct stat* st) {
+static bool sync_stat(SyncConnection& sc, const std::string& path, struct stat* st) {
     return sc.SendStat(path) && sc.FinishStat(st);
 }
 
-static bool sync_lstat(SyncConnection& sc, const char* path, struct stat* st) {
+static bool sync_lstat(SyncConnection& sc, const std::string& path, struct stat* st) {
     return sc.SendLstat(path) && sc.FinishStat(st);
 }
 
-static bool sync_stat_fallback(SyncConnection& sc, const char* path, struct stat* st) {
+static bool sync_stat_fallback(SyncConnection& sc, const std::string& path, struct stat* st) {
     if (sync_stat(sc, path, st)) {
         return true;
     }
@@ -688,7 +682,7 @@
         struct stat tmp_st;
 
         st->st_mode &= ~S_IFMT;
-        if (sync_lstat(sc, dir_path.c_str(), &tmp_st)) {
+        if (sync_lstat(sc, dir_path, &tmp_st)) {
             st->st_mode |= S_IFDIR;
         } else {
             st->st_mode |= S_IFREG;
@@ -697,10 +691,8 @@
     return true;
 }
 
-static bool sync_send(SyncConnection& sc, const char* lpath, const char* rpath, unsigned mtime,
-                      mode_t mode, bool sync) {
-    std::string path_and_mode = android::base::StringPrintf("%s,%d", rpath, mode);
-
+static bool sync_send(SyncConnection& sc, const std::string& lpath, const std::string& rpath,
+                      unsigned mtime, mode_t mode, bool sync) {
     if (sync) {
         struct stat st;
         if (sync_lstat(sc, rpath, &st)) {
@@ -714,41 +706,40 @@
     if (S_ISLNK(mode)) {
 #if !defined(_WIN32)
         char buf[PATH_MAX];
-        ssize_t data_length = readlink(lpath, buf, PATH_MAX - 1);
+        ssize_t data_length = readlink(lpath.c_str(), buf, PATH_MAX - 1);
         if (data_length == -1) {
-            sc.Error("readlink '%s' failed: %s", lpath, strerror(errno));
+            sc.Error("readlink '%s' failed: %s", lpath.c_str(), strerror(errno));
             return false;
         }
         buf[data_length++] = '\0';
 
-        if (!sc.SendSmallFile(path_and_mode.c_str(), lpath, rpath, mtime, buf, data_length)) {
+        if (!sc.SendSmallFile(rpath, mode, lpath, rpath, mtime, buf, data_length)) {
             return false;
         }
-        return sc.CopyDone(lpath, rpath);
+        return true;
 #endif
     }
 
     struct stat st;
-    if (stat(lpath, &st) == -1) {
-        sc.Error("failed to stat local file '%s': %s", lpath, strerror(errno));
+    if (stat(lpath.c_str(), &st) == -1) {
+        sc.Error("failed to stat local file '%s': %s", lpath.c_str(), strerror(errno));
         return false;
     }
     if (st.st_size < SYNC_DATA_MAX) {
         std::string data;
         if (!android::base::ReadFileToString(lpath, &data, true)) {
-            sc.Error("failed to read all of '%s': %s", lpath, strerror(errno));
+            sc.Error("failed to read all of '%s': %s", lpath.c_str(), strerror(errno));
             return false;
         }
-        if (!sc.SendSmallFile(path_and_mode.c_str(), lpath, rpath, mtime,
-                              data.data(), data.size())) {
+        if (!sc.SendSmallFile(rpath, mode, lpath, rpath, mtime, data.data(), data.size())) {
             return false;
         }
     } else {
-        if (!sc.SendLargeFile(path_and_mode.c_str(), lpath, rpath, mtime)) {
+        if (!sc.SendLargeFile(rpath, mode, lpath, rpath, mtime)) {
             return false;
         }
     }
-    return sc.CopyDone(lpath, rpath);
+    return true;
 }
 
 static bool sync_recv(SyncConnection& sc, const char* rpath, const char* lpath,
@@ -943,7 +934,7 @@
 
     if (check_timestamps) {
         for (const copyinfo& ci : file_list) {
-            if (!sc.SendLstat(ci.rpath.c_str())) {
+            if (!sc.SendLstat(ci.rpath)) {
                 sc.Error("failed to send lstat");
                 return false;
             }
@@ -965,7 +956,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.c_str(), ci.rpath.c_str(), ci.time, ci.mode, false)) {
+                if (!sync_send(sc, ci.lpath, ci.rpath, ci.time, ci.mode, false)) {
                     return false;
                 }
             }
@@ -1069,6 +1060,7 @@
         sc.ReportTransferRate(src_path, TransferDirection::push);
     }
 
+    success &= sc.ReadAcknowledgments();
     sc.ReportOverallTransferRate(TransferDirection::push);
     return success;
 }
diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
index 0a0a21d..d670ca0 100644
--- a/fs_mgr/libsnapshot/Android.bp
+++ b/fs_mgr/libsnapshot/Android.bp
@@ -96,16 +96,6 @@
     static_libs: [
         "libfs_mgr_binder"
     ],
-
-    shared_libs: [
-        // TODO(b/148818798): remove when parent bug is fixed
-        "libutilscallstack",
-    ],
-    cflags: [
-        "-g",
-        "-O0",
-        "-DLIBSNAPSHOT_USE_CALLSTACK",
-    ],
 }
 
 cc_library_static {
@@ -179,9 +169,6 @@
         "libsparse",
         "libutils",
         "libz",
-
-        // TODO(b/148818798): remove when parent bug is fixed
-        "libutilscallstack",
     ],
     static_libs: [
         "libfs_mgr",
@@ -231,8 +218,5 @@
         "libprotobuf-cpp-lite",
         "libstatslog",
         "libutils",
-
-        // TODO(b/148818798): remove when parent bug is fixed.
-        "libutilscallstack",
     ],
 }
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
index 81f616c..68a81ed 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -178,16 +178,6 @@
     UpdateState ProcessUpdateState(const std::function<bool()>& callback = {},
                                    const std::function<bool()>& before_cancel = {});
 
-    // Initiate the merge if necessary, then wait for the merge to finish.
-    // See InitiateMerge() and ProcessUpdateState() for details.
-    // Returns:
-    //   - None if no merge to initiate
-    //   - Unverified if called on the source slot
-    //   - MergeCompleted if merge is completed
-    //   - other states indicating an error has occurred
-    UpdateState InitiateMergeAndWait(SnapshotMergeReport* report = nullptr,
-                                     const std::function<bool()>& before_cancel = {});
-
     // Find the status of the current update, if any.
     //
     // |progress| depends on the returned status:
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index 154b5d7..7e84c48 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -21,7 +21,6 @@
 #include <sys/unistd.h>
 
 #include <optional>
-#include <sstream>
 #include <thread>
 #include <unordered_set>
 
@@ -38,10 +37,6 @@
 #include <libfiemap/image_manager.h>
 #include <liblp/liblp.h>
 
-#ifdef LIBSNAPSHOT_USE_CALLSTACK
-#include <utils/CallStack.h>
-#endif
-
 #include <android/snapshot/snapshot.pb.h>
 #include <libsnapshot/snapshot_stats.h>
 #include "device_info.h"
@@ -228,25 +223,6 @@
 
     LOG(INFO) << "Removing all update state.";
 
-#ifdef LIBSNAPSHOT_USE_CALLSTACK
-    LOG(WARNING) << "Logging stack; see b/148818798.";
-    // Do not use CallStack's log functions because snapshotctl relies on
-    // android-base/logging to save log to files.
-    // TODO(b/148818798): remove this before we ship.
-    CallStack callstack;
-    callstack.update();
-    auto callstack_str = callstack.toString();
-    LOG(WARNING) << callstack_str.c_str();
-    std::stringstream path;
-    path << "/data/misc/snapshotctl_log/libsnapshot." << Now() << ".log";
-    std::string path_str = path.str();
-    android::base::WriteStringToFile(callstack_str.c_str(), path_str);
-    if (chmod(path_str.c_str(), 0644) == -1) {
-        PLOG(WARNING) << "Unable to chmod 0644 "
-                      << ", file maybe dropped from bugreport:" << path_str;
-    }
-#endif
-
     if (!RemoveAllSnapshots(lock)) {
         LOG(ERROR) << "Could not remove all snapshots";
         return false;
@@ -2495,68 +2471,6 @@
     return AutoUnmountDevice::New(device_->GetMetadataDir());
 }
 
-UpdateState SnapshotManager::InitiateMergeAndWait(SnapshotMergeReport* stats_report,
-                                                  const std::function<bool()>& before_cancel) {
-    {
-        auto lock = LockExclusive();
-        // Sync update state from file with bootloader.
-        if (!WriteUpdateState(lock.get(), ReadUpdateState(lock.get()))) {
-            LOG(WARNING) << "Unable to sync write update state, fastboot may "
-                         << "reject / accept wipes incorrectly!";
-        }
-    }
-
-    auto merge_stats = SnapshotMergeStats::GetInstance(*this);
-
-    unsigned int last_progress = 0;
-    auto callback = [&]() -> bool {
-        double progress;
-        GetUpdateState(&progress);
-        if (last_progress < static_cast<unsigned int>(progress)) {
-            last_progress = progress;
-            LOG(INFO) << "Waiting for merge to complete: " << last_progress << "%.";
-        }
-        return true;  // continue
-    };
-
-    LOG(INFO) << "Waiting for any previous merge request to complete. "
-              << "This can take up to several minutes.";
-    merge_stats->Start();
-    auto state = ProcessUpdateState(callback, before_cancel);
-    merge_stats->set_state(state);
-    if (state == UpdateState::None) {
-        LOG(INFO) << "Can't find any snapshot to merge.";
-        return state;
-    }
-    if (state == UpdateState::Unverified) {
-        if (GetCurrentSlot() != Slot::Target) {
-            LOG(INFO) << "Cannot merge until device reboots.";
-            return state;
-        }
-
-        if (!InitiateMerge()) {
-            LOG(ERROR) << "Failed to initiate merge.";
-            return state;
-        }
-        // All other states can be handled by ProcessUpdateState.
-        LOG(INFO) << "Waiting for merge to complete. This can take up to several minutes.";
-        last_progress = 0;
-        state = ProcessUpdateState(callback, before_cancel);
-        merge_stats->set_state(state);
-    }
-
-    LOG(INFO) << "Merge finished with state \"" << state << "\".";
-    if (stats_report) {
-        auto result = merge_stats->Finish();
-        if (result) {
-            *stats_report = result->report();
-        } else {
-            LOG(WARNING) << "SnapshotMergeStatus::Finish failed.";
-        }
-    }
-    return state;
-}
-
 bool SnapshotManager::HandleImminentDataWipe(const std::function<void()>& callback) {
     if (!device_->IsRecovery()) {
         LOG(ERROR) << "Data wipes are only allowed in recovery.";
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index 7d16ec2..855451d 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -1027,7 +1027,8 @@
     }
 
     // Initiate the merge and wait for it to be completed.
-    ASSERT_EQ(UpdateState::MergeCompleted, init->InitiateMergeAndWait());
+    ASSERT_TRUE(init->InitiateMerge());
+    ASSERT_EQ(UpdateState::MergeCompleted, init->ProcessUpdateState());
 
     // Check that the target partitions have the same content after the merge.
     for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
@@ -1201,7 +1202,8 @@
 
     // Initiate the merge and wait for it to be completed.
     auto new_sm = SnapshotManager::New(new TestDeviceInfo(fake_super, "_b"));
-    ASSERT_EQ(UpdateState::MergeCompleted, new_sm->InitiateMergeAndWait());
+    ASSERT_TRUE(new_sm->InitiateMerge());
+    ASSERT_EQ(UpdateState::MergeCompleted, new_sm->ProcessUpdateState());
 
     // Execute the second update.
     ASSERT_TRUE(new_sm->BeginUpdate());
@@ -1341,7 +1343,8 @@
     ASSERT_GE(fd, 0);
 
     // COW cannot be removed due to open fd, so expect a soft failure.
-    ASSERT_EQ(UpdateState::MergeNeedsReboot, init->InitiateMergeAndWait());
+    ASSERT_TRUE(init->InitiateMerge());
+    ASSERT_EQ(UpdateState::MergeNeedsReboot, init->ProcessUpdateState());
 
     // Simulate shutting down the device.
     fd.reset();
@@ -1354,7 +1357,7 @@
     ASSERT_FALSE(sm->IsSnapshotDevice("sys_b", nullptr));
 
     // Merge should be able to complete now.
-    ASSERT_EQ(UpdateState::MergeCompleted, init->InitiateMergeAndWait());
+    ASSERT_EQ(UpdateState::MergeCompleted, init->ProcessUpdateState());
 }
 
 class MetadataMountedTest : public SnapshotUpdateTest {
@@ -1691,7 +1694,8 @@
 
     // There should be no snapshot to merge.
     auto new_sm = SnapshotManager::New(new TestDeviceInfo(fake_super, flashed_slot_suffix));
-    ASSERT_EQ(UpdateState::Cancelled, new_sm->InitiateMergeAndWait());
+    // update_enigne calls ProcessUpdateState first -- should see Cancelled.
+    ASSERT_EQ(UpdateState::Cancelled, new_sm->ProcessUpdateState());
 
     // Next OTA calls CancelUpdate no matter what.
     ASSERT_TRUE(new_sm->CancelUpdate());
diff --git a/fs_mgr/libsnapshot/snapshotctl.cpp b/fs_mgr/libsnapshot/snapshotctl.cpp
index aa5e9c1..a44de84 100644
--- a/fs_mgr/libsnapshot/snapshotctl.cpp
+++ b/fs_mgr/libsnapshot/snapshotctl.cpp
@@ -24,12 +24,8 @@
 #include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/unique_fd.h>
-#include <android/snapshot/snapshot.pb.h>
-#include <libsnapshot/snapshot.h>
-#include <libsnapshot/snapshot_stats.h>
-#include <statslog.h>
 
-#include "utility.h"
+#include <libsnapshot/snapshot.h>
 
 using namespace std::string_literals;
 
@@ -39,146 +35,22 @@
                  "Actions:\n"
                  "  dump\n"
                  "    Print snapshot states.\n"
-                 "  merge [--logcat] [--log-to-file] [--report] [--dry-run]\n"
-                 "    Initialize merge and wait for it to be completed.\n"
-                 "    If --logcat is specified, log to logcat.\n"
-                 "    If --log-to-file is specified, log to /data/misc/snapshotctl_log/.\n"
-                 "    If both specified, log to both. If none specified, log to stdout.\n"
-                 "    If --report is specified, send merge statistics to statsd.\n"
-                 "    If --dry-run flag, no real merge operation is is triggered, and\n"
-                 "      sample statistics are sent to statsd for testing purpose.\n";
+                 "  merge\n"
+                 "    Deprecated.\n";
     return EX_USAGE;
 }
 
 namespace android {
 namespace snapshot {
 
-static SnapshotMergeReport GetDummySnapshotMergeReport() {
-    SnapshotMergeReport fake_report;
-
-    fake_report.set_state(UpdateState::MergeCompleted);
-    fake_report.set_resume_count(56);
-
-    return fake_report;
-}
-
 bool DumpCmdHandler(int /*argc*/, char** argv) {
     android::base::InitLogging(argv, &android::base::StderrLogger);
     return SnapshotManager::New()->Dump(std::cout);
 }
 
-class FileLogger {
-  public:
-    FileLogger() {
-        static constexpr const char* kLogFilePath = "/data/misc/snapshotctl_log/";
-        std::stringstream ss;
-        ss << kLogFilePath << "snapshotctl." << Now() << ".log";
-        fd_.reset(TEMP_FAILURE_RETRY(
-                open(ss.str().c_str(),
-                     O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW | O_SYNC, 0644)));
-        if (fd_ == -1) {
-            PLOG(ERROR) << "Cannot open persistent log " << ss.str();
-            return;
-        }
-        // Explicitly chmod again because mode in open() may be masked by umask.
-        if (fchmod(fd_.get(), 0644) == -1) {
-            PLOG(ERROR) << "Cannot chmod 0644 persistent log " << ss.str();
-            return;
-        }
-    }
-    // Copy-contuctor needed to be converted to std::function.
-    FileLogger(const FileLogger& other) { fd_.reset(dup(other.fd_)); }
-    void operator()(android::base::LogId, android::base::LogSeverity, const char* /*tag*/,
-                    const char* /*file*/, unsigned int /*line*/, const char* message) {
-        if (fd_ == -1) return;
-        std::stringstream ss;
-        ss << Now() << ":" << message << "\n";
-        (void)android::base::WriteStringToFd(ss.str(), fd_);
-    }
-
-  private:
-    android::base::unique_fd fd_;
-};
-
-class MergeCmdLogger {
-  public:
-    MergeCmdLogger(int argc, char** argv) {
-        for (int i = 0; i < argc; ++i) {
-            if (argv[i] == "--logcat"s) {
-                loggers_.push_back(android::base::LogdLogger());
-            }
-            if (argv[i] == "--log-to-file"s) {
-                loggers_.push_back(std::move(FileLogger()));
-            }
-        }
-        if (loggers_.empty()) {
-            loggers_.push_back(&android::base::StdioLogger);
-        }
-    }
-    void operator()(android::base::LogId id, android::base::LogSeverity severity, const char* tag,
-                    const char* file, unsigned int line, const char* message) {
-        for (auto&& logger : loggers_) {
-            logger(id, severity, tag, file, line, message);
-        }
-    }
-
-  private:
-    std::vector<android::base::LogFunction> loggers_;
-};
-
-bool MergeCmdHandler(int argc, char** argv) {
-    std::chrono::milliseconds passed_ms;
-
-    bool report_to_statsd = false;
-    bool dry_run = false;
-    for (int i = 2; i < argc; ++i) {
-        if (argv[i] == "--report"s) {
-            report_to_statsd = true;
-        } else if (argv[i] == "--dry-run"s) {
-            dry_run = true;
-        }
-    }
-
-    // 'snapshotctl merge' is stripped away from arguments to
-    // Logger.
-    android::base::InitLogging(argv);
-    android::base::SetLogger(MergeCmdLogger(argc - 2, argv + 2));
-
-    UpdateState state;
-    SnapshotMergeReport merge_report;
-    if (dry_run) {
-        merge_report = GetDummySnapshotMergeReport();
-        state = merge_report.state();
-        passed_ms = std::chrono::milliseconds(1234);
-    } else {
-        auto begin = std::chrono::steady_clock::now();
-
-        state = SnapshotManager::New()->InitiateMergeAndWait(&merge_report);
-
-        // We could wind up in the Unverified state if the device rolled back or
-        // hasn't fully rebooted. Ignore this.
-        if (state == UpdateState::None || state == UpdateState::Unverified) {
-            return true;
-        }
-
-        auto end = std::chrono::steady_clock::now();
-        passed_ms = std::chrono::duration_cast<std::chrono::milliseconds>(end - begin);
-    }
-
-    if (report_to_statsd) {
-        android::util::stats_write(android::util::SNAPSHOT_MERGE_REPORTED,
-                                   static_cast<int32_t>(merge_report.state()),
-                                   static_cast<int64_t>(passed_ms.count()),
-                                   static_cast<int32_t>(merge_report.resume_count()));
-    }
-
-    if (state == UpdateState::MergeCompleted) {
-        LOG(INFO) << "Snapshot merged in " << passed_ms.count() << " ms.";
-        return true;
-    }
-
-    LOG(ERROR) << "Snapshot failed to merge with state \"" << state << "\".";
-
+bool MergeCmdHandler(int /*argc*/, char** argv) {
+    android::base::InitLogging(argv, &android::base::StderrLogger);
+    LOG(WARNING) << "Deprecated. Call update_engine_client --merge instead.";
     return false;
 }
 
diff --git a/liblog/include/android/log.h b/liblog/include/android/log.h
index c98455d..1c4ec64 100644
--- a/liblog/include/android/log.h
+++ b/liblog/include/android/log.h
@@ -56,6 +56,11 @@
 
 #include <stdarg.h>
 #include <stddef.h>
+#include <sys/cdefs.h>
+
+#if !defined(__BIONIC__) && !defined(__INTRODUCED_IN)
+#define __INTRODUCED_IN(x)
+#endif
 
 #ifdef __cplusplus
 extern "C" {
@@ -191,6 +196,18 @@
 };
 
 /**
+ * Prototype for the 'logger' function that is called for every log message.
+ */
+typedef void (*__android_logger_function)(const struct __android_logger_data* logger_data,
+                                          const char* message);
+/**
+ * Prototype for the 'abort' function that is called when liblog will abort due to
+ * __android_log_assert() failures.
+ */
+typedef void (*__android_aborter_function)(const char* abort_message);
+
+#if __ANDROID_API__ >= 30 || !defined(__ANDROID__)
+/**
  * Writes the log message specified with logger_data and msg to the log.  logger_data includes
  * additional file name and line number information that a logger may use.  logger_data is versioned
  * for backwards compatibility.
@@ -199,54 +216,44 @@
  * buffers, then pass the message to liblog via this function, and therefore we do not want to
  * duplicate the loggability check here.
  */
-void __android_log_write_logger_data(struct __android_logger_data* logger_data, const char* msg);
-
-/**
- * Prototype for the 'logger' function that is called for every log message.
- */
-typedef void (*__android_logger_function)(const struct __android_logger_data* logger_data,
-                                          const char* message);
+void __android_log_write_logger_data(struct __android_logger_data* logger_data, const char* msg)
+    __INTRODUCED_IN(30);
 
 /**
  * Sets a user defined logger function.  All log messages sent to liblog will be set to the
  * function pointer specified by logger for processing.
  */
-void __android_log_set_logger(__android_logger_function logger);
+void __android_log_set_logger(__android_logger_function logger) __INTRODUCED_IN(30);
 
 /**
  * Writes the log message to logd.  This is an __android_logger_function and can be provided to
  * __android_log_set_logger().  It is the default logger when running liblog on a device.
  */
-void __android_log_logd_logger(const struct __android_logger_data* logger_data, const char* msg);
+void __android_log_logd_logger(const struct __android_logger_data* logger_data, const char* msg)
+    __INTRODUCED_IN(30);
 
 /**
  * Writes the log message to stderr.  This is an __android_logger_function and can be provided to
  * __android_log_set_logger().  It is the default logger when running liblog on host.
  */
 void __android_log_stderr_logger(const struct __android_logger_data* logger_data,
-                                 const char* message);
-
-/**
- * Prototype for the 'abort' function that is called when liblog will abort due to
- * __android_log_assert() failures.
- */
-typedef void (*__android_aborter_function)(const char* abort_message);
+                                 const char* message) __INTRODUCED_IN(30);
 
 /**
  * Sets a user defined aborter function that is called for __android_log_assert() failures.
  */
-void __android_log_set_aborter(__android_aborter_function aborter);
+void __android_log_set_aborter(__android_aborter_function aborter) __INTRODUCED_IN(30);
 
 /**
  * Calls the stored aborter function.  This allows for other logging libraries to use the same
  * aborter function by calling this function in liblog.
  */
-void __android_log_call_aborter(const char* abort_message);
+void __android_log_call_aborter(const char* abort_message) __INTRODUCED_IN(30);
 
 /**
  * Sets android_set_abort_message() on device then aborts().  This is the default aborter.
  */
-void __android_log_default_aborter(const char* abort_message);
+void __android_log_default_aborter(const char* abort_message) __INTRODUCED_IN(30);
 
 /**
  * Use the per-tag properties "log.tag.<tagname>" along with the minimum priority from
@@ -260,28 +267,30 @@
  *
  * prio is ANDROID_LOG_VERBOSE to ANDROID_LOG_FATAL.
  */
-int __android_log_is_loggable(int prio, const char* tag, int default_prio);
-int __android_log_is_loggable_len(int prio, const char* tag, size_t len, int default_prio);
+int __android_log_is_loggable(int prio, const char* tag, int default_prio) __INTRODUCED_IN(30);
+int __android_log_is_loggable_len(int prio, const char* tag, size_t len, int default_prio)
+    __INTRODUCED_IN(30);
 
 /**
  * Sets the minimum priority that will be logged for this process.
  *
  * This returns the previous set minimum priority, or ANDROID_LOG_DEFAULT if none was set.
  */
-int __android_log_set_minimum_priority(int priority);
+int __android_log_set_minimum_priority(int priority) __INTRODUCED_IN(30);
 
 /**
  * Gets the minimum priority that will be logged for this process.  If none has been set by a
  * previous __android_log_set_minimum_priority() call, this returns ANDROID_LOG_DEFAULT.
  */
-int __android_log_get_minimum_priority(void);
+int __android_log_get_minimum_priority(void) __INTRODUCED_IN(30);
 
 /**
  * Sets the default tag if no tag is provided when writing a log message.  Defaults to
  * getprogname().  This truncates tag to the maximum log message size, though appropriate tags
  * should be much smaller.
  */
-void __android_log_set_default_tag(const char* tag);
+void __android_log_set_default_tag(const char* tag) __INTRODUCED_IN(30);
+#endif
 
 #ifdef __cplusplus
 }
diff --git a/liblog/logger_write.cpp b/liblog/logger_write.cpp
index cf82e0f..454a13b 100644
--- a/liblog/logger_write.cpp
+++ b/liblog/logger_write.cpp
@@ -27,6 +27,7 @@
 #include <android/set_abort_message.h>
 #endif
 
+#include <atomic>
 #include <shared_mutex>
 
 #include <android-base/errno_restorer.h>
@@ -148,11 +149,9 @@
   GetDefaultTag().assign(tag, 0, LOGGER_ENTRY_MAX_PAYLOAD);
 }
 
-static int minimum_log_priority = ANDROID_LOG_DEFAULT;
+static std::atomic_int minimum_log_priority = ANDROID_LOG_DEFAULT;
 int __android_log_set_minimum_priority(int priority) {
-  int old_minimum_log_priority = minimum_log_priority;
-  minimum_log_priority = priority;
-  return old_minimum_log_priority;
+  return minimum_log_priority.exchange(priority, std::memory_order_relaxed);
 }
 
 int __android_log_get_minimum_priority() {