Merge "better document ifc_{add,del}_address return code"
diff --git a/adb/Android.bp b/adb/Android.bp
index 2f9c8fc..170053b 100644
--- a/adb/Android.bp
+++ b/adb/Android.bp
@@ -422,14 +422,6 @@
         "liblog",
     ],
 
-    product_variables: {
-        debuggable: {
-            required: [
-                "remount",
-            ],
-        },
-    },
-
     target: {
         android: {
             srcs: [
@@ -437,7 +429,6 @@
                 "daemon/framebuffer_service.cpp",
                 "daemon/mdns.cpp",
                 "daemon/reboot_service.cpp",
-                "daemon/remount_service.cpp",
                 "daemon/restart_service.cpp",
                 "daemon/set_verity_enable_state_service.cpp",
             ],
diff --git a/adb/daemon/main.cpp b/adb/daemon/main.cpp
index e5a4917..9ebab74 100644
--- a/adb/daemon/main.cpp
+++ b/adb/daemon/main.cpp
@@ -248,6 +248,12 @@
         prop_port = android::base::GetProperty("persist.adb.tcp.port", "");
     }
 
+#if !defined(__ANDROID__)
+    if (prop_port.empty() && getenv("ADBD_PORT")) {
+        prop_port = getenv("ADBD_PORT");
+    }
+#endif
+
     int port;
     if (sscanf(prop_port.c_str(), "%d", &port) == 1 && port > 0) {
         D("using port=%d", port);
diff --git a/adb/daemon/remount_service.cpp b/adb/daemon/remount_service.cpp
deleted file mode 100644
index 6bd7855..0000000
--- a/adb/daemon/remount_service.cpp
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <errno.h>
-#include <fcntl.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-#include <string>
-
-#include "adb.h"
-#include "adb_io.h"
-#include "adb_unique_fd.h"
-
-static constexpr char kRemountCmd[] = "/system/bin/remount";
-
-static bool do_remount(int fd, const std::string& cmd) {
-    if (getuid() != 0) {
-        WriteFdExactly(fd, "Not running as root. Try \"adb root\" first.\n");
-        return false;
-    }
-
-    auto pid = fork();
-    if (pid < 0) {
-        WriteFdFmt(fd, "Failed to fork to %s: %s\n", kRemountCmd, strerror(errno));
-        return false;
-    }
-
-    if (pid == 0) {
-        // child side of the fork
-        dup2(fd, STDIN_FILENO);
-        dup2(fd, STDOUT_FILENO);
-        dup2(fd, STDERR_FILENO);
-
-        execl(kRemountCmd, kRemountCmd, cmd.empty() ? nullptr : cmd.c_str(), nullptr);
-        const char* msg = "failed to exec remount\n";
-        write(STDERR_FILENO, msg, strlen(msg));
-        _exit(errno);
-    }
-
-    int wstatus = 0;
-    auto ret = waitpid(pid, &wstatus, 0);
-
-    if (ret == -1) {
-        WriteFdFmt(fd, "Failed to wait for %s: %s\n", kRemountCmd, strerror(errno));
-        return false;
-    } else if (ret != pid) {
-        WriteFdFmt(fd, "pid %d and waitpid return %d do not match for %s\n",
-                   static_cast<int>(pid), static_cast<int>(ret), kRemountCmd);
-        return false;
-    }
-
-    if (WIFSIGNALED(wstatus)) {
-        WriteFdFmt(fd, "%s terminated with signal %s\n", kRemountCmd,
-                   strsignal(WTERMSIG(wstatus)));
-        return false;
-    }
-
-    if (!WIFEXITED(wstatus)) {
-        WriteFdFmt(fd, "%s stopped with status 0x%x\n", kRemountCmd, wstatus);
-        return false;
-    }
-
-    if (WEXITSTATUS(wstatus)) {
-        WriteFdFmt(fd, "%s exited with status %d\n", kRemountCmd, WEXITSTATUS(wstatus));
-        return false;
-    }
-
-    return true;
-}
-
-void remount_service(unique_fd fd, const std::string& cmd) {
-    do_remount(fd.get(), cmd);
-    // The remount command will print success or failure for us.
-}
diff --git a/adb/daemon/remount_service.h b/adb/daemon/remount_service.h
deleted file mode 100644
index 522a5da..0000000
--- a/adb/daemon/remount_service.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <string>
-
-#include "adb_unique_fd.h"
-
-#if defined(__ANDROID__)
-void remount_service(unique_fd, const std::string&);
-#endif
diff --git a/adb/daemon/services.cpp b/adb/daemon/services.cpp
index e6f4499..181a8c5 100644
--- a/adb/daemon/services.cpp
+++ b/adb/daemon/services.cpp
@@ -54,7 +54,6 @@
 #include "daemon/file_sync_service.h"
 #include "daemon/framebuffer_service.h"
 #include "daemon/reboot_service.h"
-#include "daemon/remount_service.h"
 #include "daemon/restart_service.h"
 #include "daemon/set_verity_enable_state_service.h"
 #include "daemon/shell_service.h"
@@ -251,9 +250,9 @@
     if (name.starts_with("framebuffer:")) {
         return create_service_thread("fb", framebuffer_service);
     } else if (android::base::ConsumePrefix(&name, "remount:")) {
-        std::string arg(name);
-        return create_service_thread("remount",
-                                     std::bind(remount_service, std::placeholders::_1, arg));
+        std::string cmd = "/system/bin/remount ";
+        cmd += name;
+        return StartSubprocess(cmd, nullptr, SubprocessType::kRaw, SubprocessProtocol::kNone);
     } else if (android::base::ConsumePrefix(&name, "reboot:")) {
         std::string arg(name);
         return create_service_thread("reboot",
diff --git a/debuggerd/client/debuggerd_client_test.cpp b/debuggerd/client/debuggerd_client_test.cpp
index 9c2f0d6..2545cd6 100644
--- a/debuggerd/client/debuggerd_client_test.cpp
+++ b/debuggerd/client/debuggerd_client_test.cpp
@@ -73,15 +73,15 @@
   unique_fd pipe_read, pipe_write;
   ASSERT_TRUE(Pipe(&pipe_read, &pipe_write));
 
-  // 64 kB should be enough for everyone.
+  // 64 MiB should be enough for everyone.
   constexpr int PIPE_SIZE = 64 * 1024 * 1024;
   ASSERT_EQ(PIPE_SIZE, fcntl(pipe_read.get(), F_SETPIPE_SZ, PIPE_SIZE));
 
   // Wait for a bit to let the child spawn all of its threads.
-  std::this_thread::sleep_for(250ms);
+  std::this_thread::sleep_for(1s);
 
   ASSERT_TRUE(
-      debuggerd_trigger_dump(forkpid, kDebuggerdNativeBacktrace, 10000, std::move(pipe_write)));
+      debuggerd_trigger_dump(forkpid, kDebuggerdNativeBacktrace, 60000, std::move(pipe_write)));
   // Immediately kill the forked child, to make sure that the dump didn't return early.
   ASSERT_EQ(0, kill(forkpid, SIGKILL)) << strerror(errno);
 
diff --git a/fs_mgr/liblp/Android.bp b/fs_mgr/liblp/Android.bp
index a7c77b8..ea0fca8 100644
--- a/fs_mgr/liblp/Android.bp
+++ b/fs_mgr/liblp/Android.bp
@@ -100,6 +100,7 @@
     test_suites: ["vts-core"],
     auto_gen_config: true,
     test_min_api_level: 29,
+    require_root: true,
 }
 
 cc_test {
diff --git a/fs_mgr/liblp/builder.cpp b/fs_mgr/liblp/builder.cpp
index 7405039..54350a5 100644
--- a/fs_mgr/liblp/builder.cpp
+++ b/fs_mgr/liblp/builder.cpp
@@ -171,7 +171,8 @@
 std::unique_ptr<MetadataBuilder> MetadataBuilder::NewForUpdate(const IPartitionOpener& opener,
                                                                const std::string& source_partition,
                                                                uint32_t source_slot_number,
-                                                               uint32_t target_slot_number) {
+                                                               uint32_t target_slot_number,
+                                                               bool always_keep_source_slot) {
     auto metadata = ReadMetadata(opener, source_partition, source_slot_number);
     if (!metadata) {
         return nullptr;
@@ -189,7 +190,8 @@
         }
     }
 
-    if (IPropertyFetcher::GetInstance()->GetBoolProperty("ro.virtual_ab.enabled", false)) {
+    if (IPropertyFetcher::GetInstance()->GetBoolProperty("ro.virtual_ab.enabled", false) &&
+        !always_keep_source_slot) {
         if (!UpdateMetadataForInPlaceSnapshot(metadata.get(), source_slot_number,
                                               target_slot_number)) {
             return nullptr;
diff --git a/fs_mgr/liblp/include/liblp/builder.h b/fs_mgr/liblp/include/liblp/builder.h
index b43ccf0..1e9d636 100644
--- a/fs_mgr/liblp/include/liblp/builder.h
+++ b/fs_mgr/liblp/include/liblp/builder.h
@@ -209,10 +209,13 @@
     // metadata may not have the target slot's devices listed yet, in which
     // case, it is automatically upgraded to include all available block
     // devices.
+    // If |always_keep_source_slot| is set, on a Virtual A/B device, source slot
+    // partitions are kept. This is useful when applying a downgrade package.
     static std::unique_ptr<MetadataBuilder> NewForUpdate(const IPartitionOpener& opener,
                                                          const std::string& source_partition,
                                                          uint32_t source_slot_number,
-                                                         uint32_t target_slot_number);
+                                                         uint32_t target_slot_number,
+                                                         bool always_keep_source_slot = false);
 
     // Import an existing table for modification. If the table is not valid, for
     // example it contains duplicate partition names, then nullptr is returned.
diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
index 8cf0f3b..ba43949 100644
--- a/fs_mgr/libsnapshot/Android.bp
+++ b/fs_mgr/libsnapshot/Android.bp
@@ -28,6 +28,7 @@
         "liblp",
     ],
     static_libs: [
+        "libcutils",
         "libdm",
         "libfs_mgr",
         "libfstab",
@@ -56,6 +57,17 @@
     },
 }
 
+cc_defaults {
+    name: "libsnapshot_hal_deps",
+    cflags: [
+        "-DLIBSNAPSHOT_USE_HAL",
+    ],
+    shared_libs: [
+        "android.hardware.boot@1.0",
+        "android.hardware.boot@1.1",
+    ],
+}
+
 filegroup {
     name: "libsnapshot_sources",
     srcs: [
@@ -75,7 +87,10 @@
 
 cc_library_static {
     name: "libsnapshot",
-    defaults: ["libsnapshot_defaults"],
+    defaults: [
+        "libsnapshot_defaults",
+        "libsnapshot_hal_deps",
+    ],
     srcs: [":libsnapshot_sources"],
     whole_static_libs: [
         "libfiemap_binder",
@@ -83,7 +98,7 @@
 }
 
 cc_library_static {
-    name: "libsnapshot_nobinder",
+    name: "libsnapshot_init",
     defaults: ["libsnapshot_defaults"],
     srcs: [":libsnapshot_sources"],
     recovery_available: true,
@@ -92,6 +107,19 @@
     ],
 }
 
+cc_library_static {
+    name: "libsnapshot_nobinder",
+    defaults: [
+        "libsnapshot_defaults",
+        "libsnapshot_hal_deps",
+    ],
+    srcs: [":libsnapshot_sources"],
+    recovery_available: true,
+    whole_static_libs: [
+        "libfiemap_passthrough",
+    ],
+}
+
 cc_test {
     name: "libsnapshot_test",
     defaults: ["libsnapshot_defaults"],
@@ -103,11 +131,13 @@
     ],
     shared_libs: [
         "libbinder",
+        "libhidlbase",
         "libprotobuf-cpp-lite",
         "libutils",
     ],
     static_libs: [
-        "libcutils",
+        "android.hardware.boot@1.0",
+        "android.hardware.boot@1.1",
         "libcrypto_static",
         "libfs_mgr",
         "libgmock",
@@ -134,10 +164,14 @@
         "libsnapshot",
     ],
     shared_libs: [
+        "android.hardware.boot@1.0",
+        "android.hardware.boot@1.1",
         "libbase",
         "libbinder",
+        "libbinderthreadstate",
         "libext4_utils",
         "libfs_mgr",
+        "libhidlbase",
         "liblog",
         "liblp",
         "libprotobuf-cpp-lite",
diff --git a/fs_mgr/libsnapshot/dm_snapshot_internals.h b/fs_mgr/libsnapshot/dm_snapshot_internals.h
new file mode 100644
index 0000000..4903de1
--- /dev/null
+++ b/fs_mgr/libsnapshot/dm_snapshot_internals.h
@@ -0,0 +1,133 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <stdint.h>
+
+#include <vector>
+
+namespace android {
+namespace snapshot {
+
+class DmSnapCowSizeCalculator {
+  public:
+    DmSnapCowSizeCalculator(unsigned int sector_bytes, unsigned int chunk_sectors)
+        : sector_bytes_(sector_bytes),
+          chunk_sectors_(chunk_sectors),
+          exceptions_per_chunk(chunk_sectors_ * sector_bytes_ / (64 * 2 / 8)) {}
+
+    void WriteByte(uint64_t address) { WriteSector(address / sector_bytes_); }
+    void WriteSector(uint64_t sector) { WriteChunk(sector / chunk_sectors_); }
+    void WriteChunk(uint64_t chunk_id) {
+        if (modified_chunks_.size() <= chunk_id) {
+            modified_chunks_.resize(chunk_id + 1, false);
+        }
+        modified_chunks_[chunk_id] = true;
+    }
+
+    uint64_t cow_size_bytes() const { return cow_size_sectors() * sector_bytes_; }
+    uint64_t cow_size_sectors() const { return cow_size_chunks() * chunk_sectors_; }
+
+    /*
+     * The COW device has a precise internal structure as follows:
+     *
+     * - header (1 chunk)
+     * - #0 map and chunks
+     *   - map (1 chunk)
+     *   - chunks addressable by previous map (exceptions_per_chunk)
+     * - #1 map and chunks
+     *   - map (1 chunk)
+     *   - chunks addressable by previous map (exceptions_per_chunk)
+     * ...
+     * - #n: map and chunks
+     *   - map (1 chunk)
+     *   - chunks addressable by previous map (exceptions_per_chunk)
+     * - 1 extra chunk
+     */
+    uint64_t cow_size_chunks() const {
+        uint64_t modified_chunks_count = 0;
+        uint64_t cow_chunks = 0;
+
+        for (const auto& c : modified_chunks_) {
+            if (c) {
+                ++modified_chunks_count;
+            }
+        }
+
+        /* disk header + padding = 1 chunk */
+        cow_chunks += 1;
+
+        /* snapshot modified chunks */
+        cow_chunks += modified_chunks_count;
+
+        /* snapshot chunks index metadata */
+        cow_chunks += 1 + modified_chunks_count / exceptions_per_chunk;
+
+        return cow_chunks;
+    }
+
+  private:
+    /*
+     * Size of each sector in bytes.
+     */
+    const uint64_t sector_bytes_;
+
+    /*
+     * Size of each chunk in sectors.
+     */
+    const uint64_t chunk_sectors_;
+
+    /*
+     * The COW device stores tables to map the modified chunks. Each table
+     * has the size of exactly 1 chunk.
+     * Each row of the table (also called exception in the kernel) contains two
+     * 64 bit indices to identify the corresponding chunk, and this 128 bit row
+     * size is a constant.
+     * The number of exceptions that each table can contain determines the
+     * number of data chunks that separate two consecutive tables. This value
+     * is then fundamental to compute the space overhead introduced by the
+     * tables in COW devices.
+     */
+    const uint64_t exceptions_per_chunk;
+
+    /*
+     * |modified_chunks_| is a container that keeps trace of the modified
+     * chunks.
+     * Multiple options were considered when choosing the most appropriate data
+     * structure for this container. Here follows a summary of why vector<bool>
+     * has been chosen, taking as a reference a snapshot partition of 4 GiB and
+     * chunk size of 4 KiB.
+     * - std::set<uint64_t> is very space-efficient for a small number of
+     *   operations, but if the whole snapshot is changed, it would need to
+     *   store
+     *     4 GiB / 4 KiB * (64 bit / 8) = 8 MiB
+     *   just for the data, plus the additional data overhead for the red-black
+     *   tree used for data sorting (if each rb-tree element stores 3 address
+     *   and the word-aligne color, the total size grows to 32 MiB).
+     * - std::bitset<N> is not a good fit because requires a priori knowledge,
+     *   at compile time, of the bitset size.
+     * - std::vector<bool> is a special case of vector, which uses a data
+     *   compression that allows reducing the space utilization of each element
+     *   to 1 bit. In detail, this data structure is composed of a resizable
+     *   array of words, each of them representing a bitmap. On a 64 bit
+     *   device, modifying the whole 4 GiB snapshot grows this container up to
+     *     4 * GiB / 4 KiB / 64 = 64 KiB
+     *   that, even if is the same space requirement to change a single byte at
+     *   the highest address of the snapshot, is a very affordable space
+     *   requirement.
+     */
+    std::vector<bool> modified_chunks_;
+};
+
+}  // namespace snapshot
+}  // namespace android
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
index 69f2895..fcaa73a 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -49,6 +49,16 @@
 class IPartitionOpener;
 }  // namespace fs_mgr
 
+// Forward declare IBootControl types since we cannot include only the headers
+// with Soong. Note: keep the enum width in sync.
+namespace hardware {
+namespace boot {
+namespace V1_1 {
+enum class MergeStatus : int32_t;
+}  // namespace V1_1
+}  // namespace boot
+}  // namespace hardware
+
 namespace snapshot {
 
 struct AutoDeleteCowImage;
@@ -94,6 +104,7 @@
     using LpMetadata = android::fs_mgr::LpMetadata;
     using MetadataBuilder = android::fs_mgr::MetadataBuilder;
     using DeltaArchiveManifest = chromeos_update_engine::DeltaArchiveManifest;
+    using MergeStatus = android::hardware::boot::V1_1::MergeStatus;
 
   public:
     // Dependency injection for testing.
@@ -107,6 +118,7 @@
         virtual std::string GetSuperDevice(uint32_t slot) const = 0;
         virtual const IPartitionOpener& GetPartitionOpener() const = 0;
         virtual bool IsOverlayfsSetup() const = 0;
+        virtual bool SetBootControlMergeStatus(MergeStatus status) = 0;
     };
 
     ~SnapshotManager();
@@ -208,6 +220,7 @@
     FRIEND_TEST(SnapshotTest, Merge);
     FRIEND_TEST(SnapshotTest, MergeCannotRemoveCow);
     FRIEND_TEST(SnapshotTest, NoMergeBeforeReboot);
+    FRIEND_TEST(SnapshotTest, UpdateBootControlHal);
     FRIEND_TEST(SnapshotUpdateTest, SnapshotStatusFileWithoutCow);
     friend class SnapshotTest;
     friend class SnapshotUpdateTest;
diff --git a/fs_mgr/libsnapshot/partition_cow_creator_test.cpp b/fs_mgr/libsnapshot/partition_cow_creator_test.cpp
index cf2d745..f683f5b 100644
--- a/fs_mgr/libsnapshot/partition_cow_creator_test.cpp
+++ b/fs_mgr/libsnapshot/partition_cow_creator_test.cpp
@@ -17,6 +17,7 @@
 #include <liblp/builder.h>
 #include <liblp/property_fetcher.h>
 
+#include "dm_snapshot_internals.h"
 #include "partition_cow_creator.h"
 #include "test_helpers.h"
 
@@ -99,5 +100,31 @@
     ASSERT_TRUE(ret.has_value());
 }
 
+TEST(DmSnapshotInternals, CowSizeCalculator) {
+    DmSnapCowSizeCalculator cc(512, 8);
+    unsigned long int b;
+
+    // Empty COW
+    ASSERT_EQ(cc.cow_size_sectors(), 16);
+
+    // First chunk written
+    for (b = 0; b < 4_KiB; ++b) {
+        cc.WriteByte(b);
+        ASSERT_EQ(cc.cow_size_sectors(), 24);
+    }
+
+    // Second chunk written
+    for (b = 4_KiB; b < 8_KiB; ++b) {
+        cc.WriteByte(b);
+        ASSERT_EQ(cc.cow_size_sectors(), 32);
+    }
+
+    // Leave a hole and write 5th chunk
+    for (b = 16_KiB; b < 20_KiB; ++b) {
+        cc.WriteByte(b);
+        ASSERT_EQ(cc.cow_size_sectors(), 40);
+    }
+}
+
 }  // namespace snapshot
 }  // namespace android
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index 395fb40..48a94e4 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -29,6 +29,9 @@
 #include <android-base/parseint.h>
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
+#ifdef LIBSNAPSHOT_USE_HAL
+#include <android/hardware/boot/1.1/IBootControl.h>
+#endif
 #include <ext4_utils/ext4_utils.h>
 #include <fs_mgr.h>
 #include <fs_mgr_dm_linear.h>
@@ -63,6 +66,7 @@
 using android::fs_mgr::LpMetadata;
 using android::fs_mgr::MetadataBuilder;
 using android::fs_mgr::SlotNumberForSlotSuffix;
+using android::hardware::boot::V1_1::MergeStatus;
 using chromeos_update_engine::DeltaArchiveManifest;
 using chromeos_update_engine::InstallOperation;
 template <typename T>
@@ -84,11 +88,39 @@
         return fs_mgr_get_super_partition_name(slot);
     }
     bool IsOverlayfsSetup() const override { return fs_mgr_overlayfs_is_setup(); }
+    bool SetBootControlMergeStatus(MergeStatus status) override;
 
   private:
     android::fs_mgr::PartitionOpener opener_;
+#ifdef LIBSNAPSHOT_USE_HAL
+    android::sp<android::hardware::boot::V1_1::IBootControl> boot_control_;
+#endif
 };
 
