Merge "Skip QD1A.190821.011 in stage-aosp-master" into stage-aosp-master
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/adb/fastdeploy/Android.bp b/adb/fastdeploy/Android.bp
index 245d52a..f5893aa 100644
--- a/adb/fastdeploy/Android.bp
+++ b/adb/fastdeploy/Android.bp
@@ -27,6 +27,7 @@
 
 java_binary {
     name: "deployagent",
+    sdk_version: "24",
     static_libs: [
         "deployagent_lib",
     ],
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/fastboot/device/commands.h b/fastboot/device/commands.h
index afd6d08..9b6e7b6 100644
--- a/fastboot/device/commands.h
+++ b/fastboot/device/commands.h
@@ -19,7 +19,7 @@
 #include <string>
 #include <vector>
 
-constexpr unsigned int kMaxDownloadSizeDefault = 0x20000000;
+constexpr unsigned int kMaxDownloadSizeDefault = 0x10000000;
 
 class FastbootDevice;
 
diff --git a/fs_mgr/libdm/Android.bp b/fs_mgr/libdm/Android.bp
index 3ce909e..8a924d5 100644
--- a/fs_mgr/libdm/Android.bp
+++ b/fs_mgr/libdm/Android.bp
@@ -81,7 +81,7 @@
 }
 
 cc_fuzz {
-  name: "dm_table_fuzzer",
+  name: "dm_linear_table_fuzzer",
   defaults: ["fs_mgr_defaults"],
   srcs: [
     "dm_linear_fuzzer.cpp",
diff --git a/fs_mgr/libdm/dm_linear_fuzzer.cpp b/fs_mgr/libdm/dm_linear_fuzzer.cpp
index b119635..8462901 100644
--- a/fs_mgr/libdm/dm_linear_fuzzer.cpp
+++ b/fs_mgr/libdm/dm_linear_fuzzer.cpp
@@ -76,7 +76,7 @@
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
     uint64_t val[6];
 
-    if (size != sizeof(*val)) {
+    if (size != sizeof(val)) {
         return 0;
     }
 
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..9256a16 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,12 +131,14 @@
     ],
     shared_libs: [
         "libbinder",
+        "libcrypto",
+        "libhidlbase",
         "libprotobuf-cpp-lite",
         "libutils",
     ],
     static_libs: [
-        "libcutils",
-        "libcrypto_static",
+        "android.hardware.boot@1.0",
+        "android.hardware.boot@1.1",
         "libfs_mgr",
         "libgmock",
         "liblp",
@@ -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..120340c 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -19,6 +19,7 @@
 #include <chrono>
 #include <map>
 #include <memory>
+#include <optional>
 #include <ostream>
 #include <string>
 #include <string_view>
@@ -49,6 +50,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 +105,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 +119,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 +221,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;
@@ -285,7 +299,8 @@
                      std::string* dev_path);
 
     // Map a COW image that was previous created with CreateCowImage.
-    bool MapCowImage(const std::string& name, const std::chrono::milliseconds& timeout_ms);
+    std::optional<std::string> MapCowImage(const std::string& name,
+                                           const std::chrono::milliseconds& timeout_ms);
 
     // Remove the backing copy-on-write image and snapshot states for the named snapshot. The
     // caller is responsible for ensuring that the snapshot is unmapped.
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..2c5eed1 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() {}
@@ -418,9 +450,9 @@
     return true;
 }
 
-bool SnapshotManager::MapCowImage(const std::string& name,
-                                  const std::chrono::milliseconds& timeout_ms) {
-    if (!EnsureImageManager()) return false;
+std::optional<std::string> SnapshotManager::MapCowImage(
+        const std::string& name, const std::chrono::milliseconds& timeout_ms) {
+    if (!EnsureImageManager()) return std::nullopt;
     auto cow_image_name = GetCowImageDeviceName(name);
 
     bool ok;
@@ -436,10 +468,10 @@
 
     if (ok) {
         LOG(INFO) << "Mapped " << cow_image_name << " to " << cow_dev;
-    } else {
-        LOG(ERROR) << "Could not map image device: " << cow_image_name;
+        return cow_dev;
     }
-    return ok;
+    LOG(ERROR) << "Could not map image device: " << cow_image_name;
+    return std::nullopt;
 }
 
 bool SnapshotManager::UnmapSnapshot(LockedFile* lock, const std::string& name) {
@@ -1411,7 +1443,7 @@
         auto remaining_time = GetRemainingTime(params.timeout_ms, begin);
         if (remaining_time.count() < 0) return false;
 
-        if (!MapCowImage(partition_name, remaining_time)) {
+        if (!MapCowImage(partition_name, remaining_time).has_value()) {
             LOG(ERROR) << "Could not map cow image for partition: " << partition_name;
             return false;
         }
@@ -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..f6a4722 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -254,12 +254,11 @@
 
     AssertionResult MapCowImage(const std::string& name,
                                 const std::chrono::milliseconds& timeout_ms, std::string* path) {
-        if (!sm->MapCowImage(name, timeout_ms)) {
+        auto cow_image_path = sm->MapCowImage(name, timeout_ms);
+        if (!cow_image_path.has_value()) {
             return AssertionFailure() << "Cannot map cow image " << name;
         }
-        if (!dm_.GetDmDevicePathByName(name + "-cow-img"s, path)) {
-            return AssertionFailure() << "No path for " << name << "-cow-img";
-        }
+        *path = *cow_image_path;
         return AssertionSuccess();
     }
 
@@ -617,6 +616,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/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp
index 06c8176..57ed362 100644
--- a/healthd/BatteryMonitor.cpp
+++ b/healthd/BatteryMonitor.cpp
@@ -200,9 +200,7 @@
     return value;
 }
 
-bool BatteryMonitor::update(void) {
-    bool logthis;
-
+void BatteryMonitor::updateValues(void) {
     initBatteryProperties(&props);
 
     if (!mHealthdConfig->batteryPresentPath.isEmpty())
@@ -289,50 +287,44 @@
             }
         }
     }
+}
 
-    logthis = !healthd_board_battery_update(&props);
+void BatteryMonitor::logValues(void) {
+    char dmesgline[256];
+    size_t len;
+    if (props.batteryPresent) {
+        snprintf(dmesgline, sizeof(dmesgline), "battery l=%d v=%d t=%s%d.%d h=%d st=%d",
+                 props.batteryLevel, props.batteryVoltage, props.batteryTemperature < 0 ? "-" : "",
+                 abs(props.batteryTemperature / 10), abs(props.batteryTemperature % 10),
+                 props.batteryHealth, props.batteryStatus);
 
-    if (logthis) {
-        char dmesgline[256];
-        size_t len;
-        if (props.batteryPresent) {
-            snprintf(dmesgline, sizeof(dmesgline),
-                 "battery l=%d v=%d t=%s%d.%d h=%d st=%d",
-                 props.batteryLevel, props.batteryVoltage,
-                 props.batteryTemperature < 0 ? "-" : "",
-                 abs(props.batteryTemperature / 10),
-                 abs(props.batteryTemperature % 10), props.batteryHealth,
-                 props.batteryStatus);
-
-            len = strlen(dmesgline);
-            if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
-                len += snprintf(dmesgline + len, sizeof(dmesgline) - len,
-                                " c=%d", props.batteryCurrent);
-            }
-
-            if (!mHealthdConfig->batteryFullChargePath.isEmpty()) {
-                len += snprintf(dmesgline + len, sizeof(dmesgline) - len,
-                                " fc=%d", props.batteryFullCharge);
-            }
-
-            if (!mHealthdConfig->batteryCycleCountPath.isEmpty()) {
-                len += snprintf(dmesgline + len, sizeof(dmesgline) - len,
-                                " cc=%d", props.batteryCycleCount);
-            }
-        } else {
-            len = snprintf(dmesgline, sizeof(dmesgline),
-                 "battery none");
+        len = strlen(dmesgline);
+        if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
+            len += snprintf(dmesgline + len, sizeof(dmesgline) - len, " c=%d",
+                            props.batteryCurrent);
         }
 
-        snprintf(dmesgline + len, sizeof(dmesgline) - len, " chg=%s%s%s",
-                 props.chargerAcOnline ? "a" : "",
-                 props.chargerUsbOnline ? "u" : "",
-                 props.chargerWirelessOnline ? "w" : "");
+        if (!mHealthdConfig->batteryFullChargePath.isEmpty()) {
+            len += snprintf(dmesgline + len, sizeof(dmesgline) - len, " fc=%d",
+                            props.batteryFullCharge);
+        }
 
-        KLOG_WARNING(LOG_TAG, "%s\n", dmesgline);
+        if (!mHealthdConfig->batteryCycleCountPath.isEmpty()) {
+            len += snprintf(dmesgline + len, sizeof(dmesgline) - len, " cc=%d",
+                            props.batteryCycleCount);
+        }
+    } else {
+        len = snprintf(dmesgline, sizeof(dmesgline), "battery none");
     }
 
-    healthd_mode_ops->battery_update(&props);
+    snprintf(dmesgline + len, sizeof(dmesgline) - len, " chg=%s%s%s",
+             props.chargerAcOnline ? "a" : "", props.chargerUsbOnline ? "u" : "",
+             props.chargerWirelessOnline ? "w" : "");
+
+    KLOG_WARNING(LOG_TAG, "%s\n", dmesgline);
+}
+
+bool BatteryMonitor::isChargerOnline() {
     return props.chargerAcOnline | props.chargerUsbOnline |
             props.chargerWirelessOnline;
 }
diff --git a/healthd/include/healthd/BatteryMonitor.h b/healthd/include/healthd/BatteryMonitor.h
index 4d1d53f..0fd3824 100644
--- a/healthd/include/healthd/BatteryMonitor.h
+++ b/healthd/include/healthd/BatteryMonitor.h
@@ -38,12 +38,15 @@
 
     BatteryMonitor();
     void init(struct healthd_config *hc);
-    bool update(void);
     int getChargeStatus();
     status_t getProperty(int id, struct BatteryProperty *val);
     void dumpState(int fd);
     friend struct BatteryProperties getBatteryProperties(BatteryMonitor* batteryMonitor);
 
+    void updateValues(void);
+    void logValues(void);
+    bool isChargerOnline();
+
   private:
     struct healthd_config *mHealthdConfig;
     Vector<String8> mChargerNames;
diff --git a/init/Android.bp b/init/Android.bp
index 9b2ddc0..bd2d38c 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",
@@ -82,7 +82,6 @@
         "libfscrypt",
         "libgsi",
         "libhidl-gen-utils",
-        "libjsoncpp",
         "libkeyutils",
         "liblog",
         "liblogwrap",
@@ -286,13 +285,11 @@
     shared_libs: [
         "libcutils",
         "libhidl-gen-utils",
+        "libhidlmetadata",
         "liblog",
         "libprocessgroup",
         "libprotobuf-cpp-lite",
     ],
-    header_libs: [
-        "libjsoncpp_headers",
-    ],
     srcs: [
         "action.cpp",
         "action_manager.cpp",
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/init/host_init_verifier.cpp b/init/host_init_verifier.cpp
index b2402b3..522709e 100644
--- a/init/host_init_verifier.cpp
+++ b/init/host_init_verifier.cpp
@@ -30,6 +30,7 @@
 #include <android-base/logging.h>
 #include <android-base/parseint.h>
 #include <android-base/strings.h>
+#include <hidl/metadata.h>
 
 #include "action.h"
 #include "action_manager.h"
@@ -142,28 +143,46 @@
 #include "generated_stub_builtin_function_map.h"
 
 void PrintUsage() {
-    std::cout << "usage: host_init_verifier [-p FILE] -i FILE <init rc file>\n"
+    std::cout << "usage: host_init_verifier [-p FILE] <init rc file>\n"
                  "\n"
                  "Tests an init script for correctness\n"
                  "\n"
                  "-p FILE\tSearch this passwd file for users and groups\n"
-                 "-i FILE\tParse this JSON file for the HIDL interface inheritance hierarchy\n"
               << std::endl;
 }
 
+Result<InterfaceInheritanceHierarchyMap> ReadInterfaceInheritanceHierarchy() {
+    InterfaceInheritanceHierarchyMap result;
+    for (const HidlInterfaceMetadata& iface : HidlInterfaceMetadata::all()) {
+        std::set<FQName> inherited_interfaces;
+        for (const std::string& intf : iface.inherited) {
+            FQName fqname;
+            if (!fqname.setTo(intf)) {
+                return Error() << "Unable to parse interface '" << intf << "'";
+            }
+            inherited_interfaces.insert(fqname);
+        }
+        FQName fqname;
+        if (!fqname.setTo(iface.name)) {
+            return Error() << "Unable to parse interface '" << iface.name << "'";
+        }
+        result[fqname] = inherited_interfaces;
+    }
+
+    return result;
+}
+
 int main(int argc, char** argv) {
     android::base::InitLogging(argv, &android::base::StdioLogger);
     android::base::SetMinimumLogSeverity(android::base::ERROR);
 
-    std::string interface_inheritance_hierarchy_file;
-
     while (true) {
         static const struct option long_options[] = {
                 {"help", no_argument, nullptr, 'h'},
                 {nullptr, 0, nullptr, 0},
         };
 
-        int arg = getopt_long(argc, argv, "p:i:", long_options, nullptr);
+        int arg = getopt_long(argc, argv, "p:", long_options, nullptr);
 
         if (arg == -1) {
             break;
@@ -176,9 +195,6 @@
             case 'p':
                 passwd_files.emplace_back(optarg);
                 break;
-            case 'i':
-                interface_inheritance_hierarchy_file = optarg;
-                break;
             default:
                 std::cerr << "getprop: getopt returned invalid result: " << arg << std::endl;
                 return EXIT_FAILURE;
@@ -188,13 +204,12 @@
     argc -= optind;
     argv += optind;
 
-    if (argc != 1 || interface_inheritance_hierarchy_file.empty()) {
+    if (argc != 1) {
         PrintUsage();
         return EXIT_FAILURE;
     }
 
-    auto interface_inheritance_hierarchy_map =
-            ReadInterfaceInheritanceHierarchy(interface_inheritance_hierarchy_file);
+    auto interface_inheritance_hierarchy_map = ReadInterfaceInheritanceHierarchy();
     if (!interface_inheritance_hierarchy_map) {
         LOG(ERROR) << interface_inheritance_hierarchy_map.error();
         return EXIT_FAILURE;
diff --git a/init/interface_utils.cpp b/init/interface_utils.cpp
index ddbacd7..1b76bba 100644
--- a/init/interface_utils.cpp
+++ b/init/interface_utils.cpp
@@ -21,7 +21,6 @@
 
 #include <android-base/strings.h>
 #include <hidl-util/FqInstance.h>
-#include <json/json.h>
 
 using android::FqInstance;
 using android::FQName;
@@ -42,37 +41,6 @@
 
 }  // namespace
 
-Result<InterfaceInheritanceHierarchyMap> ReadInterfaceInheritanceHierarchy(
-        const std::string& path) {
-    Json::Value root;
-    Json::Reader reader;
-    std::ifstream stream(path);
-    if (!reader.parse(stream, root)) {
-        return Error() << "Failed to read interface inheritance hierarchy file: " << path << "\n"
-                       << reader.getFormattedErrorMessages();
-    }
-
-    InterfaceInheritanceHierarchyMap result;
-    for (const Json::Value& entry : root) {
-        std::set<FQName> inherited_interfaces;
-        for (const Json::Value& intf : entry["inheritedInterfaces"]) {
-            FQName fqname;
-            if (!fqname.setTo(intf.asString())) {
-                return Error() << "Unable to parse interface '" << intf.asString() << "'";
-            }
-            inherited_interfaces.insert(fqname);
-        }
-        std::string intf_string = entry["interface"].asString();
-        FQName fqname;
-        if (!fqname.setTo(intf_string)) {
-            return Error() << "Unable to parse interface '" << intf_string << "'";
-        }
-        result[fqname] = inherited_interfaces;
-    }
-
-    return result;
-}
-
 Result<void> CheckInterfaceInheritanceHierarchy(const std::set<std::string>& instances,
                                                 const InterfaceInheritanceHierarchyMap& hierarchy) {
     std::set<FQName> interface_fqnames;
diff --git a/init/interface_utils.h b/init/interface_utils.h
index bd0c104..4ca377f 100644
--- a/init/interface_utils.h
+++ b/init/interface_utils.h
@@ -29,9 +29,6 @@
 
 using InterfaceInheritanceHierarchyMap = std::map<android::FQName, std::set<android::FQName>>;
 
-// Reads the HIDL interface inheritance hierarchy JSON file at the given path.
-Result<InterfaceInheritanceHierarchyMap> ReadInterfaceInheritanceHierarchy(const std::string& path);
-
 // For the given set of interfaces / interface instances, checks that each
 // interface's hierarchy of inherited interfaces is also included in the given
 // interface set. Uses the provided hierarchy data.
diff --git a/init/property_service.cpp b/init/property_service.cpp
index c6bbc14..3baaf7c 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -404,7 +404,7 @@
     // We must release the fd before sending it to init, otherwise there will be a race with init.
     // If init calls close() before Release(), then fdsan will see the wrong tag and abort().
     int fd = -1;
-    if (socket != nullptr) {
+    if (socket != nullptr && SelinuxGetVendorAndroidVersion() > __ANDROID_API_Q__) {
         fd = socket->Release();
         control_message->set_fd(fd);
     }
diff --git a/liblog/include/android/log.h b/liblog/include/android/log.h
index 935590d..7290789 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,16 +121,9 @@
  * 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
 /**
  * Identifies a specific log buffer for __android_log_buf_write()
  * and __android_log_buf_print().
@@ -163,7 +150,6 @@
 
   LOG_ID_MAX
 } log_id_t;
-#endif
 
 /**
  * Writes the constant string `text` to the log buffer `id`,
@@ -171,8 +157,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 +167,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..c8fafe7 100644
--- a/liblog/include/log/log_id.h
+++ b/liblog/include/log/log_id.h
@@ -16,41 +16,19 @@
 
 #pragma once
 
+#include <android/log.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-#ifndef log_id_t_defined
-#define log_id_t_defined
-typedef enum log_id {
-  LOG_ID_MIN = 0,
-
-  LOG_ID_MAIN = 0,
-  LOG_ID_RADIO = 1,
-  LOG_ID_EVENTS = 2,
-  LOG_ID_SYSTEM = 3,
-  LOG_ID_CRASH = 4,
-  LOG_ID_STATS = 5,
-  LOG_ID_SECURITY = 6,
-  LOG_ID_KERNEL = 7, /* place last, third-parties can not use it */
-
-  LOG_ID_MAX
-} log_id_t;
-#endif
-#define sizeof_log_id_t sizeof(typeof_log_id_t)
-#define typeof_log_id_t unsigned char
-
 /*
  * Send a simple string to the log.
  */
 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/liblog/include/private/android_logger.h b/liblog/include/private/android_logger.h
index d3cb571..d3b72bc 100644
--- a/liblog/include/private/android_logger.h
+++ b/liblog/include/private/android_logger.h
@@ -47,7 +47,7 @@
 
 /* Header Structure to logd, and second header for pstore */
 typedef struct __attribute__((__packed__)) {
-  typeof_log_id_t id;
+  uint8_t id;
   uint16_t tid;
   log_time realtime;
 } android_log_header_t;
diff --git a/libnetutils/ifc_utils.c b/libnetutils/ifc_utils.c
index a098d59..6af49bb 100644
--- a/libnetutils/ifc_utils.c
+++ b/libnetutils/ifc_utils.c
@@ -362,10 +362,12 @@
     return err->error;
 }
 
+// Returns zero on success and negative errno on failure.
 int ifc_add_address(const char *name, const char *address, int prefixlen) {
     return ifc_act_on_address(RTM_NEWADDR, name, address, prefixlen);
 }
 
+// Returns zero on success and negative errno on failure.
 int ifc_del_address(const char *name, const char * address, int prefixlen) {
     return ifc_act_on_address(RTM_DELADDR, name, address, prefixlen);
 }
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index b0f3786..2573b1c 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -239,6 +239,7 @@
         "tests/files/offline/bad_eh_frame_hdr_arm64/*",
         "tests/files/offline/debug_frame_first_x86/*",
         "tests/files/offline/debug_frame_load_bias_arm/*",
+        "tests/files/offline/eh_frame_bias_x86/*",
         "tests/files/offline/eh_frame_hdr_begin_x86_64/*",
         "tests/files/offline/invalid_elf_offset_arm/*",
         "tests/files/offline/jit_debug_arm/*",
diff --git a/libunwindstack/ElfInterface.cpp b/libunwindstack/ElfInterface.cpp
index e34273c..e863f22 100644
--- a/libunwindstack/ElfInterface.cpp
+++ b/libunwindstack/ElfInterface.cpp
@@ -228,7 +228,7 @@
     case PT_GNU_EH_FRAME:
       // This is really the pointer to the .eh_frame_hdr section.
       eh_frame_hdr_offset_ = phdr.p_offset;
-      eh_frame_hdr_section_bias_ = static_cast<uint64_t>(phdr.p_paddr) - phdr.p_offset;
+      eh_frame_hdr_section_bias_ = static_cast<uint64_t>(phdr.p_vaddr) - phdr.p_offset;
       eh_frame_hdr_size_ = phdr.p_memsz;
       break;
 
diff --git a/libunwindstack/tests/ElfInterfaceTest.cpp b/libunwindstack/tests/ElfInterfaceTest.cpp
index b048b17..ea27e3e 100644
--- a/libunwindstack/tests/ElfInterfaceTest.cpp
+++ b/libunwindstack/tests/ElfInterfaceTest.cpp
@@ -1310,7 +1310,7 @@
 
   memset(&phdr, 0, sizeof(phdr));
   phdr.p_type = PT_GNU_EH_FRAME;
-  phdr.p_paddr = addr;
+  phdr.p_vaddr = addr;
   phdr.p_offset = offset;
   memory_.SetMemory(phdr_offset, &phdr, sizeof(phdr));
 
diff --git a/libunwindstack/tests/UnwindOfflineTest.cpp b/libunwindstack/tests/UnwindOfflineTest.cpp
index 72eef3e..0d58c09 100644
--- a/libunwindstack/tests/UnwindOfflineTest.cpp
+++ b/libunwindstack/tests/UnwindOfflineTest.cpp
@@ -1583,4 +1583,50 @@
   EXPECT_EQ(0x7fdd4a4170ULL, unwinder.frames()[11].sp);
 }
 
+TEST_F(UnwindOfflineTest, eh_frame_bias_x86) {
+  ASSERT_NO_FATAL_FAILURE(Init("eh_frame_bias_x86/", ARCH_X86));
+
+  Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
+  unwinder.Unwind();
+
+  std::string frame_info(DumpFrames(unwinder));
+  ASSERT_EQ(11U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
+  EXPECT_EQ(
+      "  #00 pc ffffe430  vdso.so (__kernel_vsyscall+16)\n"
+      "  #01 pc 00082a4b  libc.so (__epoll_pwait+43)\n"
+      "  #02 pc 000303a3  libc.so (epoll_pwait+115)\n"
+      "  #03 pc 000303ed  libc.so (epoll_wait+45)\n"
+      "  #04 pc 00010ea2  tombstoned (epoll_dispatch+226)\n"
+      "  #05 pc 0000c5e7  tombstoned (event_base_loop+1095)\n"
+      "  #06 pc 0000c193  tombstoned (event_base_dispatch+35)\n"
+      "  #07 pc 00005c77  tombstoned (main+884)\n"
+      "  #08 pc 00015f66  libc.so (__libc_init+102)\n"
+      "  #09 pc 0000360e  tombstoned (_start+98)\n"
+      "  #10 pc 00000001  <unknown>\n",
+      frame_info);
+
+  EXPECT_EQ(0xffffe430ULL, unwinder.frames()[0].pc);
+  EXPECT_EQ(0xfffe1a30ULL, unwinder.frames()[0].sp);
+  EXPECT_EQ(0xeb585a4bULL, unwinder.frames()[1].pc);
+  EXPECT_EQ(0xfffe1a40ULL, unwinder.frames()[1].sp);
+  EXPECT_EQ(0xeb5333a3ULL, unwinder.frames()[2].pc);
+  EXPECT_EQ(0xfffe1a60ULL, unwinder.frames()[2].sp);
+  EXPECT_EQ(0xeb5333edULL, unwinder.frames()[3].pc);
+  EXPECT_EQ(0xfffe1ab0ULL, unwinder.frames()[3].sp);
+  EXPECT_EQ(0xeb841ea2ULL, unwinder.frames()[4].pc);
+  EXPECT_EQ(0xfffe1ae0ULL, unwinder.frames()[4].sp);
+  EXPECT_EQ(0xeb83d5e7ULL, unwinder.frames()[5].pc);
+  EXPECT_EQ(0xfffe1b30ULL, unwinder.frames()[5].sp);
+  EXPECT_EQ(0xeb83d193ULL, unwinder.frames()[6].pc);
+  EXPECT_EQ(0xfffe1bd0ULL, unwinder.frames()[6].sp);
+  EXPECT_EQ(0xeb836c77ULL, unwinder.frames()[7].pc);
+  EXPECT_EQ(0xfffe1c00ULL, unwinder.frames()[7].sp);
+  EXPECT_EQ(0xeb518f66ULL, unwinder.frames()[8].pc);
+  EXPECT_EQ(0xfffe1d00ULL, unwinder.frames()[8].sp);
+  EXPECT_EQ(0xeb83460eULL, unwinder.frames()[9].pc);
+  EXPECT_EQ(0xfffe1d40ULL, unwinder.frames()[9].sp);
+  EXPECT_EQ(0x00000001ULL, unwinder.frames()[10].pc);
+  EXPECT_EQ(0xfffe1d74ULL, unwinder.frames()[10].sp);
+}
+
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/files/offline/eh_frame_bias_x86/libc.so b/libunwindstack/tests/files/offline/eh_frame_bias_x86/libc.so
new file mode 100644
index 0000000..f3eb615
--- /dev/null
+++ b/libunwindstack/tests/files/offline/eh_frame_bias_x86/libc.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/eh_frame_bias_x86/maps.txt b/libunwindstack/tests/files/offline/eh_frame_bias_x86/maps.txt
new file mode 100644
index 0000000..7d52483
--- /dev/null
+++ b/libunwindstack/tests/files/offline/eh_frame_bias_x86/maps.txt
@@ -0,0 +1,3 @@
+eb503000-eb5e8000 r-xp 0 00:00 0   libc.so
+eb831000-eb852000 r-xp 0 00:00 0   tombstoned
+ffffe000-fffff000 r-xp 0 00:00 0   vdso.so
diff --git a/libunwindstack/tests/files/offline/eh_frame_bias_x86/regs.txt b/libunwindstack/tests/files/offline/eh_frame_bias_x86/regs.txt
new file mode 100644
index 0000000..821928e
--- /dev/null
+++ b/libunwindstack/tests/files/offline/eh_frame_bias_x86/regs.txt
@@ -0,0 +1,9 @@
+eax: fffffffc
+ebx: 4
+ecx: eb290180
+edx: 20
+ebp: 8
+edi: 0
+esi: ffffffff
+esp: fffe1a30
+eip: ffffe430
diff --git a/libunwindstack/tests/files/offline/eh_frame_bias_x86/stack.data b/libunwindstack/tests/files/offline/eh_frame_bias_x86/stack.data
new file mode 100644
index 0000000..b95bfac
--- /dev/null
+++ b/libunwindstack/tests/files/offline/eh_frame_bias_x86/stack.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/eh_frame_bias_x86/tombstoned b/libunwindstack/tests/files/offline/eh_frame_bias_x86/tombstoned
new file mode 100644
index 0000000..aefdb6b
--- /dev/null
+++ b/libunwindstack/tests/files/offline/eh_frame_bias_x86/tombstoned
Binary files differ
diff --git a/libunwindstack/tests/files/offline/eh_frame_bias_x86/vdso.so b/libunwindstack/tests/files/offline/eh_frame_bias_x86/vdso.so
new file mode 100644
index 0000000..c71dcfb
--- /dev/null
+++ b/libunwindstack/tests/files/offline/eh_frame_bias_x86/vdso.so
Binary files differ
diff --git a/libunwindstack/tools/unwind_for_offline.cpp b/libunwindstack/tools/unwind_for_offline.cpp
index 4f67d67..64b58a8 100644
--- a/libunwindstack/tools/unwind_for_offline.cpp
+++ b/libunwindstack/tools/unwind_for_offline.cpp
@@ -275,6 +275,9 @@
 
     if (maps_by_start.count(frame.map_start) == 0) {
       map_info = maps->Find(frame.map_start);
+      if (map_info == nullptr) {
+        continue;
+      }
 
       auto info = FillInAndGetMapInfo(maps_by_start, map_info);
       bool file_copied = false;
diff --git a/libziparchive/Android.bp b/libziparchive/Android.bp
index 0253f2f..2251479 100644
--- a/libziparchive/Android.bp
+++ b/libziparchive/Android.bp
@@ -184,3 +184,10 @@
     ],
     recovery_available: true,
 }
+
+cc_fuzz {
+    name: "libziparchive_fuzzer",
+    srcs: ["libziparchive_fuzzer.cpp"],
+    static_libs: ["libziparchive", "libbase", "libz", "liblog"],
+    host_supported: true,
+}
diff --git a/libziparchive/include/ziparchive/zip_archive.h b/libziparchive/include/ziparchive/zip_archive.h
index e3ac114..391cff9 100644
--- a/libziparchive/include/ziparchive/zip_archive.h
+++ b/libziparchive/include/ziparchive/zip_archive.h
@@ -114,7 +114,7 @@
 int32_t OpenArchiveFd(const int fd, const char* debugFileName, ZipArchiveHandle* handle,
                       bool assume_ownership = true);
 
-int32_t OpenArchiveFromMemory(void* address, size_t length, const char* debugFileName,
+int32_t OpenArchiveFromMemory(const void* address, size_t length, const char* debugFileName,
                               ZipArchiveHandle* handle);
 /*
  * Close archive, releasing resources associated with it. This will
diff --git a/libziparchive/libziparchive_fuzzer.cpp b/libziparchive/libziparchive_fuzzer.cpp
new file mode 100644
index 0000000..75e7939
--- /dev/null
+++ b/libziparchive/libziparchive_fuzzer.cpp
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: Apache-2.0
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <ziparchive/zip_archive.h>
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+  ZipArchiveHandle handle = nullptr;
+  OpenArchiveFromMemory(data, size, "fuzz", &handle);
+  CloseArchive(handle);
+  return 0;
+}
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index c95b035..3a552d8 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -178,7 +178,7 @@
 #endif
 }
 
-ZipArchive::ZipArchive(void* address, size_t length)
+ZipArchive::ZipArchive(const void* address, size_t length)
     : mapped_zip(address, length),
       close_file(false),
       directory_offset(0),
@@ -471,7 +471,7 @@
   return OpenArchiveInternal(archive, fileName);
 }
 
-int32_t OpenArchiveFromMemory(void* address, size_t length, const char* debug_file_name,
+int32_t OpenArchiveFromMemory(const void* address, size_t length, const char* debug_file_name,
                               ZipArchiveHandle* handle) {
   ZipArchive* archive = new ZipArchive(address, length);
   *handle = archive;
@@ -1152,7 +1152,7 @@
   return fd_;
 }
 
-void* MappedZipFile::GetBasePtr() const {
+const void* MappedZipFile::GetBasePtr() const {
   if (has_fd_) {
     ALOGW("Zip: MappedZipFile doesn't have a base pointer.");
     return nullptr;
@@ -1188,13 +1188,14 @@
       ALOGE("Zip: invalid offset: %" PRId64 ", data length: %" PRId64 "\n", off, data_length_);
       return false;
     }
-    memcpy(buf, static_cast<uint8_t*>(base_ptr_) + off, len);
+    memcpy(buf, static_cast<const uint8_t*>(base_ptr_) + off, len);
   }
   return true;
 }
 
-void CentralDirectory::Initialize(void* map_base_ptr, off64_t cd_start_offset, size_t cd_size) {
-  base_ptr_ = static_cast<uint8_t*>(map_base_ptr) + cd_start_offset;
+void CentralDirectory::Initialize(const void* map_base_ptr, off64_t cd_start_offset,
+                                  size_t cd_size) {
+  base_ptr_ = static_cast<const uint8_t*>(map_base_ptr) + cd_start_offset;
   length_ = cd_size;
 }
 
diff --git a/libziparchive/zip_archive_private.h b/libziparchive/zip_archive_private.h
index 30a1d72..60fdec0 100644
--- a/libziparchive/zip_archive_private.h
+++ b/libziparchive/zip_archive_private.h
@@ -95,14 +95,14 @@
   explicit MappedZipFile(const int fd)
       : has_fd_(true), fd_(fd), base_ptr_(nullptr), data_length_(0) {}
 
-  explicit MappedZipFile(void* address, size_t length)
+  explicit MappedZipFile(const void* address, size_t length)
       : has_fd_(false), fd_(-1), base_ptr_(address), data_length_(static_cast<off64_t>(length)) {}
 
   bool HasFd() const { return has_fd_; }
 
   int GetFileDescriptor() const;
 
-  void* GetBasePtr() const;
+  const void* GetBasePtr() const;
 
   off64_t GetFileLength() const;
 
@@ -117,7 +117,7 @@
 
   const int fd_;
 
-  void* const base_ptr_;
+  const void* const base_ptr_;
   const off64_t data_length_;
 };
 
@@ -129,7 +129,7 @@
 
   size_t GetMapLength() const { return length_; }
 
-  void Initialize(void* map_base_ptr, off64_t cd_start_offset, size_t cd_size);
+  void Initialize(const void* map_base_ptr, off64_t cd_start_offset, size_t cd_size);
 
  private:
   const uint8_t* base_ptr_;
@@ -177,7 +177,7 @@
   ZipStringOffset* hash_table;
 
   ZipArchive(const int fd, bool assume_ownership);
-  ZipArchive(void* address, size_t length);
+  ZipArchive(const void* address, size_t length);
   ~ZipArchive();
 
   bool InitializeCentralDirectory(off64_t cd_start_offset, size_t cd_size);
diff --git a/logd/LogListener.cpp b/logd/LogListener.cpp
index 443570f..ba61042 100644
--- a/logd/LogListener.cpp
+++ b/logd/LogListener.cpp
@@ -41,8 +41,7 @@
     }
 
     // + 1 to ensure null terminator if MAX_PAYLOAD buffer is received
-    char buffer[sizeof_log_id_t + sizeof(uint16_t) + sizeof(log_time) +
-                LOGGER_ENTRY_MAX_PAYLOAD + 1];
+    char buffer[sizeof(android_log_header_t) + LOGGER_ENTRY_MAX_PAYLOAD + 1];
     struct iovec iov = { buffer, sizeof(buffer) - 1 };
 
     alignas(4) char control[CMSG_SPACE(sizeof(struct ucred))];
diff --git a/logd/fuzz/Android.bp b/logd/fuzz/Android.bp
new file mode 100644
index 0000000..3215b24
--- /dev/null
+++ b/logd/fuzz/Android.bp
@@ -0,0 +1,28 @@
+// 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.
+cc_fuzz {
+    name: "log_buffer_log_fuzzer",
+    srcs: [
+        "log_buffer_log_fuzzer.cpp",
+    ],
+    static_libs: [
+        "libbase",
+        "libcutils",
+        "libselinux",
+        "liblog",
+        "liblogd",
+        "libcutils",
+    ],
+    cflags: ["-Werror"],
+}
diff --git a/logd/fuzz/log_buffer_log_fuzzer.cpp b/logd/fuzz/log_buffer_log_fuzzer.cpp
new file mode 100644
index 0000000..be4c7c3
--- /dev/null
+++ b/logd/fuzz/log_buffer_log_fuzzer.cpp
@@ -0,0 +1,98 @@
+/*
+ * 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 "../LogBuffer.h"
+#include "../LogTimes.h"
+
+namespace android {
+struct LogInput {
+  public:
+    log_id_t log_id;  // char
+    log_time realtime;
+    uid_t uid;
+    pid_t pid;
+    pid_t tid;
+};
+
+int write_log_messages(const uint8_t* data, size_t* data_left, LogBuffer* log_buffer) {
+    const LogInput* logInput = reinterpret_cast<const LogInput*>(data);
+    data += sizeof(LogInput);
+    *data_left -= sizeof(LogInput);
+
+    uint8_t tag_length = data[0] % 32;
+    uint8_t msg_length = data[1] % 32;
+    if (tag_length < 2 || msg_length < 2) {
+        // Not enough data for tag and message
+        return 0;
+    }
+
+    data += 2 * sizeof(uint8_t);
+    *data_left -= 2 * sizeof(uint8_t);
+
+    if (*data_left < tag_length + msg_length) {
+        // Not enough data for tag and message
+        return 0;
+    }
+
+    // We need nullterm'd strings
+    char* msg = new char[tag_length + msg_length + 2];
+    char* msg_only = msg + tag_length + 1;
+    memcpy(msg, data, tag_length);
+    msg[tag_length] = '\0';
+    memcpy(msg_only, data, msg_length);
+    msg_only[msg_length] = '\0';
+    data += tag_length + msg_length;
+    *data_left -= tag_length + msg_length;
+
+    // Other elements not in enum.
+    log_id_t log_id = static_cast<log_id_t>(unsigned(logInput->log_id) % (LOG_ID_MAX + 1));
+    log_buffer->log(log_id, logInput->realtime, logInput->uid, logInput->pid, logInput->tid, msg,
+                    tag_length + msg_length + 2);
+    delete[] msg;
+    return 1;
+}
+
+// Because system/core/logd/main.cpp redefines this.
+void prdebug(char const* fmt, ...) {
+    va_list ap;
+    va_start(ap, fmt);
+    vfprintf(stderr, fmt, ap);
+    va_end(ap);
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    // We want a random tag length and a random remaining message length
+    if (data == nullptr || size < sizeof(LogInput) + 2 * sizeof(uint8_t)) {
+        return 0;
+    }
+
+    LastLogTimes times;
+    LogBuffer log_buffer(&times);
+    size_t data_left = size;
+
+    log_buffer.enableStatistics();
+    // We want to get pruning code to get called.
+    log_id_for_each(i) { log_buffer.setSize(i, 10000); }
+
+    while (data_left >= sizeof(LogInput) + 2 * sizeof(uint8_t)) {
+        if (!write_log_messages(data, &data_left, &log_buffer)) {
+            return 0;
+        }
+    }
+
+    log_id_for_each(i) { log_buffer.clear(i); }
+    return 0;
+}
+}  // namespace android
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 $@)