Merge "Concatenate conditional" into main
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
index 5393e25..267571b 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -12,6 +12,7 @@
         "-Wno-unused-argument",
         "-Wno-unused-function",
         "-Wno-nullability-completeness",
+        "-Wno-reorder-init-list",
         "-Os",
         "-fno-finite-loops",
         "-DANDROID_DEBUGGABLE=0",
diff --git a/fastboot/README.md b/fastboot/README.md
index 55583eb..28e623c 100644
--- a/fastboot/README.md
+++ b/fastboot/README.md
@@ -188,6 +188,21 @@
     erase %s           Erase a given partition (can only be used in conjunction)
                        with if-wipe -> eg. if-wipe erase cache
 
+Flashing Optimization:
+
+    After generating the list of tasks to execute, Fastboot will try and
+    optimize the flashing of the dynamic partitions by constructing an
+    optimized flash super task. Fastboot will explicitly pattern match the
+    following commands and try and concatenate it into this task. (doing so
+    will allow us to avoid the reboot into userspace fastbootd which takes
+    significant time)
+
+    //Optimizable Block
+    reboot fastboot
+    update-super                        ---> generate optimized flash super task
+    $FOR EACH {dynamic partition}
+        flash {dynamic partition}
+
 ## Client Variables
 
 The "getvar:%s" command is used to read client variables which
diff --git a/fastboot/device/commands.cpp b/fastboot/device/commands.cpp
index d605393..6de598f 100644
--- a/fastboot/device/commands.cpp
+++ b/fastboot/device/commands.cpp
@@ -639,6 +639,12 @@
     return UpdateSuper(device, args[1], wipe);
 }
 
