Merge "logd: remove SocketClient from LogBuffer and LogBufferElement"
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 9b6213a..a2ed205 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -28,9 +28,6 @@
       "name": "fs_mgr_vendor_overlay_test"
     },
     {
-      "name": "init_kill_services_test"
-    },
-    {
       "name": "libbase_test"
     },
     {
diff --git a/adb/client/adb_install.cpp b/adb/client/adb_install.cpp
index e562f8b..d66d400 100644
--- a/adb/client/adb_install.cpp
+++ b/adb/client/adb_install.cpp
@@ -310,7 +310,7 @@
     const auto start = clock::now();
     int first_apk = -1;
     int last_apk = -1;
-    std::vector<std::string_view> args = {"package"sv};
+    incremental::Args passthrough_args = {};
     for (int i = 0; i < argc; ++i) {
         const auto arg = std::string_view(argv[i]);
         if (android::base::EndsWithIgnoreCase(arg, ".apk"sv)) {
@@ -318,12 +318,11 @@
             if (first_apk == -1) {
                 first_apk = i;
             }
-        } else if (arg.starts_with("install-"sv)) {
+        } else if (arg.starts_with("install"sv)) {
             // incremental installation command on the device is the same for all its variations in
             // the adb, e.g. install-multiple or install-multi-package
-            args.push_back("install"sv);
         } else {
-            args.push_back(arg);
+            passthrough_args.push_back(arg);
         }
     }
 
@@ -344,7 +343,7 @@
     }
 
     printf("Performing Incremental Install\n");
-    auto server_process = incremental::install(files, silent);
+    auto server_process = incremental::install(files, passthrough_args, silent);
     if (!server_process) {
         return -1;
     }
diff --git a/adb/client/incremental.cpp b/adb/client/incremental.cpp
index 2814932..a8b0ab3 100644
--- a/adb/client/incremental.cpp
+++ b/adb/client/incremental.cpp
@@ -93,12 +93,10 @@
 
 // Send install-incremental to the device along with properly configured file descriptors in
 // streaming format. Once connection established, send all fs-verity tree bytes.