+bool DeviceInfo::SetBootControlMergeStatus([[maybe_unused]] MergeStatus status) {
+#ifdef LIBSNAPSHOT_USE_HAL
+    if (!boot_control_) {
+        auto hal = android::hardware::boot::V1_0::IBootControl::getService();
+        if (!hal) {
+            LOG(ERROR) << "Could not find IBootControl HAL";
+            return false;
+        }
+        boot_control_ = android::hardware::boot::V1_1::IBootControl::castFrom(hal);
+        if (!boot_control_) {
+            LOG(ERROR) << "Could not find IBootControl 1.1 HAL";
+            return false;
+        }
+    }
+    if (!boot_control_->setSnapshotMergeStatus(status)) {
+        LOG(ERROR) << "Unable to set the snapshot merge status";
+        return false;
+    }
+    return true;
+#else
+    return false;
+#endif
+}
+
 // Note: IImageManager is an incomplete type in the header, so the default
 // destructor doesn't work.
 SnapshotManager::~SnapshotManager() {}
@@ -1590,6 +1622,35 @@
         PLOG(ERROR) << "Could not write to state file";
         return false;
     }
+
+#ifdef LIBSNAPSHOT_USE_HAL
+    auto merge_status = MergeStatus::UNKNOWN;
+    switch (state) {
+        // The needs-reboot and completed cases imply that /data and /metadata
+        // can be safely wiped, so we don't report a merge status.
+        case UpdateState::None:
+        case UpdateState::MergeNeedsReboot:
+        case UpdateState::MergeCompleted:
+            merge_status = MergeStatus::NONE;
+            break;
+        case UpdateState::Initiated:
+        case UpdateState::Unverified:
+            merge_status = MergeStatus::SNAPSHOTTED;
+            break;
+        case UpdateState::Merging:
+        case UpdateState::MergeFailed:
+            merge_status = MergeStatus::MERGING;
+            break;
+        default:
+            // Note that Cancelled flows to here - it is never written, since
+            // it only communicates a transient state to the caller.
+            LOG(ERROR) << "Unexpected update status: " << state;
+            break;
+    }
+    if (!device_->SetBootControlMergeStatus(merge_status)) {
+        return false;
+    }
+#endif
     return true;
 }
 
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index aea12be..a008294 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -617,6 +617,31 @@
     ASSERT_EQ(sm->GetUpdateState(), UpdateState::None);
 }
 