+static bool IsLockedDsu() {
+    std::string active_dsu;
+    android::gsi::GetActiveDsu(&active_dsu);
+    return android::base::EndsWith(active_dsu, ".lock");
+}
+
 bool GsiHandler(FastbootDevice* device, const std::vector<std::string>& args) {
     if (args.size() != 2) {
         return device->WriteFail("Invalid arguments");
@@ -653,6 +659,11 @@
         return device->WriteStatus(FastbootResult::FAIL, "No GSI is installed");
     }
 
+    if ((args[1] == "wipe" || args[1] == "disable") && GetDeviceLockStatus() && IsLockedDsu()) {
+        // Block commands that modify the states of locked DSU
+        return device->WriteFail("Command not available on locked DSU/devices");
+    }
+
     if (args[1] == "wipe") {
         if (!android::gsi::UninstallGsi()) {
             return device->WriteStatus(FastbootResult::FAIL, strerror(errno));
diff --git a/fastboot/task_test.cpp b/fastboot/task_test.cpp
index 42be3cb..1e25b6f 100644
--- a/fastboot/task_test.cpp
+++ b/fastboot/task_test.cpp
@@ -234,6 +234,35 @@
             << "size of fastboot-info task list: " << fastboot_info_tasks.size()
             << " size of hardcoded task list: " << hardcoded_tasks.size();
 }
+TEST_F(ParseTest, IsDynamicParitiontest) {
+    if (!get_android_product_out()) {
+        GTEST_SKIP();
+    }
+
+    LocalImageSource s;
+    fp->source = &s;
+
+    fastboot::MockFastbootDriver fb;
+    fp->fb = &fb;
+    fp->should_optimize_flash_super = true;
+    fp->should_use_fastboot_info = true;
+
+    std::vector<std::pair<std::string, bool>> test_cases = {
+            {"flash boot", false},
+            {"flash init_boot", false},
+            {"flash --apply-vbmeta vbmeta", false},
+            {"flash product", true},
+            {"flash system", true},
+            {"flash --slot-other system system_other.img", true},
+    };
+    for (auto& test : test_cases) {
+        std::unique_ptr<Task> task =
+                ParseFastbootInfoLine(fp.get(), android::base::Tokenize(test.first, " "));
+        auto flash_task = task->AsFlashTask();
+        ASSERT_FALSE(flash_task == nullptr);
+        ASSERT_EQ(FlashTask::IsDynamicParitition(fp->source, flash_task), test.second);
+    }
+}
 
 TEST_F(ParseTest, CanOptimizeTest) {
     if (!get_android_product_out()) {
@@ -275,6 +304,7 @@
         ASSERT_EQ(OptimizedFlashSuperTask::CanOptimize(fp->source, tasks), test.second);
     }
 }
+
 // Note: this test is exclusively testing that optimized flash super pattern matches a given task
 // list and is able to optimized based on a correct sequence of tasks
 TEST_F(ParseTest, OptimizedFlashSuperPatternMatchTest) {
diff --git a/fs_mgr/fs_mgr_overlayfs_control.cpp b/fs_mgr/fs_mgr_overlayfs_control.cpp
index 68576f2..2cc0d2d 100644
--- a/fs_mgr/fs_mgr_overlayfs_control.cpp
+++ b/fs_mgr/fs_mgr_overlayfs_control.cpp
@@ -688,7 +688,7 @@
                 continue;
             }
         } else {
-            if (GetEntryForMountPoint(&fstab, overlay_mount_point) == nullptr) {
+            if (!fs_mgr_overlayfs_already_mounted(overlay_mount_point, false /* overlay */)) {
                 continue;
             }
         }
diff --git a/fs_mgr/fs_mgr_overlayfs_mount.cpp b/fs_mgr/fs_mgr_overlayfs_mount.cpp
index 8fb63b1..9f17c06 100644
--- a/fs_mgr/fs_mgr_overlayfs_mount.cpp
+++ b/fs_mgr/fs_mgr_overlayfs_mount.cpp
@@ -733,15 +733,18 @@
 
 bool fs_mgr_overlayfs_already_mounted(const std::string& mount_point, bool overlay_only) {
     Fstab fstab;
-    if (!ReadFstabFromFile("/proc/mounts", &fstab)) {
+    if (!ReadFstabFromProcMounts(&fstab)) {
         return false;
     }
     const auto lowerdir = kLowerdirOption + mount_point;
-    for (const auto& entry : fstab) {
-        if (overlay_only && "overlay" != entry.fs_type && "overlayfs" != entry.fs_type) continue;
-        if (mount_point != entry.mount_point) continue;
-        if (!overlay_only) return true;
-        const auto options = android::base::Split(entry.fs_options, ",");
+    for (const auto& entry : GetEntriesForMountPoint(&fstab, mount_point)) {
+        if (!overlay_only) {
+            return true;
+        }
+        if (entry->fs_type != "overlay" && entry->fs_type != "overlayfs") {
+            continue;
+        }
+        const auto options = android::base::Split(entry->fs_options, ",");
         for (const auto& opt : options) {
             if (opt == lowerdir) {
                 return true;
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
index 6bc8b9b..e7b0020 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -73,6 +73,9 @@
 class SnapshotMergeStats;
 class SnapshotStatus;
 
+using std::chrono::duration_cast;
+using namespace std::chrono_literals;
+
 static constexpr const std::string_view kCowGroupName = "cow";
 static constexpr char kVirtualAbCompressionProp[] = "ro.virtual_ab.compression.enabled";
 
@@ -424,6 +427,7 @@
     FRIEND_TEST(SnapshotTest, MergeFailureCode);
     FRIEND_TEST(SnapshotTest, NoMergeBeforeReboot);
     FRIEND_TEST(SnapshotTest, UpdateBootControlHal);
+    FRIEND_TEST(SnapshotTest, BootSnapshotWithoutSlotSwitch);
     FRIEND_TEST(SnapshotUpdateTest, AddPartition);
     FRIEND_TEST(SnapshotUpdateTest, ConsistencyCheckResume);
     FRIEND_TEST(SnapshotUpdateTest, DaemonTransition);
@@ -436,6 +440,7 @@
     FRIEND_TEST(SnapshotUpdateTest, QueryStatusError);
     FRIEND_TEST(SnapshotUpdateTest, SnapshotStatusFileWithoutCow);
     FRIEND_TEST(SnapshotUpdateTest, SpaceSwapUpdate);
+    FRIEND_TEST(SnapshotUpdateTest, MapAllSnapshotsWithoutSlotSwitch);
     friend class SnapshotTest;
     friend class SnapshotUpdateTest;
     friend class FlashAfterUpdateTest;
@@ -456,7 +461,7 @@
     bool EnsureImageManager();
 
     // Ensure we're connected to snapuserd.
-    bool EnsureSnapuserdConnected();
+    bool EnsureSnapuserdConnected(std::chrono::milliseconds timeout_ms = 10s);
 
     // Helpers for first-stage init.
     const std::unique_ptr<IDeviceInfo>& device() const { return device_; }
@@ -549,6 +554,16 @@
     // Unmap and remove all known snapshots.
     bool RemoveAllSnapshots(LockedFile* lock);
 
+    // Boot device off snapshots without slot switch
+    bool BootFromSnapshotsWithoutSlotSwitch();
+
+    // Remove kBootSnapshotsWithoutSlotSwitch so that device can boot
+    // without snapshots on the current slot
+    bool PrepareDeviceToBootWithoutSnapshot();
+
+    // Is the kBootSnapshotsWithoutSlotSwitch present
+    bool IsSnapshotWithoutSlotSwitch();
+
     // List the known snapshot names.
     bool ListSnapshots(LockedFile* lock, std::vector<std::string>* snapshots,
                        const std::string& suffix = "");
@@ -663,6 +678,7 @@
     std::string GetRollbackIndicatorPath();
     std::string GetForwardMergeIndicatorPath();
     std::string GetOldPartitionMetadataPath();
+    std::string GetBootSnapshotsWithoutSlotSwitchPath();
 
     const LpMetadata* ReadOldPartitionMetadata(LockedFile* lock);
 
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index 51389a0..4743a42 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -83,6 +83,8 @@
 using namespace std::chrono_literals;
 using namespace std::string_literals;
 
+static constexpr char kBootSnapshotsWithoutSlotSwitch[] =
+        "/metadata/ota/snapshot-boot-without-slot-switch";
 static constexpr char kBootIndicatorPath[] = "/metadata/ota/snapshot-boot";
 static constexpr char kRollbackIndicatorPath[] = "/metadata/ota/rollback-indicator";
 static constexpr auto kUpdateStateCheckInterval = 2s;
@@ -217,6 +219,12 @@
     auto file = LockExclusive();
     if (!file) return false;
 
+    if (IsSnapshotWithoutSlotSwitch()) {
+        LOG(ERROR) << "Cannot cancel the snapshots as partitions are mounted off the snapshots on "
+                      "current slot.";
+        return false;
+    }
+
     UpdateState state = ReadUpdateState(file.get());
     if (state == UpdateState::None) {
         RemoveInvalidSnapshots(file.get());
@@ -299,10 +307,9 @@
     // - For ForwardMerge, FinishedSnapshotWrites asserts that the existence of the indicator
     // matches the incoming update.
     std::vector<std::string> files = {
-            GetSnapshotBootIndicatorPath(),
-            GetRollbackIndicatorPath(),
-            GetForwardMergeIndicatorPath(),
-            GetOldPartitionMetadataPath(),
+            GetSnapshotBootIndicatorPath(),          GetRollbackIndicatorPath(),
+            GetForwardMergeIndicatorPath(),          GetOldPartitionMetadataPath(),
+            GetBootSnapshotsWithoutSlotSwitchPath(),
     };
     for (const auto& file : files) {
         RemoveFileIfExists(file);
@@ -483,6 +490,32 @@
             LOG(ERROR) << "Failed to retrieve base_sectors from Snapuserd";
             return false;
         }
+    } else if (IsSnapshotWithoutSlotSwitch()) {
+        // When snapshots are on current slot, we determine the size
+        // of block device based on the number of COW operations. We cannot
+        // use base device as it will be from older image.
+        size_t num_ops = 0;
+        uint64_t dev_sz = 0;
+        unique_fd fd(open(cow_file.c_str(), O_RDONLY | O_CLOEXEC));
+        if (fd < 0) {
+            PLOG(ERROR) << "Failed to open " << cow_file;
+            return false;
+        }
+
+        CowReader reader;
+        if (!reader.Parse(std::move(fd))) {
+            LOG(ERROR) << "Failed to parse cow " << cow_file;
+            return false;
+        }
+
+        const auto& header = reader.GetHeader();
+        if (header.prefix.major_version > 2) {
+            LOG(ERROR) << "COW format not supported";
+            return false;
+        }
+        num_ops = reader.get_num_total_data_ops();
+        dev_sz = (num_ops * header.block_size);
+        base_sectors = dev_sz >> 9;
     } else {
         // For userspace snapshots, the size of the base device is taken as the
         // size of the dm-user block device. Since there is no pseudo mapping
@@ -1479,6 +1512,10 @@
     return result;
 }
 
+std::string SnapshotManager::GetBootSnapshotsWithoutSlotSwitchPath() {
+    return metadata_dir_ + "/" + android::base::Basename(kBootSnapshotsWithoutSlotSwitch);
+}
+
 std::string SnapshotManager::GetSnapshotBootIndicatorPath() {
     return metadata_dir_ + "/" + android::base::Basename(kBootIndicatorPath);
 }
@@ -2120,6 +2157,10 @@
     return state;
 }
 
+bool SnapshotManager::IsSnapshotWithoutSlotSwitch() {
+    return (access(GetBootSnapshotsWithoutSlotSwitchPath().c_str(), F_OK) == 0);
+}
+
 bool SnapshotManager::UpdateUsesCompression() {
     auto lock = LockShared();
     if (!lock) return false;
@@ -2212,6 +2253,13 @@
 }
 
 bool SnapshotManager::NeedSnapshotsInFirstStageMount() {
+    if (IsSnapshotWithoutSlotSwitch()) {
+        if (GetCurrentSlot() != Slot::Source) {
+            LOG(ERROR) << "Snapshots marked to boot without slot switch; but slot is wrong";
+            return false;
+        }
+        return true;
+    }
     // If we fail to read, we'll wind up using CreateLogicalPartitions, which
     // will create devices that look like the old slot, except with extra
     // content at the end of each device. This will confuse dm-verity, and
@@ -2347,7 +2395,8 @@
     // completed, live_snapshot_status is set to nullopt.
     std::optional<SnapshotStatus> live_snapshot_status;
     do {
-        if (!(params.partition->attributes & LP_PARTITION_ATTR_UPDATED)) {
+        if (!IsSnapshotWithoutSlotSwitch() &&
+            !(params.partition->attributes & LP_PARTITION_ATTR_UPDATED)) {
             LOG(INFO) << "Detected re-flashing of partition, will skip snapshot: "
                       << params.GetPartitionName();
             break;
@@ -2703,7 +2752,7 @@
     // to unmap; hence, we can't be deleting the device
     // as the table would be mounted off partitions and will fail.
     if (snapshot_status.state() != SnapshotState::MERGE_COMPLETED) {
-        if (!DeleteDeviceIfExists(dm_user_name)) {
+        if (!DeleteDeviceIfExists(dm_user_name, 4000ms)) {
             LOG(ERROR) << "Cannot unmap " << dm_user_name;
             return false;
         }
@@ -3098,7 +3147,7 @@
     return true;
 }
 
-bool SnapshotManager::EnsureSnapuserdConnected() {
+bool SnapshotManager::EnsureSnapuserdConnected(std::chrono::milliseconds timeout_ms) {
     if (snapuserd_client_) {
         return true;
     }
@@ -3107,7 +3156,7 @@
         return false;
     }
 
-    snapuserd_client_ = SnapuserdClient::Connect(kSnapuserdSocket, 10s);
+    snapuserd_client_ = SnapuserdClient::Connect(kSnapuserdSocket, timeout_ms);
     if (!snapuserd_client_) {
         LOG(ERROR) << "Unable to connect to snapuserd";
         return false;
@@ -4372,13 +4421,70 @@
 bool SnapshotManager::IsUserspaceSnapshotUpdateInProgress() {
     auto slot = GetCurrentSlot();
     if (slot == Slot::Target) {
+        // Merge in-progress
         if (IsSnapuserdRequired()) {
             return true;
         }
     }
 
+    // Let's check more deeper to see if snapshots are mounted
+    auto lock = LockExclusive();
+    if (!lock) {
+        return false;
+    }
+
+    std::vector<std::string> snapshots;
+    if (!ListSnapshots(lock.get(), &snapshots)) {
+        return false;
+    }
+
+    for (const auto& snapshot : snapshots) {
+        // Active snapshot and daemon is alive
+        if (IsSnapshotDevice(snapshot) && EnsureSnapuserdConnected(2s)) {
+            return true;
+        }
+    }
+
     return false;
 }
 
+bool SnapshotManager::BootFromSnapshotsWithoutSlotSwitch() {
+    auto lock = LockExclusive();
+    if (!lock) return false;
+
+    auto contents = device_->GetSlotSuffix();
+    // This is the indicator which tells first-stage init
+    // to boot from snapshots even though there was no slot-switch
+    auto boot_file = GetBootSnapshotsWithoutSlotSwitchPath();
+    if (!WriteStringToFileAtomic(contents, boot_file)) {
+        PLOG(ERROR) << "write failed: " << boot_file;
+        return false;
+    }
+
+    SnapshotUpdateStatus update_status = ReadSnapshotUpdateStatus(lock.get());
+    update_status.set_state(UpdateState::Initiated);
+    update_status.set_userspace_snapshots(true);
+    update_status.set_using_snapuserd(true);
+    if (!WriteSnapshotUpdateStatus(lock.get(), update_status)) {
+        return false;
+    }
+    return true;
+}
+
+bool SnapshotManager::PrepareDeviceToBootWithoutSnapshot() {
+    auto lock = LockExclusive();
+    if (!lock) return false;
+
+    android::base::RemoveFileIfExists(GetSnapshotBootIndicatorPath());
+    android::base::RemoveFileIfExists(GetBootSnapshotsWithoutSlotSwitchPath());
+
+    SnapshotUpdateStatus update_status = ReadSnapshotUpdateStatus(lock.get());
+    update_status.set_state(UpdateState::Cancelled);
+    if (!WriteSnapshotUpdateStatus(lock.get(), update_status)) {
+        return false;
+    }
+    return true;
+}
+
 }  // namespace snapshot
 }  // namespace android
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index 3b6d26a..e506110 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -2559,6 +2559,56 @@
     }
 }
 
+TEST_F(SnapshotUpdateTest, MapAllSnapshotsWithoutSlotSwitch) {
+    MountMetadata();
+    AddOperationForPartitions();
+    // Execute the update.
+    ASSERT_TRUE(sm->BeginUpdate());
+    ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
+
+    if (!sm->UpdateUsesUserSnapshots()) {
+        GTEST_SKIP() << "Test does not apply as UserSnapshots aren't enabled.";
+    }
+
+    ASSERT_TRUE(WriteSnapshots());
+    ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
+
+    if (ShouldSkipLegacyMerging()) {
+        GTEST_SKIP() << "Skipping legacy merge test";
+    }
+    // Mark the indicator
+    ASSERT_TRUE(sm->BootFromSnapshotsWithoutSlotSwitch());
+
+    ASSERT_TRUE(sm->EnsureSnapuserdConnected());
+    sm->set_use_first_stage_snapuserd(true);
+
+    ASSERT_TRUE(sm->NeedSnapshotsInFirstStageMount());
+
+    // Map snapshots
+    ASSERT_TRUE(sm->MapAllSnapshots(10s));
+
+    // New updates should fail
+    ASSERT_FALSE(sm->BeginUpdate());
+
+    // Snapshots cannot be cancelled
+    ASSERT_FALSE(sm->CancelUpdate());
+
+    // Merge cannot start
+    ASSERT_FALSE(sm->InitiateMerge());
+
+    // Read bytes back and verify they match the cache.
+    ASSERT_TRUE(IsPartitionUnchanged("sys_b"));
+
+    // Remove the indicators
+    ASSERT_TRUE(sm->PrepareDeviceToBootWithoutSnapshot());
+
+    // Ensure snapshots are still mounted
+    ASSERT_TRUE(sm->IsUserspaceSnapshotUpdateInProgress());
+
+    // Cleanup snapshots
+    ASSERT_TRUE(sm->UnmapAllSnapshots());
+}
+
 TEST_F(SnapshotUpdateTest, MapAllSnapshots) {
     AddOperationForPartitions();
     // Execute the update.
diff --git a/fs_mgr/libsnapshot/snapshotctl.cpp b/fs_mgr/libsnapshot/snapshotctl.cpp
index 1323b0b..ebaca2d 100644
--- a/fs_mgr/libsnapshot/snapshotctl.cpp
+++ b/fs_mgr/libsnapshot/snapshotctl.cpp
@@ -75,7 +75,11 @@
                  "  unmap-snapshots\n"
                  "    Unmap all pre-created snapshots\n"
                  "  delete-snapshots\n"
-                 "    Delete all pre-created snapshots\n";
+                 "    Delete all pre-created snapshots\n"
+                 "  revert-snapshots\n"
+                 "    Prepares devices to boot without snapshots on next boot.\n"
+                 "    This does not delete the snapshot. It only removes the indicators\n"
+                 "    so that first stage init will not mount from snapshots.\n";
     return EX_USAGE;
 }
 
@@ -87,9 +91,11 @@
     MapSnapshots(std::string path = "");
     bool CreateSnapshotDevice(std::string& partition_name, std::string& patch);
     bool InitiateThreadedSnapshotWrite(std::string& pname, std::string& snapshot_patch);
-    bool WaitForSnapshotWritesToComplete();
+    bool FinishSnapshotWrites();
     bool UnmapCowImagePath(std::string& name);
-    bool DeleteCowImage(std::string& name);
+    bool DeleteSnapshots();
+    bool CleanupSnapshot() { return sm_->PrepareDeviceToBootWithoutSnapshot(); }
+    bool BeginUpdate();
 
   private:
     std::optional<std::string> GetCowImagePath(std::string& name);
@@ -107,7 +113,24 @@
         exit(1);
     }
     snapshot_dir_path_ = path + "/";
+}
+
+bool MapSnapshots::BeginUpdate() {
     lock_ = sm_->LockExclusive();
+    std::vector<std::string> snapshots;
+    sm_->ListSnapshots(lock_.get(), &snapshots);
+    if (!snapshots.empty()) {
+        // Snapshots are already present.
+        return true;
+    }
+
+    lock_ = nullptr;
+    if (!sm_->BeginUpdate()) {
+        LOG(ERROR) << "BeginUpdate failed";
+        return false;
+    }
+    lock_ = sm_->LockExclusive();
+    return true;
 }
 
 bool MapSnapshots::CreateSnapshotDevice(std::string& partition_name, std::string& patchfile) {
@@ -130,6 +153,9 @@
     dev_sz &= ~(block_sz - 1);
 
     SnapshotStatus status;
+    status.set_state(SnapshotState::CREATED);
+    status.set_using_snapuserd(true);
+    status.set_old_partition_size(0);
     status.set_name(partition_name);
     status.set_cow_file_size(dev_sz);
     status.set_cow_partition_size(0);
@@ -216,27 +242,33 @@
     return true;
 }
 
-bool MapSnapshots::WaitForSnapshotWritesToComplete() {
+bool MapSnapshots::FinishSnapshotWrites() {
     bool ret = true;
     for (auto& t : threads_) {
         ret = t.get() && ret;
     }
 
+    lock_ = nullptr;
     if (ret) {
         LOG(INFO) << "Pre-created snapshots successfully copied";
-    } else {
-        LOG(ERROR) << "Snapshot copy failed";
+        if (!sm_->FinishedSnapshotWrites(false)) {
+            return false;
+        }
+        return sm_->BootFromSnapshotsWithoutSlotSwitch();
     }
-    return ret;
+
+    LOG(ERROR) << "Snapshot copy failed";
+    return false;
 }
 
 bool MapSnapshots::UnmapCowImagePath(std::string& name) {
     return sm_->UnmapCowImage(name);
 }
 
-bool MapSnapshots::DeleteCowImage(std::string& name) {
-    if (!sm_->DeleteSnapshot(lock_.get(), name)) {
-        LOG(ERROR) << "Delete snapshot failed";
+bool MapSnapshots::DeleteSnapshots() {
+    lock_ = sm_->LockExclusive();
+    if (!sm_->RemoveAllUpdateState(lock_.get())) {
+        LOG(ERROR) << "Remove All Update State failed";
         return false;
     }
     return true;
@@ -281,7 +313,8 @@
     return true;
 }
 
-bool UnMapPrecreatedSnapshots(int, char**) {
+bool UnMapPrecreatedSnapshots(int, char** argv) {
+    android::base::InitLogging(argv, &android::base::KernelLogger);
     // Make sure we are root.
     if (::getuid() != 0) {
         LOG(ERROR) << "Not running as root. Try \"adb root\" first.";
@@ -302,29 +335,36 @@
     return true;
 }
 
-bool DeletePrecreatedSnapshots(int, char**) {
+bool RemovePrecreatedSnapshots(int, char** argv) {
+    android::base::InitLogging(argv, &android::base::KernelLogger);
+    // Make sure we are root.
+    if (::getuid() != 0) {
+        LOG(ERROR) << "Not running as root. Try \"adb root\" first.";
+        return false;
+    }
+
+    MapSnapshots snapshot;
+    if (!snapshot.CleanupSnapshot()) {
+        LOG(ERROR) << "CleanupSnapshot failed";
+        return false;
+    }
+    return true;
+}
+
+bool DeletePrecreatedSnapshots(int, char** argv) {
+    android::base::InitLogging(argv, &android::base::KernelLogger);
     // Make sure we are root.
     if (::getuid() != 0) {
         LOG(ERROR) << "Not running as root. Try \"adb root\" first.";
         return EXIT_FAILURE;
     }
 
-    std::vector<std::string> partitions;
-    if (!GetVerityPartitions(partitions)) {
-        return false;
-    }
-
     MapSnapshots snapshot;
-    for (auto partition : partitions) {
-        if (!snapshot.DeleteCowImage(partition)) {
-            LOG(ERROR) << "DeleteCowImage failed: " << partition;
-        }
-    }
-    return true;
+    return snapshot.DeleteSnapshots();
 }
 
 bool MapPrecreatedSnapshots(int argc, char** argv) {
-    android::base::InitLogging(argv, &android::base::StderrLogger);
+    android::base::InitLogging(argv, &android::base::KernelLogger);
 
     // Make sure we are root.
     if (::getuid() != 0) {
@@ -365,6 +405,11 @@
     }
 
     MapSnapshots cow(path);
+    if (!cow.BeginUpdate()) {
+        LOG(ERROR) << "BeginUpdate failed";
+        return false;
+    }
+
     for (auto& pair : partitions) {
         if (!cow.CreateSnapshotDevice(pair.first, pair.second)) {
             LOG(ERROR) << "CreateSnapshotDevice failed for: " << pair.first;
@@ -376,7 +421,7 @@
         }
     }
 
-    return cow.WaitForSnapshotWritesToComplete();
+    return cow.FinishSnapshotWrites();
 }
 
 #ifdef SNAPSHOTCTL_USERDEBUG_OR_ENG
@@ -508,6 +553,7 @@
         {"map-snapshots", MapPrecreatedSnapshots},
         {"unmap-snapshots", UnMapPrecreatedSnapshots},
         {"delete-snapshots", DeletePrecreatedSnapshots},
+        {"revert-snapshots", RemovePrecreatedSnapshots},
         // clang-format on
 };
 
diff --git a/libutils/String8.cpp b/libutils/String8.cpp
index 2b72847..4301f0e 100644
--- a/libutils/String8.cpp
+++ b/libutils/String8.cpp
@@ -430,31 +430,6 @@
 // ---------------------------------------------------------------------------
 // Path functions
 
-static void setPathName(String8& s, const char* name) {
-    size_t len = strlen(name);
-    char* buf = s.lockBuffer(len);
-
-    memcpy(buf, name, len);
-
-    // remove trailing path separator, if present
-    if (len > 0 && buf[len - 1] == OS_PATH_SEPARATOR) len--;
-    buf[len] = '\0';
-
-    s.unlockBuffer(len);
-}
-
-String8 String8::getPathLeaf(void) const
-{
-    const char* cp;
-    const char*const buf = mString;
-
-    cp = strrchr(buf, OS_PATH_SEPARATOR);
-    if (cp == nullptr)
-        return String8(*this);
-    else
-        return String8(cp+1);
-}
-
 String8 String8::getPathDir(void) const
 {
     const char* cp;
@@ -467,40 +442,14 @@
         return String8(str, cp - str);
 }
 
-String8 String8::walkPath(String8* outRemains) const
-{
-    const char* cp;
-    const char*const str = mString;
-    const char* buf = str;
-
-    cp = strchr(buf, OS_PATH_SEPARATOR);
-    if (cp == buf) {
-        // don't include a leading '/'.
-        buf = buf+1;
-        cp = strchr(buf, OS_PATH_SEPARATOR);
-    }
-
-    if (cp == nullptr) {
-        String8 res = buf != str ? String8(buf) : *this;
-        if (outRemains) *outRemains = String8("");
-        return res;
-    }
-
-    String8 res(buf, cp-buf);
-    if (outRemains) *outRemains = String8(cp+1);
-    return res;
-}
-
 /*
  * Helper function for finding the start of an extension in a pathname.
  *
  * Returns a pointer inside mString, or NULL if no extension was found.
  */
-char* String8::find_extension(void) const
-{
+static const char* find_extension(const char* str) {
     const char* lastSlash;
     const char* lastDot;
-    const char* const str = mString;
 
     // only look at the filename
     lastSlash = strrchr(str, OS_PATH_SEPARATOR);
@@ -515,67 +464,16 @@
         return nullptr;
 
     // looks good, ship it
-    return const_cast<char*>(lastDot);
+    return lastDot;
 }
 
 String8 String8::getPathExtension(void) const
 {
-    char* ext;
-
-    ext = find_extension();
+    auto ext = find_extension(mString);
     if (ext != nullptr)
         return String8(ext);
     else
         return String8("");
 }
 
-String8 String8::getBasePath(void) const
-{
-    char* ext;
-    const char* const str = mString;
-
-    ext = find_extension();
-    if (ext == nullptr)
-        return String8(*this);
-    else
-        return String8(str, ext - str);
-}
-
-String8& String8::appendPath(const char* name)
-{
-    // TODO: The test below will fail for Win32 paths. Fix later or ignore.
-    if (name[0] != OS_PATH_SEPARATOR) {
-        if (*name == '\0') {
-            // nothing to do
-            return *this;
-        }
-
-        size_t len = length();
-        if (len == 0) {
-            // no existing filename, just use the new one
-            setPathName(*this, name);
-            return *this;
-        }
-
-        // make room for oldPath + '/' + newPath
-        int newlen = strlen(name);
-
-        char* buf = lockBuffer(len+1+newlen);
-
-        // insert a '/' if needed
-        if (buf[len-1] != OS_PATH_SEPARATOR)
-            buf[len++] = OS_PATH_SEPARATOR;
-
-        memcpy(buf+len, name, newlen+1);
-        len += newlen;
-
-        unlockBuffer(len);
-
-        return *this;
-    } else {
-        setPathName(*this, name);
-        return *this;
-    }
-}
-
 }; // namespace android
diff --git a/libutils/String8_fuzz.cpp b/libutils/String8_fuzz.cpp
index 6f7a54f..cbce050 100644
--- a/libutils/String8_fuzz.cpp
+++ b/libutils/String8_fuzz.cpp
@@ -68,30 +68,6 @@
                     int start_index = dataProvider->ConsumeIntegralInRange<int>(0, str1->size());
                     str1->find(str2->c_str(), start_index);
                 },
-
-                // Path handling
-                [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
-                    str1->getBasePath();
-                },
-                [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
-                    str1->getPathExtension();
-                },
-                [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
-                    str1->getPathLeaf();
-                },
-                [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
-                    str1->getPathDir();
-                },
-                [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
-                    std::shared_ptr<android::String8> path_out_str =
-                            std::make_shared<android::String8>();
-                    str1->walkPath(path_out_str.get());
-                    path_out_str->clear();
-                },
-                [](FuzzedDataProvider* dataProvider, android::String8* str1,
-                   android::String8*) -> void {
-                    str1->appendPath(dataProvider->ConsumeBytesWithTerminator<char>(5).data());
-                },
 };
 
 void fuzzFormat(FuzzedDataProvider* dataProvider, android::String8* str1, bool shouldAppend) {
diff --git a/libutils/abi-dumps/arm64/source-based/libutils.so.lsdump b/libutils/abi-dumps/arm64/source-based/libutils.so.lsdump
index 46badde..8881b44 100644
--- a/libutils/abi-dumps/arm64/source-based/libutils.so.lsdump
+++ b/libutils/abi-dumps/arm64/source-based/libutils.so.lsdump
@@ -704,9 +704,6 @@
    "name" : "_ZN7android7RefBaseD2Ev"
   },
   {
-   "name" : "_ZN7android7String810appendPathEPKc"
-  },
-  {
    "name" : "_ZN7android7String810lockBufferEm"
   },
   {
@@ -1145,15 +1142,6 @@
    "name" : "_ZNK7android7String810getPathDirEv"
   },
   {
-   "name" : "_ZNK7android7String811getBasePathEv"
-  },
-  {
-   "name" : "_ZNK7android7String811getPathLeafEv"
-  },
-  {
-   "name" : "_ZNK7android7String814find_extensionEv"
-  },
-  {
    "name" : "_ZNK7android7String816getPathExtensionEv"
   },
   {
@@ -1163,9 +1151,6 @@
    "name" : "_ZNK7android7String86lengthEv"
   },
   {
-   "name" : "_ZNK7android7String88walkPathEPS0_"
-  },
-  {
    "name" : "_ZNK7android8String1610startsWithEPKDs"
   },
   {
@@ -6809,22 +6794,6 @@
    "source_file" : "system/core/libutils/include/utils/RefBase.h"
   },
   {
-   "function_name" : "android::String8::appendPath",
-   "linker_set_key" : "_ZN7android7String810appendPathEPKc",
-   "parameters" :
-   [
-    {
-     "is_this_ptr" : true,
-     "referenced_type" : "_ZTIPN7android7String8E"
-    },
-    {
-     "referenced_type" : "_ZTIPKc"
-    }
-   ],
-   "return_type" : "_ZTIRN7android7String8E",
-   "source_file" : "system/core/libutils/include/utils/String8.h"
-  },
-  {
    "function_name" : "android::String8::lockBuffer",
    "linker_set_key" : "_ZN7android7String810lockBufferEm",
    "parameters" :
@@ -9104,6 +9073,7 @@
    "source_file" : "system/core/libutils/include/utils/RefBase.h"
   },
   {
+   "access" : "private",
    "function_name" : "android::String8::getPathDir",
    "linker_set_key" : "_ZNK7android7String810getPathDirEv",
    "parameters" :
@@ -9117,46 +9087,7 @@
    "source_file" : "system/core/libutils/include/utils/String8.h"
   },
   {
-   "function_name" : "android::String8::getBasePath",
-   "linker_set_key" : "_ZNK7android7String811getBasePathEv",
-   "parameters" :
-   [
-    {
-     "is_this_ptr" : true,
-     "referenced_type" : "_ZTIPKN7android7String8E"
-    }
-   ],
-   "return_type" : "_ZTIN7android7String8E",
-   "source_file" : "system/core/libutils/include/utils/String8.h"
-  },
-  {
-   "function_name" : "android::String8::getPathLeaf",
-   "linker_set_key" : "_ZNK7android7String811getPathLeafEv",
-   "parameters" :
-   [
-    {
-     "is_this_ptr" : true,
-     "referenced_type" : "_ZTIPKN7android7String8E"
-    }
-   ],
-   "return_type" : "_ZTIN7android7String8E",
-   "source_file" : "system/core/libutils/include/utils/String8.h"
-  },
-  {
    "access" : "private",
-   "function_name" : "android::String8::find_extension",
-   "linker_set_key" : "_ZNK7android7String814find_extensionEv",
-   "parameters" :
-   [
-    {
-     "is_this_ptr" : true,
-     "referenced_type" : "_ZTIPKN7android7String8E"
-    }
-   ],
-   "return_type" : "_ZTIPc",
-   "source_file" : "system/core/libutils/include/utils/String8.h"
-  },
-  {
    "function_name" : "android::String8::getPathExtension",
    "linker_set_key" : "_ZNK7android7String816getPathExtensionEv",
    "parameters" :
@@ -9203,23 +9134,6 @@
    "source_file" : "system/core/libutils/include/utils/String8.h"
   },
   {
-   "function_name" : "android::String8::walkPath",
-   "linker_set_key" : "_ZNK7android7String88walkPathEPS0_",
-   "parameters" :
-   [
-    {
-     "is_this_ptr" : true,
-     "referenced_type" : "_ZTIPKN7android7String8E"
-    },
-    {
-     "default_arg" : true,
-     "referenced_type" : "_ZTIPN7android7String8E"
-    }
-   ],
-   "return_type" : "_ZTIN7android7String8E",
-   "source_file" : "system/core/libutils/include/utils/String8.h"
-  },
-  {
    "function_name" : "android::String16::startsWith",
    "linker_set_key" : "_ZNK7android8String1610startsWithEPKDs",
    "parameters" :
diff --git a/libutils/abi-dumps/arm_arm64/source-based/libutils.so.lsdump b/libutils/abi-dumps/arm_arm64/source-based/libutils.so.lsdump
index 219c766..e8236ea 100644
--- a/libutils/abi-dumps/arm_arm64/source-based/libutils.so.lsdump
+++ b/libutils/abi-dumps/arm_arm64/source-based/libutils.so.lsdump
@@ -704,9 +704,6 @@
    "name" : "_ZN7android7RefBaseD2Ev"
   },
   {
-   "name" : "_ZN7android7String810appendPathEPKc"
-  },
-  {
    "name" : "_ZN7android7String810lockBufferEj"
   },
   {
@@ -1145,15 +1142,6 @@
    "name" : "_ZNK7android7String810getPathDirEv"
   },
   {
-   "name" : "_ZNK7android7String811getBasePathEv"
-  },
-  {
-   "name" : "_ZNK7android7String811getPathLeafEv"
-  },
-  {
-   "name" : "_ZNK7android7String814find_extensionEv"
-  },
-  {
    "name" : "_ZNK7android7String816getPathExtensionEv"
   },
   {
@@ -1163,9 +1151,6 @@
    "name" : "_ZNK7android7String86lengthEv"
   },
   {
-   "name" : "_ZNK7android7String88walkPathEPS0_"
-  },
-  {
    "name" : "_ZNK7android8String1610startsWithEPKDs"
   },
   {
@@ -6805,22 +6790,6 @@
    "source_file" : "system/core/libutils/include/utils/RefBase.h"
   },
   {
-   "function_name" : "android::String8::appendPath",
-   "linker_set_key" : "_ZN7android7String810appendPathEPKc",
-   "parameters" :
-   [
-    {
-     "is_this_ptr" : true,
-     "referenced_type" : "_ZTIPN7android7String8E"
-    },
-    {
-     "referenced_type" : "_ZTIPKc"
-    }
-   ],
-   "return_type" : "_ZTIRN7android7String8E",
-   "source_file" : "system/core/libutils/include/utils/String8.h"
-  },
-  {
    "function_name" : "android::String8::lockBuffer",
    "linker_set_key" : "_ZN7android7String810lockBufferEj",
    "parameters" :
@@ -9100,6 +9069,7 @@
    "source_file" : "system/core/libutils/include/utils/RefBase.h"
   },
   {
+   "access" : "private",
    "function_name" : "android::String8::getPathDir",
    "linker_set_key" : "_ZNK7android7String810getPathDirEv",
    "parameters" :
@@ -9113,46 +9083,7 @@
    "source_file" : "system/core/libutils/include/utils/String8.h"
   },
   {
-   "function_name" : "android::String8::getBasePath",
-   "linker_set_key" : "_ZNK7android7String811getBasePathEv",
-   "parameters" :
-   [
-    {
-     "is_this_ptr" : true,
-     "referenced_type" : "_ZTIPKN7android7String8E"
-    }
-   ],
-   "return_type" : "_ZTIN7android7String8E",
-   "source_file" : "system/core/libutils/include/utils/String8.h"
-  },
-  {
-   "function_name" : "android::String8::getPathLeaf",
-   "linker_set_key" : "_ZNK7android7String811getPathLeafEv",
-   "parameters" :
-   [
-    {
-     "is_this_ptr" : true,
-     "referenced_type" : "_ZTIPKN7android7String8E"
-    }
-   ],
-   "return_type" : "_ZTIN7android7String8E",
-   "source_file" : "system/core/libutils/include/utils/String8.h"
-  },
-  {
    "access" : "private",
-   "function_name" : "android::String8::find_extension",
-   "linker_set_key" : "_ZNK7android7String814find_extensionEv",
-   "parameters" :
-   [
-    {
-     "is_this_ptr" : true,
-     "referenced_type" : "_ZTIPKN7android7String8E"
-    }
-   ],
-   "return_type" : "_ZTIPc",
-   "source_file" : "system/core/libutils/include/utils/String8.h"
-  },
-  {
    "function_name" : "android::String8::getPathExtension",
    "linker_set_key" : "_ZNK7android7String816getPathExtensionEv",
    "parameters" :
@@ -9199,23 +9130,6 @@
    "source_file" : "system/core/libutils/include/utils/String8.h"
   },
   {
-   "function_name" : "android::String8::walkPath",
-   "linker_set_key" : "_ZNK7android7String88walkPathEPS0_",
-   "parameters" :
-   [
-    {
-     "is_this_ptr" : true,
-     "referenced_type" : "_ZTIPKN7android7String8E"
-    },
-    {
-     "default_arg" : true,
-     "referenced_type" : "_ZTIPN7android7String8E"
-    }
-   ],
-   "return_type" : "_ZTIN7android7String8E",
-   "source_file" : "system/core/libutils/include/utils/String8.h"
-  },
-  {
    "function_name" : "android::String16::startsWith",
    "linker_set_key" : "_ZNK7android8String1610startsWithEPKDs",
    "parameters" :
diff --git a/libutils/include/utils/String16.h b/libutils/include/utils/String16.h
index b48b907..1fa3723 100644
--- a/libutils/include/utils/String16.h
+++ b/libutils/include/utils/String16.h
@@ -24,6 +24,11 @@
 #include <utils/String8.h>
 #include <utils/TypeHelpers.h>
 
+#if __has_include(<string_view>)
+#include <string_view>
+#define HAS_STRING_VIEW
+#endif
+
 // ---------------------------------------------------------------------------
 
 namespace android {
@@ -56,9 +61,6 @@
     inline  const char16_t*     c_str() const;
     inline  const char16_t*     string() const;
 
-private:
-    static inline std::string   std_string(const String16& str);
-public:
             size_t              size() const;
     inline  bool                empty() const;
 
@@ -91,6 +93,7 @@
             bool                startsWith(const char16_t* prefix) const;
 
             bool                contains(const char16_t* chrs) const;
+    inline  bool                contains(const String16& other) const;
 
             status_t            replaceAll(char16_t replaceThis,
                                            char16_t withThis);
@@ -113,6 +116,12 @@
 
     inline                      operator const char16_t*() const;
 
+#ifdef HAS_STRING_VIEW
+    // Implicit cast to std::u16string is not implemented on purpose - u16string_view is much
+    // lighter and if one needs, they can still create u16string from u16string_view.
+    inline                      operator std::u16string_view() const;
+#endif
+
     // Static and non-static String16 behave the same for the users, so
     // this method isn't of much use for the users. It is public for testing.
             bool                isStaticString() const;
@@ -249,11 +258,6 @@
     return mString;
 }
 
-inline std::string String16::std_string(const String16& str)
-{
-    return std::string(String8(str).c_str());
-}
-
 inline bool String16::empty() const
 {
     return length() == 0;
@@ -264,6 +268,11 @@
     return size();
 }
 
+inline bool String16::contains(const String16& other) const
+{
+    return contains(other.c_str());
+}
+
 inline String16& String16::operator=(const String16& other)
 {
     setTo(other);
@@ -353,8 +362,15 @@
     return mString;
 }
 
+inline String16::operator std::u16string_view() const
+{
+    return {mString, length()};
+}
+
 }  // namespace android
 
 // ---------------------------------------------------------------------------
 
+#undef HAS_STRING_VIEW
+
 #endif // ANDROID_STRING16_H
diff --git a/libutils/include/utils/String8.h b/libutils/include/utils/String8.h
index ea25c6a..0b92f5b 100644
--- a/libutils/include/utils/String8.h
+++ b/libutils/include/utils/String8.h
@@ -18,7 +18,6 @@
 #define ANDROID_STRING8_H
 
 #include <iostream>
-#include <string>
 
 #include <utils/Errors.h>
 #include <utils/Unicode.h>
@@ -27,6 +26,16 @@
 #include <string.h> // for strcmp
 #include <stdarg.h>
 
+#if __has_include(<string>)
+#include <string>
+#define HAS_STRING
+#endif
+
+#if __has_include(<string_view>)
+#include <string_view>
+#define HAS_STRING_VIEW
+#endif
+
 // ---------------------------------------------------------------------------
 
 namespace android {
@@ -58,14 +67,9 @@
     inline  const char*         c_str() const;
     inline  const char*         string() const;
 
-private:
-    static inline std::string   std_string(const String8& str);
-public:
-
     inline  size_t              size() const;
     inline  size_t              bytes() const;
     inline  bool                empty() const;
-    inline  bool                isEmpty() const;
 
             size_t              length() const;
 
@@ -113,6 +117,10 @@
 
     inline                      operator const char*() const;
 
+#ifdef HAS_STRING_VIEW
+    inline explicit             operator std::string_view() const;
+#endif
+
             char*               lockBuffer(size_t size);
             void                unlockBuffer();
             status_t            unlockBuffer(size_t size);
@@ -120,92 +128,34 @@
             // return the index of the first byte of other in this at or after
             // start, or -1 if not found
             ssize_t             find(const char* other, size_t start = 0) const;
+    inline  ssize_t             find(const String8& other, size_t start = 0) const;
 
             // return true if this string contains the specified substring
     inline  bool                contains(const char* other) const;
+    inline  bool                contains(const String8& other) const;
 
             // removes all occurrence of the specified substring
             // returns true if any were found and removed
             bool                removeAll(const char* other);
+    inline  bool                removeAll(const String8& other);
 
             void                toLower();
 
-
-    /*
-     * These methods operate on the string as if it were a path name.
-     */
-
-    /*
-     * Get just the filename component.
-     *
-     * "/tmp/foo/bar.c" --> "bar.c"
-     */
-    String8 getPathLeaf(void) const;
-
-    /*
-     * Remove the last (file name) component, leaving just the directory
-     * name.
-     *
-     * "/tmp/foo/bar.c" --> "/tmp/foo"
-     * "/tmp" --> "" // ????? shouldn't this be "/" ???? XXX
-     * "bar.c" --> ""
-     */
-    String8 getPathDir(void) const;
-
-    /*
-     * Retrieve the front (root dir) component.  Optionally also return the
-     * remaining components.
-     *
-     * "/tmp/foo/bar.c" --> "tmp" (remain = "foo/bar.c")
-     * "/tmp" --> "tmp" (remain = "")
-     * "bar.c" --> "bar.c" (remain = "")
-     */
-    String8 walkPath(String8* outRemains = nullptr) const;
-
-    /*
-     * Return the filename extension.  This is the last '.' and any number
-     * of characters that follow it.  The '.' is included in case we
-     * decide to expand our definition of what constitutes an extension.
-     *
-     * "/tmp/foo/bar.c" --> ".c"
-     * "/tmp" --> ""
-     * "/tmp/foo.bar/baz" --> ""
-     * "foo.jpeg" --> ".jpeg"
-     * "foo." --> ""
-     */
-    String8 getPathExtension(void) const;
-
-    /*
-     * Return the path without the extension.  Rules for what constitutes
-     * an extension are described in the comment for getPathExtension().
-     *
-     * "/tmp/foo/bar.c" --> "/tmp/foo/bar"
-     */
-    String8 getBasePath(void) const;
-
-    /*
-     * Add a component to the pathname.  We guarantee that there is
-     * exactly one path separator between the old path and the new.
-     * If there is no existing name, we just copy the new name in.
-     *
-     * If leaf is a fully qualified path (i.e. starts with '/', it
-     * replaces whatever was there before.
-     */
-    String8& appendPath(const char* leaf);
-    String8& appendPath(const String8& leaf) { return appendPath(leaf.c_str()); }
-
-    /*
-     * Like appendPath(), but does not affect this string.  Returns a new one instead.
-     */
-    String8 appendPathCopy(const char* leaf) const
-                                             { String8 p(*this); p.appendPath(leaf); return p; }
-    String8 appendPathCopy(const String8& leaf) const { return appendPathCopy(leaf.c_str()); }
-
 private:
+            String8 getPathDir(void) const;
+            String8 getPathExtension(void) const;
+
             status_t            real_append(const char* other, size_t numChars);
-            char*               find_extension(void) const;
 
             const char* mString;
+
+// These symbols are for potential backward compatibility with prebuilts. To be removed.
+#ifdef ENABLE_STRING8_OBSOLETE_METHODS
+public:
+#else
+private:
+#endif
+    inline  bool                isEmpty() const;
 };
 
 // String8 can be trivially moved using memcpy() because moving does not
@@ -239,11 +189,6 @@
     return mString;
 }
 
-inline std::string String8::std_string(const String8& str)
-{
-    return std::string(str.c_str());
-}
-
 inline size_t String8::size() const
 {
     return length();
@@ -264,11 +209,26 @@
     return length();
 }
 
+inline ssize_t String8::find(const String8& other, size_t start) const
+{
+    return find(other.c_str(), start);
+}
+
 inline bool String8::contains(const char* other) const
 {
     return find(other) >= 0;
 }
 
+inline bool String8::contains(const String8& other) const
+{
+    return contains(other.c_str());
+}
+
+inline bool String8::removeAll(const String8& other)
+{
+    return removeAll(other.c_str());
+}
+
 inline String8& String8::operator=(const String8& other)
 {
     setTo(other);
@@ -377,8 +337,18 @@
     return mString;
 }
 
+#ifdef HAS_STRING_VIEW
+inline String8::operator std::string_view() const
+{
+    return {mString, length()};
+}
+#endif
+
 }  // namespace android
 
 // ---------------------------------------------------------------------------
 
+#undef HAS_STRING
+#undef HAS_STRING_VIEW
+
 #endif // ANDROID_STRING8_H
diff --git a/rootdir/init.zygote32.rc b/rootdir/init.zygote32.rc
index 2f0ec8a..442bd15 100644
--- a/rootdir/init.zygote32.rc
+++ b/rootdir/init.zygote32.rc
@@ -13,7 +13,7 @@
     onrestart restart audioserver
     onrestart restart cameraserver
     onrestart restart media
-    onrestart restart media.tuner
+    onrestart restart --only-if-running media.tuner
     onrestart restart netd
     onrestart restart wificond
     task_profiles ProcessCapacityHigh
diff --git a/rootdir/init.zygote64.rc b/rootdir/init.zygote64.rc
index 74a64c8..3422121 100644
--- a/rootdir/init.zygote64.rc
+++ b/rootdir/init.zygote64.rc
@@ -13,7 +13,7 @@
     onrestart restart audioserver
     onrestart restart cameraserver
     onrestart restart media
-    onrestart restart media.tuner
+    onrestart restart --only-if-running media.tuner
     onrestart restart netd
     onrestart restart wificond
     task_profiles ProcessCapacityHigh MaxPerformance