-static unique_fd start_install(const Files& files, bool silent) {
+static unique_fd start_install(const Files& files, const Args& passthrough_args, bool silent) {
     std::vector<std::string> command_args{"package", "install-incremental"};
+    command_args.insert(command_args.end(), passthrough_args.begin(), passthrough_args.end());
 
-    // fd's with positions at the beginning of fs-verity
-    std::vector<unique_fd> signature_fds;
-    signature_fds.reserve(files.size());
     for (int i = 0, size = files.size(); i < size; ++i) {
         const auto& file = files[i];
 
@@ -118,8 +116,6 @@
         auto file_desc = StringPrintf("%s:%lld:%d:%s:1", android::base::Basename(file).c_str(),
                                       (long long)st.st_size, i, signature.c_str());
         command_args.push_back(std::move(file_desc));
-
-        signature_fds.push_back(std::move(signature_fd));
     }
 
     std::string error;
@@ -150,8 +146,8 @@
     return true;
 }
 
-std::optional<Process> install(const Files& files, bool silent) {
-    auto connection_fd = start_install(files, silent);
+std::optional<Process> install(const Files& files, const Args& passthrough_args, bool silent) {
+    auto connection_fd = start_install(files, passthrough_args, silent);
     if (connection_fd < 0) {
         if (!silent) {
             fprintf(stderr, "adb: failed to initiate installation on device.\n");
diff --git a/adb/client/incremental.h b/adb/client/incremental.h
index 1fb1e0b..40e928a 100644
--- a/adb/client/incremental.h
+++ b/adb/client/incremental.h
@@ -26,9 +26,10 @@
 namespace incremental {
 
 using Files = std::vector<std::string>;
+using Args = std::vector<std::string_view>;
 
 bool can_install(const Files& files);
-std::optional<Process> install(const Files& files, bool silent);
+std::optional<Process> install(const Files& files, const Args& passthrough_args, bool silent);
 
 enum class Result { Success, Failure, None };
 Result wait_for_installation(int read_fd);
diff --git a/fastboot/Android.bp b/fastboot/Android.bp
index 3a2deb7..6b49fc7 100644
--- a/fastboot/Android.bp
+++ b/fastboot/Android.bp
@@ -149,6 +149,7 @@
     ],
 
     header_libs: [
+        "avb_headers",
         "libsnapshot_headers",
     ]
 }
diff --git a/fastboot/device/flashing.cpp b/fastboot/device/flashing.cpp
index fd6ff8e..1bf4c9c 100644
--- a/fastboot/device/flashing.cpp
+++ b/fastboot/device/flashing.cpp
@@ -31,6 +31,7 @@
 #include <ext4_utils/ext4_utils.h>
 #include <fs_mgr_overlayfs.h>
 #include <fstab/fstab.h>
+#include <libavb/libavb.h>
 #include <liblp/builder.h>
 #include <liblp/liblp.h>
 #include <libsnapshot/snapshot.h>
@@ -122,6 +123,27 @@
     }
 }
 
+static void CopyAVBFooter(std::vector<char>* data, const uint64_t block_device_size) {
+    if (data->size() < AVB_FOOTER_SIZE) {
+        return;
+    }
+    std::string footer;
+    uint64_t footer_offset = data->size() - AVB_FOOTER_SIZE;
+    for (int idx = 0; idx < AVB_FOOTER_MAGIC_LEN; idx++) {
+        footer.push_back(data->at(footer_offset + idx));
+    }
+    if (0 != footer.compare(AVB_FOOTER_MAGIC)) {
+        return;
+    }
+
+    // copy AVB footer from end of data to end of block device
+    uint64_t original_data_size = data->size();
+    data->resize(block_device_size, 0);
+    for (int idx = 0; idx < AVB_FOOTER_SIZE; idx++) {
+        data->at(block_device_size - 1 - idx) = data->at(original_data_size - 1 - idx);
+    }
+}
+
 int Flash(FastbootDevice* device, const std::string& partition_name) {
     PartitionHandle handle;
     if (!OpenPartition(device, partition_name, &handle)) {
@@ -131,8 +153,14 @@
     std::vector<char> data = std::move(device->download_data());
     if (data.size() == 0) {
         return -EINVAL;
-    } else if (data.size() > get_block_device_size(handle.fd())) {
+    }
+    uint64_t block_device_size = get_block_device_size(handle.fd());
+    if (data.size() > block_device_size) {
         return -EOVERFLOW;
+    } else if (data.size() < block_device_size &&
+               (partition_name == "boot" || partition_name == "boot_a" ||
+                partition_name == "boot_b")) {
+        CopyAVBFooter(&data, block_device_size);
     }
     WipeOverlayfsForPartition(device, partition_name);
     int result = FlashBlockDevice(handle.fd(), data);
diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
index e916693..c191102 100644
--- a/fs_mgr/libsnapshot/Android.bp
+++ b/fs_mgr/libsnapshot/Android.bp
@@ -289,7 +289,7 @@
         canonical_path_from_root: false,
         local_include_dirs: ["."],
     },
-
+    corpus: ["corpus/*"],
     fuzz_config: {
         cc: ["android-virtual-ab+bugs@google.com"],
         componentid: 30545,
diff --git a/fs_mgr/libsnapshot/android/snapshot/snapshot_fuzz.proto b/fs_mgr/libsnapshot/android/snapshot/snapshot_fuzz.proto
index 91fbb60..a55b42a 100644
--- a/fs_mgr/libsnapshot/android/snapshot/snapshot_fuzz.proto
+++ b/fs_mgr/libsnapshot/android/snapshot/snapshot_fuzz.proto
@@ -64,6 +64,7 @@
         bool has_metadata_device_object = 1;
         bool metadata_mounted = 2;
     }
+    reserved 18 to 9999;
     oneof value {
         NoArgs begin_update = 1;
         NoArgs cancel_update = 2;
@@ -82,6 +83,9 @@
         NoArgs dump = 15;
         NoArgs ensure_metadata_mounted = 16;
         NoArgs get_snapshot_merge_stats_instance = 17;
+
+        // Test directives that has nothing to do with ISnapshotManager API surface.
+        NoArgs switch_slot = 10000;
     }
 }
 
@@ -97,7 +101,10 @@
     bool is_super_metadata_valid = 3;
     chromeos_update_engine.DeltaArchiveManifest super_data = 4;
 
+    // Whether the directory that mocks /metadata/ota/snapshot is created.
+    bool has_metadata_snapshots_dir = 5;
+
     // More data used to prep the test before running actions.
-    reserved 5 to 9999;
+    reserved 6 to 9999;
     repeated SnapshotManagerActionProto actions = 10000;
 }
diff --git a/fs_mgr/libsnapshot/corpus/launch_device.txt b/fs_mgr/libsnapshot/corpus/launch_device.txt
new file mode 100644
index 0000000..55a7f2c
--- /dev/null
+++ b/fs_mgr/libsnapshot/corpus/launch_device.txt
@@ -0,0 +1,161 @@
+device_info_data {
+  slot_suffix_is_a: true
+  is_overlayfs_setup: false
+  allow_set_boot_control_merge_status: true
+  allow_set_slot_as_unbootable: true
+  is_recovery: false
+}
+manager_data {
+  is_local_image_manager: false
+}
+is_super_metadata_valid: true
+super_data {
+  partitions {
+    partition_name: "sys_a"
+    new_partition_info {
+      size: 3145728
+    }
+  }
+  partitions {
+    partition_name: "vnd_a"
+    new_partition_info {
+      size: 3145728
+    }
+  }
+  partitions {
+    partition_name: "prd_a"
+    new_partition_info {
+      size: 3145728
+    }
+  }
+  dynamic_partition_metadata {
+    groups {
+      name: "group_google_dp_a"
+      size: 15728640
+      partition_names: "sys_a"
+      partition_names: "vnd_a"
+      partition_names: "prd_a"
+    }
+  }
+}
+has_metadata_snapshots_dir: true
+actions {
+  begin_update {
+  }
+}
+actions {
+  create_update_snapshots {
+    partitions {
+      partition_name: "sys"
+      new_partition_info {
+        size: 3878912
+      }
+      operations {
+        type: ZERO,
+        dst_extents {
+          start_block: 0
+          num_blocks: 947
+        }
+      }
+    }
+    partitions {
+      partition_name: "vnd"
+      new_partition_info {
+        size: 3878912
+      }
+      operations {
+        type: ZERO,
+        dst_extents {
+          start_block: 0
+          num_blocks: 947
+        }
+      }
+    }
+    partitions {
+      partition_name: "prd"
+      new_partition_info {
+        size: 3878912
+      }
+      operations {
+        type: ZERO,
+        dst_extents {
+          start_block: 0
+          num_blocks: 947
+        }
+      }
+    }
+    dynamic_partition_metadata {
+      groups {
+        name: "group_google_dp"
+        size: 15728640
+        partition_names: "sys"
+        partition_names: "vnd"
+        partition_names: "prd"
+      }
+    }
+  }
+}
+actions {
+  map_update_snapshot {
+    use_correct_super: true
+    has_metadata_slot: true
+    metadata_slot: 1
+    partition_name: "sys_b"
+    force_writable: true
+    timeout_millis: 3000
+  }
+}
+actions {
+  map_update_snapshot {
+    use_correct_super: true
+    has_metadata_slot: true
+    metadata_slot: 1
+    partition_name: "vnd_b"
+    force_writable: true
+    timeout_millis: 3000
+  }
+}
+actions {
+  map_update_snapshot {
+    use_correct_super: true
+    has_metadata_slot: true
+    metadata_slot: 1
+    partition_name: "prd_b"
+    force_writable: true
+    timeout_millis: 3000
+  }
+}
+actions {
+  finished_snapshot_writes: false
+}
+actions {
+  unmap_update_snapshot: "sys_b"
+}
+actions {
+  unmap_update_snapshot: "vnd_b"
+}
+actions {
+  unmap_update_snapshot: "prd_b"
+}
+actions {
+  switch_slot {
+  }
+}
+actions {
+  need_snapshots_in_first_stage_mount {
+  }
+}
+actions {
+  create_logical_and_snapshot_partitions {
+    use_correct_super: true
+    timeout_millis: 5000
+  }
+}
+actions {
+  initiate_merge {
+  }
+}
+actions {
+  process_update_state {
+  }
+}
diff --git a/fs_mgr/libsnapshot/fuzz.sh b/fs_mgr/libsnapshot/fuzz.sh
index 2910129..0e57674 100755
--- a/fs_mgr/libsnapshot/fuzz.sh
+++ b/fs_mgr/libsnapshot/fuzz.sh
@@ -3,7 +3,8 @@
 FUZZ_TARGET=libsnapshot_fuzzer
 TARGET_ARCH=$(get_build_var TARGET_ARCH)
 FUZZ_BINARY=/data/fuzz/${TARGET_ARCH}/${FUZZ_TARGET}/${FUZZ_TARGET}
-DEVICE_CORPSE_DIR=/data/local/tmp/${FUZZ_TARGET}
+DEVICE_INIT_CORPUS_DIR=/data/fuzz/${TARGET_ARCH}/${FUZZ_TARGET}/corpus
+DEVICE_GENERATED_CORPUS_DIR=/data/local/tmp/${FUZZ_TARGET}/corpus
 DEVICE_GCOV_DIR=/data/local/tmp/${FUZZ_TARGET}/gcov
 HOST_SCRATCH_DIR=/tmp/${FUZZ_TARGET}
 GCOV_TOOL=${HOST_SCRATCH_DIR}/llvm-gcov
@@ -26,13 +27,14 @@
 
 prepare_device() {
     adb root && adb remount &&
-    adb shell mkdir -p ${DEVICE_CORPSE_DIR} &&
+    adb shell mkdir -p ${DEVICE_GENERATED_CORPUS_DIR} &&
     adb shell rm -rf ${DEVICE_GCOV_DIR} &&
     adb shell mkdir -p ${DEVICE_GCOV_DIR}
 }
 
 push_binary() {
-    adb push ${ANDROID_PRODUCT_OUT}/${FUZZ_BINARY} ${FUZZ_BINARY}
+    adb push ${ANDROID_PRODUCT_OUT}/${FUZZ_BINARY} ${FUZZ_BINARY} &&
+    adb push ${ANDROID_PRODUCT_OUT}/${DEVICE_INIT_CORPUS_DIR} $(dirname ${FUZZ_BINARY})
 }
 
 prepare_host() {
@@ -52,7 +54,7 @@
     prepare_device &&
     build_normal &&
     push_binary &&
-    adb shell ${FUZZ_BINARY} "$@" ${DEVICE_CORPSE_DIR}
+    adb shell ${FUZZ_BINARY} "$@" ${DEVICE_INIT_CORPUS_DIR} ${DEVICE_GENERATED_CORPUS_DIR}
 }
 
 run_snapshot_fuzz() {
@@ -62,7 +64,7 @@
     adb shell GCOV_PREFIX=${DEVICE_GCOV_DIR} GCOV_PREFIX_STRIP=3 \
         ${FUZZ_BINARY} \
         -runs=0 \
-        ${DEVICE_CORPSE_DIR}
+        ${DEVICE_INIT_CORPUS_DIR} ${DEVICE_GENERATED_CORPUS_DIR}
 }
 
 show_fuzz_result() {
@@ -82,7 +84,7 @@
 
 # run_snapshot_fuzz -runs=10000
 run_snapshot_fuzz_all() {
-    generate_corpse "$@" &&
+    generate_corpus "$@" &&
     run_snapshot_fuzz &&
     show_fuzz_result
 }
diff --git a/fs_mgr/libsnapshot/snapshot_fuzz.cpp b/fs_mgr/libsnapshot/snapshot_fuzz.cpp
index 421154d..1e90ace 100644
--- a/fs_mgr/libsnapshot/snapshot_fuzz.cpp
+++ b/fs_mgr/libsnapshot/snapshot_fuzz.cpp
@@ -54,6 +54,7 @@
 namespace android::snapshot {
 
 const SnapshotFuzzData* current_data = nullptr;
+const SnapshotTestModule* current_module = nullptr;
 
 SnapshotFuzzEnv* GetSnapshotFuzzEnv();
 
@@ -155,6 +156,13 @@
     (void)snapshot->MapUpdateSnapshot(params, &path);
 }
 
+SNAPSHOT_FUZZ_FUNCTION(SwitchSlot) {
+    (void)snapshot;
+    CHECK(current_module != nullptr);
+    CHECK(current_module->device_info != nullptr);
+    current_module->device_info->SwitchSlot();
+}
+
 // During global init, log all messages to stdio. This is only done once.
 int AllowLoggingDuringGlobalInit() {
     SetLogger(&StdioLogger);
@@ -208,8 +216,12 @@
     auto env = GetSnapshotFuzzEnv();
     env->CheckSoftReset();
 
-    auto snapshot_manager = env->CheckCreateSnapshotManager(snapshot_fuzz_data);
-    CHECK(snapshot_manager);
+    auto test_module = env->CheckCreateSnapshotManager(snapshot_fuzz_data);
+    current_module = &test_module;
+    CHECK(test_module.snapshot);
 
-    SnapshotManagerAction::ExecuteAll(snapshot_manager.get(), snapshot_fuzz_data.actions());
+    SnapshotManagerAction::ExecuteAll(test_module.snapshot.get(), snapshot_fuzz_data.actions());
+
+    current_module = nullptr;
+    current_data = nullptr;
 }
diff --git a/fs_mgr/libsnapshot/snapshot_fuzz_utils.cpp b/fs_mgr/libsnapshot/snapshot_fuzz_utils.cpp
index 8101d03..c9f1ab0 100644
--- a/fs_mgr/libsnapshot/snapshot_fuzz_utils.cpp
+++ b/fs_mgr/libsnapshot/snapshot_fuzz_utils.cpp
@@ -24,7 +24,11 @@
 
 #include <android-base/file.h>
 #include <android-base/logging.h>
+#include <android-base/properties.h>
 #include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <cutils/properties.h>
+#include <fs_mgr.h>
 #include <libsnapshot/auto_device.h>
 #include <libsnapshot/snapshot.h>
 #include <storage_literals/storage_literals.h>
@@ -41,21 +45,30 @@
 using namespace std::chrono_literals;
 using namespace std::string_literals;
 
+using android::base::Basename;
+using android::base::ReadFileToString;
+using android::base::SetProperty;
+using android::base::Split;
+using android::base::StartsWith;
 using android::base::StringPrintf;
 using android::base::unique_fd;
 using android::base::WriteStringToFile;
+using android::dm::DeviceMapper;
+using android::dm::DmTarget;
 using android::dm::LoopControl;
 using android::fiemap::IImageManager;
 using android::fiemap::ImageManager;
 using android::fs_mgr::BlockDeviceInfo;
+using android::fs_mgr::FstabEntry;
 using android::fs_mgr::IPartitionOpener;
 using chromeos_update_engine::DynamicPartitionMetadata;
 
-// This directory is exempted from pinning in ImageManager.
-static const char MNT_DIR[] = "/data/gsi/ota/test/";
+static const char MNT_DIR[] = "/mnt";
+static const char BLOCK_SYSFS[] = "/sys/block";
 
 static const char FAKE_ROOT_NAME[] = "snapshot_fuzz";
 static const auto SUPER_IMAGE_SIZE = 16_MiB;
+static const auto DATA_IMAGE_SIZE = 16_MiB;
 static const auto FAKE_ROOT_SIZE = 64_MiB;
 
 namespace android::snapshot {
@@ -98,6 +111,149 @@
     return nftw(path.c_str(), callback, 128, FTW_DEPTH | FTW_MOUNT | FTW_PHYS) == 0;
 }
 
+std::string GetLinearBaseDeviceString(const DeviceMapper::TargetInfo& target) {
+    if (target.spec.target_type != "linear"s) return {};
+    auto tokens = Split(target.data, " ");
+    CHECK_EQ(2, tokens.size());
+    return tokens[0];
+}
+
+std::vector<std::string> GetSnapshotBaseDeviceStrings(const DeviceMapper::TargetInfo& target) {
+    if (target.spec.target_type != "snapshot"s && target.spec.target_type != "snapshot-merge"s)
+        return {};
+    auto tokens = Split(target.data, " ");
+    CHECK_EQ(4, tokens.size());
+    return {tokens[0], tokens[1]};
+}
+
+bool ShouldDeleteLoopDevice(const std::string& node) {
+    std::string backing_file;
+    if (ReadFileToString(StringPrintf("%s/loop/backing_file", node.data()), &backing_file)) {
+        if (StartsWith(backing_file, std::string(MNT_DIR) + "/" + FAKE_ROOT_NAME)) {
+            return true;
+        }
+    }
+    return false;
+}
+
+std::vector<DeviceMapper::TargetInfo> GetTableInfoIfExists(const std::string& dev_name) {
+    auto& dm = DeviceMapper::Instance();
+    std::vector<DeviceMapper::TargetInfo> table;
+    if (!dm.GetTableInfo(dev_name, &table)) {
+        PCHECK(errno == ENODEV);
+        return {};
+    }
+    return table;
+}
+
+std::set<std::string> GetAllBaseDeviceStrings(const std::string& child_dev) {
+    std::set<std::string> ret;
+    for (const auto& child_target : GetTableInfoIfExists(child_dev)) {
+        auto snapshot_bases = GetSnapshotBaseDeviceStrings(child_target);
+        ret.insert(snapshot_bases.begin(), snapshot_bases.end());
+
+        auto linear_base = GetLinearBaseDeviceString(child_target);
+        if (!linear_base.empty()) {
+            ret.insert(linear_base);
+        }
+    }
+    return ret;
+}
+
+using PropertyList = std::set<std::string>;
+void InsertProperty(const char* key, const char* /*name*/, void* cookie) {
+    reinterpret_cast<PropertyList*>(cookie)->insert(key);
+}
+
+void CheckUnsetGsidProps() {
+    PropertyList list;
+    property_list(&InsertProperty, reinterpret_cast<void*>(&list));
+    for (const auto& key : list) {
+        SetProperty(key, "");
+    }
+}
+
+// Attempt to delete all devices that is based on dev_name, including itself.
+void CheckDeleteDeviceMapperTree(const std::string& dev_name, bool known_allow_delete = false,
+                                 uint64_t depth = 100) {
+    CHECK(depth > 0) << "Reaching max depth when deleting " << dev_name
+                     << ". There may be devices referencing itself. Check `dmctl list devices -v`.";
+
+    auto& dm = DeviceMapper::Instance();
+    auto table = GetTableInfoIfExists(dev_name);
+    if (table.empty()) {
+        PCHECK(dm.DeleteDeviceIfExists(dev_name)) << dev_name;
+        return;
+    }
+
+    if (!known_allow_delete) {
+        for (const auto& target : table) {
+            auto base_device_string = GetLinearBaseDeviceString(target);
+            if (base_device_string.empty()) continue;
+            if (ShouldDeleteLoopDevice(
+                        StringPrintf("/sys/dev/block/%s", base_device_string.data()))) {
+                known_allow_delete = true;
+                break;
+            }
+        }
+    }
+    if (!known_allow_delete) {
+        return;
+    }
+
+    std::string dev_string;
+    PCHECK(dm.GetDeviceString(dev_name, &dev_string));
+
+    std::vector<DeviceMapper::DmBlockDevice> devices;
+    PCHECK(dm.GetAvailableDevices(&devices));
+    for (const auto& child_dev : devices) {
+        auto child_bases = GetAllBaseDeviceStrings(child_dev.name());
+        if (child_bases.find(dev_string) != child_bases.end()) {
+            CheckDeleteDeviceMapperTree(child_dev.name(), true /* known_allow_delete */, depth - 1);
+        }
+    }
+
+    PCHECK(dm.DeleteDeviceIfExists(dev_name)) << dev_name;
+}
+
+// Attempt to clean up residues from previous runs.
+void CheckCleanupDeviceMapperDevices() {
+    auto& dm = DeviceMapper::Instance();
+    std::vector<DeviceMapper::DmBlockDevice> devices;
+    PCHECK(dm.GetAvailableDevices(&devices));
+
+    for (const auto& dev : devices) {
+        CheckDeleteDeviceMapperTree(dev.name());
+    }
+}
+
+void CheckUmount(const std::string& path) {
+    PCHECK(TEMP_FAILURE_RETRY(umount(path.data()) == 0) || errno == ENOENT || errno == EINVAL)
+            << path;
+}
+
+void CheckDetachLoopDevices(const std::set<std::string>& exclude_names = {}) {
+    // ~SnapshotFuzzEnv automatically does the following.
+    std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(BLOCK_SYSFS), closedir);
+    PCHECK(dir != nullptr) << BLOCK_SYSFS;
+    LoopControl loop_control;
+    dirent* dp;
+    while ((dp = readdir(dir.get())) != nullptr) {
+        if (exclude_names.find(dp->d_name) != exclude_names.end()) {
+            continue;
+        }
+        if (!ShouldDeleteLoopDevice(StringPrintf("%s/%s", BLOCK_SYSFS, dp->d_name).data())) {
+            continue;
+        }
+        PCHECK(loop_control.Detach(StringPrintf("/dev/block/%s", dp->d_name).data()));
+    }
+}
+
+void CheckUmountAll() {
+    CheckUmount(std::string(MNT_DIR) + "/snapshot_fuzz_data");
+    CheckUmount(std::string(MNT_DIR) + "/" + FAKE_ROOT_NAME);
+}
+
 class AutoDeleteDir : public AutoDevice {
   public:
     static std::unique_ptr<AutoDeleteDir> New(const std::string& path) {
@@ -108,9 +264,7 @@
     }
     ~AutoDeleteDir() {
         if (!HasDevice()) return;
-        if (rmdir(name_.c_str()) == -1) {
-            PLOG(ERROR) << "Cannot remove " << name_;
-        }
+        PCHECK(rmdir(name_.c_str()) == 0 || errno == ENOENT) << name_;
     }
 
   private:
@@ -119,6 +273,15 @@
 
 class AutoUnmount : public AutoDevice {
   public:
+    ~AutoUnmount() {
+        if (!HasDevice()) return;
+        CheckUmount(name_);
+    }
+    AutoUnmount(const std::string& path) : AutoDevice(path) {}
+};
+
+class AutoUnmountTmpfs : public AutoUnmount {
+  public:
     static std::unique_ptr<AutoUnmount> New(const std::string& path, uint64_t size) {
         if (mount("tmpfs", path.c_str(), "tmpfs", 0,
                   (void*)StringPrintf("size=%" PRIu64, size).data()) == -1) {
@@ -127,30 +290,20 @@
         }
         return std::unique_ptr<AutoUnmount>(new AutoUnmount(path));
     }
-    ~AutoUnmount() {
-        if (!HasDevice()) return;
-        if (umount(name_.c_str()) == -1) {
-            PLOG(ERROR) << "Cannot umount " << name_;
-        }
-    }
-
   private:
-    AutoUnmount(const std::string& path) : AutoDevice(path) {}
+    using AutoUnmount::AutoUnmount;
 };
 
 // A directory on tmpfs. Upon destruct, it is unmounted and deleted.
 class AutoMemBasedDir : public AutoDevice {
   public:
     static std::unique_ptr<AutoMemBasedDir> New(const std::string& name, uint64_t size) {
-        if (!Mkdir(MNT_DIR)) {
-            return std::unique_ptr<AutoMemBasedDir>(new AutoMemBasedDir(""));
-        }
         auto ret = std::unique_ptr<AutoMemBasedDir>(new AutoMemBasedDir(name));
         ret->auto_delete_mount_dir_ = AutoDeleteDir::New(ret->mount_path());
         if (!ret->auto_delete_mount_dir_->HasDevice()) {
             return std::unique_ptr<AutoMemBasedDir>(new AutoMemBasedDir(""));
         }
-        ret->auto_umount_mount_point_ = AutoUnmount::New(ret->mount_path(), size);
+        ret->auto_umount_mount_point_ = AutoUnmountTmpfs::New(ret->mount_path(), size);
         if (!ret->auto_umount_mount_point_->HasDevice()) {
             return std::unique_ptr<AutoMemBasedDir>(new AutoMemBasedDir(""));
         }
@@ -191,14 +344,41 @@
 };
 
 SnapshotFuzzEnv::SnapshotFuzzEnv() {
+    CheckUnsetGsidProps();
+    CheckCleanupDeviceMapperDevices();
+    CheckDetachLoopDevices();
+    CheckUmountAll();
+
     fake_root_ = AutoMemBasedDir::New(FAKE_ROOT_NAME, FAKE_ROOT_SIZE);
     CHECK(fake_root_ != nullptr);
     CHECK(fake_root_->HasDevice());
     loop_control_ = std::make_unique<LoopControl>();
-    mapped_super_ = CheckMapSuper(fake_root_->persist_path(), loop_control_.get(), &fake_super_);
+
+    fake_data_mount_point_ = MNT_DIR + "/snapshot_fuzz_data"s;
+    auto_delete_data_mount_point_ = AutoDeleteDir::New(fake_data_mount_point_);
+    CHECK(auto_delete_data_mount_point_ != nullptr);
+    CHECK(auto_delete_data_mount_point_->HasDevice());
+
+    const auto& fake_persist_path = fake_root_->persist_path();
+    mapped_super_ = CheckMapImage(fake_persist_path + "/super.img", SUPER_IMAGE_SIZE,
+                                  loop_control_.get(), &fake_super_);
+    mapped_data_ = CheckMapImage(fake_persist_path + "/data.img", DATA_IMAGE_SIZE,
+                                 loop_control_.get(), &fake_data_block_device_);
+    mounted_data_ = CheckMountFormatData(fake_data_block_device_, fake_data_mount_point_);
 }
 
-SnapshotFuzzEnv::~SnapshotFuzzEnv() = default;
+SnapshotFuzzEnv::~SnapshotFuzzEnv() {
+    CheckUnsetGsidProps();
+    CheckCleanupDeviceMapperDevices();
+    mounted_data_ = nullptr;
+    auto_delete_data_mount_point_ = nullptr;
+    mapped_data_ = nullptr;
+    mapped_super_ = nullptr;
+    CheckDetachLoopDevices();
+    loop_control_ = nullptr;
+    fake_root_ = nullptr;
+    CheckUmountAll();
+}
 
 void CheckZeroFill(const std::string& file, size_t size) {
     std::string zeros(size, '\0');
@@ -208,15 +388,12 @@
 void SnapshotFuzzEnv::CheckSoftReset() {
     fake_root_->CheckSoftReset();
     CheckZeroFill(super(), SUPER_IMAGE_SIZE);
+    CheckCleanupDeviceMapperDevices();
+    CheckDetachLoopDevices({Basename(fake_super_), Basename(fake_data_block_device_)});
 }
 
 std::unique_ptr<IImageManager> SnapshotFuzzEnv::CheckCreateFakeImageManager(
-        const std::string& path) {
-    auto images_dir = path + "/images";
-    auto metadata_dir = images_dir + "/metadata";
-    auto data_dir = images_dir + "/data";
-
-    PCHECK(Mkdir(images_dir));
+        const std::string& metadata_dir, const std::string& data_dir) {
     PCHECK(Mkdir(metadata_dir));
     PCHECK(Mkdir(data_dir));
     return ImageManager::Open(metadata_dir, data_dir);
@@ -236,36 +413,42 @@
   public:
     AutoDetachLoopDevice(LoopControl* control, const std::string& device)
         : AutoDevice(device), control_(control) {}
-    ~AutoDetachLoopDevice() { control_->Detach(name_); }
+    ~AutoDetachLoopDevice() { PCHECK(control_->Detach(name_)) << name_; }
 
   private:
     LoopControl* control_;
 };
 
-std::unique_ptr<AutoDevice> SnapshotFuzzEnv::CheckMapSuper(const std::string& fake_persist_path,
-                                                           LoopControl* control,
-                                                           std::string* fake_super) {
-    auto super_img = fake_persist_path + "/super.img";
-    CheckZeroFill(super_img, SUPER_IMAGE_SIZE);
-    CheckCreateLoopDevice(control, super_img, 1s, fake_super);
+std::unique_ptr<AutoDevice> SnapshotFuzzEnv::CheckMapImage(const std::string& img_path,
+                                                           uint64_t size, LoopControl* control,
+                                                           std::string* mapped_path) {
+    CheckZeroFill(img_path, size);
+    CheckCreateLoopDevice(control, img_path, 1s, mapped_path);
 
-    return std::make_unique<AutoDetachLoopDevice>(control, *fake_super);
+    return std::make_unique<AutoDetachLoopDevice>(control, *mapped_path);
 }
 
-std::unique_ptr<ISnapshotManager> SnapshotFuzzEnv::CheckCreateSnapshotManager(
-        const SnapshotFuzzData& data) {
+SnapshotTestModule SnapshotFuzzEnv::CheckCreateSnapshotManager(const SnapshotFuzzData& data) {
+    SnapshotTestModule ret;
     auto partition_opener = std::make_unique<TestPartitionOpener>(super());
+    ret.opener = partition_opener.get();
     CheckWriteSuperMetadata(data, *partition_opener);
     auto metadata_dir = fake_root_->tmp_path() + "/snapshot_metadata";
     PCHECK(Mkdir(metadata_dir));
+    if (data.has_metadata_snapshots_dir()) {
+        PCHECK(Mkdir(metadata_dir + "/snapshots"));
+    }
 
-    auto device_info = new SnapshotFuzzDeviceInfo(data.device_info_data(),
-                                                  std::move(partition_opener), metadata_dir);
-    auto snapshot = SnapshotManager::New(device_info /* takes ownership */);
-    snapshot->images_ = CheckCreateFakeImageManager(fake_root_->tmp_path());
+    ret.device_info = new SnapshotFuzzDeviceInfo(data.device_info_data(),
+                                                 std::move(partition_opener), metadata_dir);
+    auto snapshot = SnapshotManager::New(ret.device_info /* takes ownership */);
+    snapshot->images_ =
+            CheckCreateFakeImageManager(fake_root_->tmp_path() + "/images_manager_metadata",
+                                        fake_data_mount_point_ + "/image_manager_data");
     snapshot->has_local_image_manager_ = data.manager_data().is_local_image_manager();
+    ret.snapshot = std::move(snapshot);
 
-    return snapshot;
+    return ret;
 }
 
 const std::string& SnapshotFuzzEnv::super() const {
@@ -311,4 +494,17 @@
     CHECK(FlashPartitionTable(opener, super(), *metadata.get()));
 }
 
+std::unique_ptr<AutoDevice> SnapshotFuzzEnv::CheckMountFormatData(const std::string& blk_device,
+                                                                  const std::string& mount_point) {
+    FstabEntry entry{
+            .blk_device = blk_device,
+            .length = static_cast<off64_t>(DATA_IMAGE_SIZE),
+            .fs_type = "ext4",
+            .mount_point = mount_point,
+    };
+    CHECK(0 == fs_mgr_do_format(entry, false /* crypt_footer */));
+    CHECK(0 == fs_mgr_do_mount_one(entry));
+    return std::make_unique<AutoUnmount>(mount_point);
+}
+
 }  // namespace android::snapshot
diff --git a/fs_mgr/libsnapshot/snapshot_fuzz_utils.h b/fs_mgr/libsnapshot/snapshot_fuzz_utils.h
index 5533def..2405088 100644
--- a/fs_mgr/libsnapshot/snapshot_fuzz_utils.h
+++ b/fs_mgr/libsnapshot/snapshot_fuzz_utils.h
@@ -31,12 +31,19 @@
 namespace android::snapshot {
 
 class AutoMemBasedDir;
+class SnapshotFuzzDeviceInfo;
 
 class DummyAutoDevice : public AutoDevice {
   public:
     DummyAutoDevice(bool mounted) : AutoDevice(mounted ? "dummy" : "") {}
 };
 
+struct SnapshotTestModule {
+    std::unique_ptr<ISnapshotManager> snapshot;
+    SnapshotFuzzDeviceInfo* device_info = nullptr;
+    TestPartitionOpener* opener = nullptr;
+};
+
 // Prepare test environment. This has a heavy overhead and should be done once.
 class SnapshotFuzzEnv {
   public:
@@ -54,7 +61,7 @@
     // Create a snapshot manager for this test run.
     // Client is responsible for maintaining the lifetime of |data| over the life time of
     // ISnapshotManager.
-    std::unique_ptr<ISnapshotManager> CheckCreateSnapshotManager(const SnapshotFuzzData& data);
+    SnapshotTestModule CheckCreateSnapshotManager(const SnapshotFuzzData& data);
 
     // Return path to super partition.
     const std::string& super() const;
@@ -62,14 +69,22 @@
   private:
     std::unique_ptr<AutoMemBasedDir> fake_root_;
     std::unique_ptr<android::dm::LoopControl> loop_control_;
+    std::string fake_data_mount_point_;
+    std::unique_ptr<AutoDevice> auto_delete_data_mount_point_;
     std::unique_ptr<AutoDevice> mapped_super_;
     std::string fake_super_;
+    std::unique_ptr<AutoDevice> mapped_data_;
+    std::string fake_data_block_device_;
+    std::unique_ptr<AutoDevice> mounted_data_;
 
     static std::unique_ptr<android::fiemap::IImageManager> CheckCreateFakeImageManager(
-            const std::string& fake_tmp_path);
-    static std::unique_ptr<AutoDevice> CheckMapSuper(const std::string& fake_persist_path,
+            const std::string& metadata_dir, const std::string& data_dir);
+    static std::unique_ptr<AutoDevice> CheckMapImage(const std::string& fake_persist_path,
+                                                     uint64_t size,
                                                      android::dm::LoopControl* control,
-                                                     std::string* fake_super);
+                                                     std::string* mapped_path);
+    static std::unique_ptr<AutoDevice> CheckMountFormatData(const std::string& blk_device,
+                                                            const std::string& mount_point);
 
     void CheckWriteSuperMetadata(const SnapshotFuzzData& proto,
                                  const android::fs_mgr::IPartitionOpener& opener);
@@ -97,10 +112,8 @@
     }
 
     // Following APIs are fuzzed.
-    std::string GetSlotSuffix() const override { return data_->slot_suffix_is_a() ? "_a" : "_b"; }
-    std::string GetOtherSlotSuffix() const override {
-        return data_->slot_suffix_is_a() ? "_b" : "_a";
-    }
+    std::string GetSlotSuffix() const override { return CurrentSlotIsA() ? "_a" : "_b"; }
+    std::string GetOtherSlotSuffix() const override { return CurrentSlotIsA() ? "_b" : "_a"; }
     bool IsOverlayfsSetup() const override { return data_->is_overlayfs_setup(); }
     bool SetBootControlMergeStatus(android::hardware::boot::V1_1::MergeStatus) override {
         return data_->allow_set_boot_control_merge_status();
@@ -110,10 +123,15 @@
     }
     bool IsRecovery() const override { return data_->is_recovery(); }
 
+    void SwitchSlot() { switched_slot_ = !switched_slot_; }
+
   private:
     const FuzzDeviceInfoData* data_;
     std::unique_ptr<TestPartitionOpener> partition_opener_;
     std::string metadata_dir_;
+    bool switched_slot_ = false;
+
+    bool CurrentSlotIsA() const { return data_->slot_suffix_is_a() != switched_slot_; }
 };
 
 }  // namespace android::snapshot
diff --git a/fs_mgr/libsnapshot/update_engine/update_metadata.proto b/fs_mgr/libsnapshot/update_engine/update_metadata.proto
index be5e1fe..8a11eaa 100644
--- a/fs_mgr/libsnapshot/update_engine/update_metadata.proto
+++ b/fs_mgr/libsnapshot/update_engine/update_metadata.proto
@@ -45,7 +45,12 @@
 }
 
 message InstallOperation {
-    enum Type { SOURCE_COPY = 4; }
+    enum Type {
+        SOURCE_COPY = 4;
+        // Not used by libsnapshot. Declared here so that the fuzzer has an
+        // alternative value to use for |type|.
+        ZERO = 6;
+    }
     required Type type = 1;
     repeated Extent src_extents = 4;
     repeated Extent dst_extents = 6;
diff --git a/init/init.cpp b/init/init.cpp
index 3f8f628..631db8e 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -537,7 +537,9 @@
 // Set the UDC controller for the ConfigFS USB Gadgets.
 // Read the UDC controller in use from "/sys/class/udc".
 // In case of multiple UDC controllers select the first one.
-static void set_usb_controller() {
+static void SetUsbController() {
+    static auto controller_set = false;
+    if (controller_set) return;
     std::unique_ptr<DIR, decltype(&closedir)>dir(opendir("/sys/class/udc"), closedir);
     if (!dir) return;
 
@@ -546,6 +548,7 @@
         if (dp->d_name[0] == '.') continue;
 
         SetProperty("sys.usb.controller", dp->d_name);
+        controller_set = true;
         break;
     }
 }
@@ -800,7 +803,7 @@
     fs_mgr_vendor_overlay_mount_all();
     export_oem_lock_status();
     MountHandler mount_handler(&epoll);
-    set_usb_controller();
+    SetUsbController();
 
     const BuiltinFunctionMap& function_map = GetBuiltinFunctionMap();
     Action::set_function_map(&function_map);
@@ -910,6 +913,7 @@
         }
         if (!IsShuttingDown()) {
             HandleControlMessages();
+            SetUsbController();
         }
     }
 
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 842b2e5..f9a94d7 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -877,28 +877,36 @@
 }
 
 void PropertyLoadBootDefaults() {
-    // TODO(b/117892318): merge prop.default and build.prop files into one
     // We read the properties and their values into a map, in order to always allow properties
     // loaded in the later property files to override the properties in loaded in the earlier
     // property files, regardless of if they are "ro." properties or not.
     std::map<std::string, std::string> properties;
-    if (!load_properties_from_file("/system/etc/prop.default", nullptr, &properties)) {
-        // Try recovery path
-        if (!load_properties_from_file("/prop.default", nullptr, &properties)) {
-            // Try legacy path
-            load_properties_from_file("/default.prop", nullptr, &properties);
-        }
+
+    if (IsRecoveryMode()) {
+        load_properties_from_file("/prop.default", nullptr, &properties);
     }
+
+    // Try legacy (non-Treble) path. This file might not exist in most of the
+    // post-Oreo devices. Absence of the file is not an error.
+    load_properties_from_file("/default.prop", nullptr, &properties);
+
     load_properties_from_file("/system/build.prop", nullptr, &properties);
     load_properties_from_file("/system_ext/build.prop", nullptr, &properties);
-    load_properties_from_file("/vendor/default.prop", nullptr, &properties);
+
+    // TODO(b/117892318): uncomment the following condition when vendor.imgs for
+    // aosp_* targets are all updated.
+//    if (SelinuxGetVendorAndroidVersion() <= __ANDROID_API_R__) {
+        load_properties_from_file("/vendor/default.prop", nullptr, &properties);
+//    }
     load_properties_from_file("/vendor/build.prop", nullptr, &properties);
+
     if (SelinuxGetVendorAndroidVersion() >= __ANDROID_API_Q__) {
         load_properties_from_file("/odm/etc/build.prop", nullptr, &properties);
     } else {
         load_properties_from_file("/odm/default.prop", nullptr, &properties);
         load_properties_from_file("/odm/build.prop", nullptr, &properties);
     }
+
     load_properties_from_file("/product/build.prop", nullptr, &properties);
     load_properties_from_file("/factory/factory.prop", "ro.*", &properties);
 
diff --git a/init/util_test.cpp b/init/util_test.cpp
index 96a5b55..565e7d4 100644
--- a/init/util_test.cpp
+++ b/init/util_test.cpp
@@ -61,8 +61,8 @@
 
 TEST(util, ReadFileSymbolicLink) {
     errno = 0;
-    // lrw------- 1 root root 23 2008-12-31 19:00 default.prop -> system/etc/prop.default
-    auto file_contents = ReadFile("/default.prop");
+    // lrwxr-xr-x 1 root shell 6 2009-01-01 09:00 /system/bin/ps -> toybox
+    auto file_contents = ReadFile("/system/bin/ps");
     EXPECT_EQ(ELOOP, errno);
     ASSERT_FALSE(file_contents.ok());
     EXPECT_EQ("open() failed: Too many symbolic links encountered",
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index f3d3f27..601904a 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -411,6 +411,7 @@
     srcs: [
         "benchmarks/unwind_benchmarks.cpp",
         "benchmarks/ElfBenchmark.cpp",
+        "benchmarks/MapsBenchmark.cpp",
         "benchmarks/SymbolBenchmark.cpp",
         "benchmarks/Utils.cpp",
     ],
diff --git a/libunwindstack/benchmarks/ElfBenchmark.cpp b/libunwindstack/benchmarks/ElfBenchmark.cpp
index c108a2a..a46bd7a 100644
--- a/libunwindstack/benchmarks/ElfBenchmark.cpp
+++ b/libunwindstack/benchmarks/ElfBenchmark.cpp
@@ -23,7 +23,9 @@
 #include <benchmark/benchmark.h>
 
 #include <unwindstack/Elf.h>
+#include <unwindstack/Maps.h>
 #include <unwindstack/Memory.h>
+#include <unwindstack/Regs.h>
 
 #include "Utils.h"
 
@@ -75,3 +77,66 @@
   BenchmarkElfCreate(state, GetCompressedElfFile());
 }
 BENCHMARK(BM_elf_create_compressed);
+
+static void InitializeBuildId(benchmark::State& state, unwindstack::Maps& maps,
+                              unwindstack::MapInfo** build_id_map_info) {
+  if (!maps.Parse()) {
+    state.SkipWithError("Failed to parse local maps.");
+    return;
+  }
+
+  // Find the libc.so share library and use that for benchmark purposes.
+  *build_id_map_info = nullptr;
+  for (auto& map_info : maps) {
+    if (map_info->offset == 0 && map_info->GetBuildID() != "") {
+      *build_id_map_info = map_info.get();
+      break;
+    }
+  }
+
+  if (*build_id_map_info == nullptr) {
+    state.SkipWithError("Failed to find a map with a BuildID.");
+  }
+}
+
+static void BM_elf_get_build_id_from_object(benchmark::State& state) {
+  unwindstack::LocalMaps maps;
+  unwindstack::MapInfo* build_id_map_info;
+  InitializeBuildId(state, maps, &build_id_map_info);
+
+  unwindstack::Elf* elf = build_id_map_info->GetElf(std::shared_ptr<unwindstack::Memory>(),
+                                                    unwindstack::Regs::CurrentArch());
+  if (!elf->valid()) {
+    state.SkipWithError("Cannot get valid elf from map.");
+  }
+
+  for (auto _ : state) {
+    state.PauseTiming();
+    uintptr_t id = build_id_map_info->build_id;
+    if (id != 0) {
+      delete reinterpret_cast<std::string*>(id);
+      build_id_map_info->build_id = 0;
+    }
+    state.ResumeTiming();
+    benchmark::DoNotOptimize(build_id_map_info->GetBuildID());
+  }
+}
+BENCHMARK(BM_elf_get_build_id_from_object);
+
+static void BM_elf_get_build_id_from_file(benchmark::State& state) {
+  unwindstack::LocalMaps maps;
+  unwindstack::MapInfo* build_id_map_info;
+  InitializeBuildId(state, maps, &build_id_map_info);
+
+  for (auto _ : state) {
+    state.PauseTiming();
+    uintptr_t id = build_id_map_info->build_id;
+    if (id != 0) {
+      delete reinterpret_cast<std::string*>(id);
+      build_id_map_info->build_id = 0;
+    }
+    state.ResumeTiming();
+    benchmark::DoNotOptimize(build_id_map_info->GetBuildID());
+  }
+}
+BENCHMARK(BM_elf_get_build_id_from_file);
diff --git a/libunwindstack/benchmarks/MapsBenchmark.cpp b/libunwindstack/benchmarks/MapsBenchmark.cpp
new file mode 100644
index 0000000..be106a3
--- /dev/null
+++ b/libunwindstack/benchmarks/MapsBenchmark.cpp
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2020 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 <err.h>
+#include <stdint.h>
+
+#include <string>
+
+#include <android-base/file.h>
+#include <android-base/stringprintf.h>
+
+#include <benchmark/benchmark.h>
+
+#include <unwindstack/Maps.h>
+
+class BenchmarkLocalUpdatableMaps : public unwindstack::LocalUpdatableMaps {
+ public:
+  BenchmarkLocalUpdatableMaps() : unwindstack::LocalUpdatableMaps() {}
+  virtual ~BenchmarkLocalUpdatableMaps() = default;
+
+  const std::string GetMapsFile() const override { return maps_file_; }
+
+  void BenchmarkSetMapsFile(const std::string& maps_file) { maps_file_ = maps_file; }
+
+ private:
+  std::string maps_file_;
+};
+
+constexpr size_t kNumMaps = 10000;
+
+static void CreateInitialMap(const char* filename) {
+  std::string maps;
+  for (size_t i = 0; i < kNumMaps; i += 2) {
+    maps += android::base::StringPrintf("%zu-%zu r-xp 0000 00:00 0 name%zu\n", i * 1000,
+                                        (i + 1) * 1000, i);
+  }
+  if (!android::base::WriteStringToFile(maps, filename)) {
+    errx(1, "WriteStringToFile failed");
+  }
+}
+
+static void CreateReparseMap(const char* filename) {
+  std::string maps;
+  for (size_t i = 0; i < kNumMaps; i++) {
+    maps += android::base::StringPrintf("%zu-%zu r-xp 0000 00:00 0 name%zu\n", i * 2000,
+                                        (i + 1) * 2000, 2 * i);
+  }
+  if (!android::base::WriteStringToFile(maps, filename)) {
+    errx(1, "WriteStringToFile failed");
+  }
+}
+
+void BM_local_updatable_maps_reparse(benchmark::State& state) {
+  TemporaryFile initial_map;
+  CreateInitialMap(initial_map.path);
+
+  TemporaryFile reparse_map;
+  CreateReparseMap(reparse_map.path);
+
+  for (auto _ : state) {
+    BenchmarkLocalUpdatableMaps maps;
+    maps.BenchmarkSetMapsFile(initial_map.path);
+    if (!maps.Reparse()) {
+      errx(1, "Internal Error: reparse of initial maps filed.");
+    }
+    if (maps.Total() != (kNumMaps / 2)) {
+      errx(1, "Internal Error: Incorrect total number of maps %zu, expected %zu.", maps.Total(),
+           kNumMaps / 2);
+    }
+    maps.BenchmarkSetMapsFile(reparse_map.path);
+    if (!maps.Reparse()) {
+      errx(1, "Internal Error: reparse of second set of maps filed.");
+    }
+    if (maps.Total() != kNumMaps) {
+      errx(1, "Internal Error: Incorrect total number of maps %zu, expected %zu.", maps.Total(),
+           kNumMaps);
+    }
+  }
+}
+BENCHMARK(BM_local_updatable_maps_reparse);
diff --git a/libunwindstack/benchmarks/unwind_benchmarks.cpp b/libunwindstack/benchmarks/unwind_benchmarks.cpp
index de9137a..0bee6ef 100644
--- a/libunwindstack/benchmarks/unwind_benchmarks.cpp
+++ b/libunwindstack/benchmarks/unwind_benchmarks.cpp
@@ -22,7 +22,6 @@
 
 #include <android-base/strings.h>
 
-#include <unwindstack/Elf.h>
 #include <unwindstack/Maps.h>
 #include <unwindstack/Memory.h>
 #include <unwindstack/Regs.h>
@@ -83,63 +82,4 @@
 }
 BENCHMARK(BM_cached_unwind);
 
-static void Initialize(benchmark::State& state, unwindstack::Maps& maps,
-                       unwindstack::MapInfo** build_id_map_info) {
-  if (!maps.Parse()) {
-    state.SkipWithError("Failed to parse local maps.");
-    return;
-  }
-
-  // Find the libc.so share library and use that for benchmark purposes.
-  *build_id_map_info = nullptr;
-  for (auto& map_info : maps) {
-    if (map_info->offset == 0 && map_info->GetBuildID() != "") {
-      *build_id_map_info = map_info.get();
-      break;
-    }
-  }
-
-  if (*build_id_map_info == nullptr) {
-    state.SkipWithError("Failed to find a map with a BuildID.");
-  }
-}
-
-static void BM_get_build_id_from_elf(benchmark::State& state) {
-  unwindstack::LocalMaps maps;
-  unwindstack::MapInfo* build_id_map_info;
-  Initialize(state, maps, &build_id_map_info);
-
-  unwindstack::Elf* elf = build_id_map_info->GetElf(std::shared_ptr<unwindstack::Memory>(),
-                                                    unwindstack::Regs::CurrentArch());
-  if (!elf->valid()) {
-    state.SkipWithError("Cannot get valid elf from map.");
-  }
-
-  for (auto _ : state) {
-    uintptr_t id = build_id_map_info->build_id;
-    if (id != 0) {
-      delete reinterpret_cast<std::string*>(id);
-      build_id_map_info->build_id = 0;
-    }
-    benchmark::DoNotOptimize(build_id_map_info->GetBuildID());
-  }
-}
-BENCHMARK(BM_get_build_id_from_elf);
-
-static void BM_get_build_id_from_file(benchmark::State& state) {
-  unwindstack::LocalMaps maps;
-  unwindstack::MapInfo* build_id_map_info;
-  Initialize(state, maps, &build_id_map_info);
-
-  for (auto _ : state) {
-    uintptr_t id = build_id_map_info->build_id;
-    if (id != 0) {
-      delete reinterpret_cast<std::string*>(id);
-      build_id_map_info->build_id = 0;
-    }
-    benchmark::DoNotOptimize(build_id_map_info->GetBuildID());
-  }
-}
-BENCHMARK(BM_get_build_id_from_file);
-
 BENCHMARK_MAIN();
diff --git a/logd/Android.bp b/logd/Android.bp
index 80e3cb2..ee86566 100644
--- a/logd/Android.bp
+++ b/logd/Android.bp
@@ -57,6 +57,10 @@
         "-Wextra",
         "-Wthread-safety",
     ] + event_flag,
+
+    lto: {
+        thin: true
+    }
 }
 
 cc_binary {
@@ -82,6 +86,10 @@
     cflags: [
         "-Wextra",
     ],
+
+    lto: {
+        thin: true
+    }
 }
 
 cc_binary {
diff --git a/rootdir/init.rc b/rootdir/init.rc
index a380ebb..00a58bf 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -547,8 +547,8 @@
     enter_default_mount_ns
 
     # /data/apex is now available. Start apexd to scan and activate APEXes.
-    mkdir /data/apex 0750 root system encryption=None
-    mkdir /data/apex/active 0750 root system
+    mkdir /data/apex 0755 root system encryption=None
+    mkdir /data/apex/active 0755 root system
     mkdir /data/apex/backup 0700 root system
     mkdir /data/apex/hashtree 0700 root system
     mkdir /data/apex/sessions 0700 root system