+TEST_F(SnapshotTest, UpdateBootControlHal) {
+    ASSERT_TRUE(AcquireLock());
+
+    ASSERT_TRUE(sm->WriteUpdateState(lock_.get(), UpdateState::None));
+    ASSERT_EQ(test_device->merge_status(), MergeStatus::NONE);
+
+    ASSERT_TRUE(sm->WriteUpdateState(lock_.get(), UpdateState::Initiated));
+    ASSERT_EQ(test_device->merge_status(), MergeStatus::SNAPSHOTTED);
+
+    ASSERT_TRUE(sm->WriteUpdateState(lock_.get(), UpdateState::Unverified));
+    ASSERT_EQ(test_device->merge_status(), MergeStatus::SNAPSHOTTED);
+
+    ASSERT_TRUE(sm->WriteUpdateState(lock_.get(), UpdateState::Merging));
+    ASSERT_EQ(test_device->merge_status(), MergeStatus::MERGING);
+
+    ASSERT_TRUE(sm->WriteUpdateState(lock_.get(), UpdateState::MergeNeedsReboot));
+    ASSERT_EQ(test_device->merge_status(), MergeStatus::NONE);
+
+    ASSERT_TRUE(sm->WriteUpdateState(lock_.get(), UpdateState::MergeCompleted));
+    ASSERT_EQ(test_device->merge_status(), MergeStatus::NONE);
+
+    ASSERT_TRUE(sm->WriteUpdateState(lock_.get(), UpdateState::MergeFailed));
+    ASSERT_EQ(test_device->merge_status(), MergeStatus::MERGING);
+}
+
 class SnapshotUpdateTest : public SnapshotTest {
   public:
     void SetUp() override {
diff --git a/fs_mgr/libsnapshot/test_helpers.h b/fs_mgr/libsnapshot/test_helpers.h
index 769d21e..ea2c5b6 100644
--- a/fs_mgr/libsnapshot/test_helpers.h
+++ b/fs_mgr/libsnapshot/test_helpers.h
@@ -17,6 +17,7 @@
 #include <optional>
 #include <string>
 
+#include <android/hardware/boot/1.1/IBootControl.h>
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 #include <libfiemap/image_manager.h>
@@ -32,6 +33,7 @@
 using android::fs_mgr::IPropertyFetcher;
 using android::fs_mgr::MetadataBuilder;
 using android::fs_mgr::testing::MockPropertyFetcher;
+using android::hardware::boot::V1_1::MergeStatus;
 using chromeos_update_engine::DeltaArchiveManifest;
 using chromeos_update_engine::PartitionUpdate;
 using testing::_;
@@ -81,16 +83,22 @@
     const android::fs_mgr::IPartitionOpener& GetPartitionOpener() const override {
         return *opener_.get();
     }
+    bool SetBootControlMergeStatus(MergeStatus status) override {
+        merge_status_ = status;
+        return true;
+    }
     bool IsOverlayfsSetup() const override { return false; }
 
     void set_slot_suffix(const std::string& suffix) { slot_suffix_ = suffix; }
     void set_fake_super(const std::string& path) {
         opener_ = std::make_unique<TestPartitionOpener>(path);
     }
+    MergeStatus merge_status() const { return merge_status_; }
 
   private:
     std::string slot_suffix_ = "_a";
     std::unique_ptr<TestPartitionOpener> opener_;
+    MergeStatus merge_status_;
 };
 
 class SnapshotTestPropertyFetcher : public android::fs_mgr::testing::MockPropertyFetcher {
diff --git a/init/Android.bp b/init/Android.bp
index 9b2ddc0..ce5b12a 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -69,7 +69,7 @@
         "libprotobuf-cpp-lite",
         "libpropertyinfoserializer",
         "libpropertyinfoparser",
-        "libsnapshot_nobinder",
+        "libsnapshot_init",
     ],
     shared_libs: [
         "libbacktrace",
diff --git a/init/Android.mk b/init/Android.mk
index 8fc44da..4e4c002 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -114,7 +114,7 @@
     libmodprobe \
     libext2_uuid \
     libprotobuf-cpp-lite \
-    libsnapshot_nobinder \
+    libsnapshot_init \
 
 LOCAL_SANITIZE := signed-integer-overflow
 # First stage init is weird: it may start without stdout/stderr, and no /proc.
diff --git a/liblog/include/android/log.h b/liblog/include/android/log.h
index 935590d..2e6210e 100644
--- a/liblog/include/android/log.h
+++ b/liblog/include/android/log.h
@@ -96,20 +96,14 @@
  * [printf(3)](http://man7.org/linux/man-pages/man3/printf.3.html).
  */
 int __android_log_print(int prio, const char* tag, const char* fmt, ...)
-#if defined(__GNUC__)
-    __attribute__((__format__(printf, 3, 4)))
-#endif
-    ;
+    __attribute__((__format__(printf, 3, 4)));
 
 /**
  * Equivalent to `__android_log_print`, but taking a `va_list`.
  * (If `__android_log_print` is like `printf`, this is like `vprintf`.)
  */
 int __android_log_vprint(int prio, const char* tag, const char* fmt, va_list ap)
-#if defined(__GNUC__)
-    __attribute__((__format__(printf, 3, 0)))
-#endif
-    ;
+    __attribute__((__format__(printf, 3, 0)));
 
 /**
  * Writes an assertion failure to the log (as `ANDROID_LOG_FATAL`) and to
@@ -127,13 +121,8 @@
  * including the source filename and line number more conveniently than this
  * function.
  */
-void __android_log_assert(const char* cond, const char* tag, const char* fmt,
-                          ...)
-#if defined(__GNUC__)
-    __attribute__((__noreturn__))
-    __attribute__((__format__(printf, 3, 4)))
-#endif
-    ;
+void __android_log_assert(const char* cond, const char* tag, const char* fmt, ...)
+    __attribute__((__noreturn__)) __attribute__((__format__(printf, 3, 4)));
 
 #ifndef log_id_t_defined
 #define log_id_t_defined
@@ -171,8 +160,7 @@
  *
  * Apps should use __android_log_write() instead.
  */
-int __android_log_buf_write(int bufID, int prio, const char* tag,
-                            const char* text);
+int __android_log_buf_write(int bufID, int prio, const char* tag, const char* text);
 
 /**
  * Writes a formatted string to log buffer `id`,
@@ -182,12 +170,8 @@
  *
  * Apps should use __android_log_print() instead.
  */
-int __android_log_buf_print(int bufID, int prio, const char* tag,
-                            const char* fmt, ...)
-#if defined(__GNUC__)
-    __attribute__((__format__(printf, 4, 5)))
-#endif
-    ;
+int __android_log_buf_print(int bufID, int prio, const char* tag, const char* fmt, ...)
+    __attribute__((__format__(printf, 4, 5)));
 
 #ifdef __cplusplus
 }
diff --git a/liblog/include/log/log_id.h b/liblog/include/log/log_id.h
index c052a50..4c6d809 100644
--- a/liblog/include/log/log_id.h
+++ b/liblog/include/log/log_id.h
@@ -45,12 +45,8 @@
  */
 int __android_log_buf_write(int bufID, int prio, const char* tag,
                             const char* text);
-int __android_log_buf_print(int bufID, int prio, const char* tag,
-                            const char* fmt, ...)
-#if defined(__GNUC__)
-    __attribute__((__format__(printf, 4, 5)))
-#endif
-    ;
+int __android_log_buf_print(int bufID, int prio, const char* tag, const char* fmt, ...)
+    __attribute__((__format__(printf, 4, 5)));
 
 /*
  * log_id_t helpers
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index 5241730..e1bb02f 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -326,7 +326,7 @@
 LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)
 LOCAL_MODULE_STEM := $(call append_vndk_version,$(LOCAL_MODULE))
 include $(BUILD_SYSTEM)/base_rules.mk
-$(LOCAL_BUILT_MODULE): PRIVATE_VNDK_SAMEPROCESS_LIBRARIES := $(call module-installed-files-or-guess,$(VNDK_SAMEPROCESS_LIBRARIES),.com.android.vndk.current)
+$(LOCAL_BUILT_MODULE): PRIVATE_VNDK_SAMEPROCESS_LIBRARIES := $(call module-installed-files-or-guess,$(VNDK_SAMEPROCESS_LIBRARIES),.vendor)
 $(LOCAL_BUILT_MODULE):
 	@echo "Generate: $@"
 	@mkdir -p $(dir $@)
@@ -342,7 +342,7 @@
 LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)
 LOCAL_MODULE_STEM := $(call append_vndk_version,$(LOCAL_MODULE))
 include $(BUILD_SYSTEM)/base_rules.mk
-$(LOCAL_BUILT_MODULE): PRIVATE_VNDK_CORE_LIBRARIES := $(call module-installed-files-or-guess,$(VNDK_CORE_LIBRARIES),.com.android.vndk.current)
+$(LOCAL_BUILT_MODULE): PRIVATE_VNDK_CORE_LIBRARIES := $(call module-installed-files-or-guess,$(VNDK_CORE_LIBRARIES),.vendor)
 $(LOCAL_BUILT_MODULE):
 	@echo "Generate: $@"
 	@mkdir -p $(dir $@)
@@ -358,7 +358,7 @@
 LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)
 LOCAL_MODULE_STEM := $(call append_vndk_version,$(LOCAL_MODULE))
 include $(BUILD_SYSTEM)/base_rules.mk
-$(LOCAL_BUILT_MODULE): PRIVATE_VNDK_PRIVATE_LIBRARIES := $(call module-installed-files-or-guess,$(VNDK_PRIVATE_LIBRARIES),.com.android.vndk.current)
+$(LOCAL_BUILT_MODULE): PRIVATE_VNDK_PRIVATE_LIBRARIES := $(call module-installed-files-or-guess,$(VNDK_PRIVATE_LIBRARIES),.vendor)
 $(LOCAL_BUILT_MODULE):
 	@echo "Generate: $@"
 	@mkdir -p $(dir $@)