Merge "snapuserd: Add snapuserd_test to presubmit and VTS." into main
diff --git a/fastboot/README.md b/fastboot/README.md
index 63db5c3..55583eb 100644
--- a/fastboot/README.md
+++ b/fastboot/README.md
@@ -165,6 +165,28 @@
                        using the new bootloader.
 
 
+## Flashing Logic
+
+Fastboot binary will follow directions listed out fastboot-info.txt
+build artifact for fastboot flashall && fastboot update comamnds.
+This build artifact will live inside of ANDROID_PRODUCT_OUT &&
+target_files_package && updatepackage.
+
+
+The currently defined commands are:
+
+    flash %s           Flash a given partition. Optional arguments include
+                       --slot-other, {filename_path}, --apply-vbmeta
+
+    reboot %s          Reboot to either bootloader or fastbootd
+
+    update-super       Updates the super partition
+
+    if-wipe            Conditionally run some other functionality if
+                       wipe is specified
+
+    erase %s           Erase a given partition (can only be used in conjunction)
+                       with if-wipe -> eg. if-wipe erase cache
 
 ## Client Variables
 
diff --git a/fs_mgr/libfs_avb/avb_ops.cpp b/fs_mgr/libfs_avb/avb_ops.cpp
index a119bfc..cc19776 100644
--- a/fs_mgr/libfs_avb/avb_ops.cpp
+++ b/fs_mgr/libfs_avb/avb_ops.cpp
@@ -108,8 +108,8 @@
 // Converts a partition name (with ab_suffix) to the corresponding mount point.
 // e.g., "system_a" => "/system",
 // e.g., "vendor_a" => "/vendor",
-static std::string DeriveMountPoint(const std::string& partition_name) {
-    const std::string ab_suffix = fs_mgr_get_slot_suffix();
+static std::string DeriveMountPoint(const std::string& partition_name,
+                                    const std::string& ab_suffix) {
     std::string mount_point(partition_name);
     auto found = partition_name.rfind(ab_suffix);
     if (found != std::string::npos) {
@@ -119,7 +119,7 @@
     return "/" + mount_point;
 }
 
-FsManagerAvbOps::FsManagerAvbOps() {
+FsManagerAvbOps::FsManagerAvbOps(const std::string& slot_suffix) {
     // We only need to provide the implementation of read_from_partition()
     // operation since that's all what is being used by the avb_slot_verify().
     // Other I/O operations are only required in bootloader but not in
@@ -135,6 +135,11 @@
 
     // Sets user_data for GetInstanceFromAvbOps() to convert it back to FsManagerAvbOps.
     avb_ops_.user_data = this;
+
+    slot_suffix_ = slot_suffix;
+    if (slot_suffix_.empty()) {
+        slot_suffix_ = fs_mgr_get_slot_suffix();
+    }
 }
 
 // Given a partition name (with ab_suffix), e.g., system_a, returns the corresponding
@@ -149,7 +154,7 @@
         return "";
     }
 
-    const auto mount_point = DeriveMountPoint(partition_name);
+    const auto mount_point = DeriveMountPoint(partition_name, slot_suffix_);
     if (mount_point.empty()) return "";
 
     auto fstab_entry = GetEntryForMountPoint(&fstab_, mount_point);
diff --git a/fs_mgr/libfs_avb/avb_ops.h b/fs_mgr/libfs_avb/avb_ops.h
index 12686a6..709091e 100644
--- a/fs_mgr/libfs_avb/avb_ops.h
+++ b/fs_mgr/libfs_avb/avb_ops.h
@@ -48,7 +48,7 @@
 //
 class FsManagerAvbOps {
   public:
-    FsManagerAvbOps();
+    explicit FsManagerAvbOps(const std::string& slot_suffix = {});
 
     static FsManagerAvbOps* GetInstanceFromAvbOps(AvbOps* ops) {
         return reinterpret_cast<FsManagerAvbOps*>(ops->user_data);
@@ -66,6 +66,7 @@
     std::string GetPartitionPath(const char* partition_name);
     AvbOps avb_ops_;
     Fstab fstab_;
+    std::string slot_suffix_;
 };
 
 }  // namespace fs_mgr
diff --git a/fs_mgr/libfs_avb/fs_avb.cpp b/fs_mgr/libfs_avb/fs_avb.cpp
index a288876..fb22423 100644
--- a/fs_mgr/libfs_avb/fs_avb.cpp
+++ b/fs_mgr/libfs_avb/fs_avb.cpp
@@ -182,6 +182,11 @@
 
 // class AvbHandle
 // ---------------
+AvbHandle::AvbHandle() : status_(AvbHandleStatus::kUninitialized) {
+    slot_suffix_ = fs_mgr_get_slot_suffix();
+    other_slot_suffix_ = fs_mgr_get_other_slot_suffix();
+}
+
 AvbUniquePtr AvbHandle::LoadAndVerifyVbmeta(
         const std::string& partition_name, const std::string& ab_suffix,
         const std::string& ab_other_suffix, const std::string& expected_public_key_path,
@@ -194,6 +199,9 @@
         return nullptr;
     }
 
+    avb_handle->slot_suffix_ = ab_suffix;
+    avb_handle->other_slot_suffix_ = ab_other_suffix;
+
     std::string expected_key_blob;
     if (!expected_public_key_path.empty()) {
         if (access(expected_public_key_path.c_str(), F_OK) != 0) {
@@ -373,9 +381,14 @@
     return avb_handle;
 }
 
-AvbUniquePtr AvbHandle::LoadAndVerifyVbmeta() {
+AvbUniquePtr AvbHandle::LoadAndVerifyVbmeta(const std::string& slot_suffix) {
     // Loads inline vbmeta images, starting from /vbmeta.
-    return LoadAndVerifyVbmeta("vbmeta", fs_mgr_get_slot_suffix(), fs_mgr_get_other_slot_suffix(),
+    auto suffix = slot_suffix;
+    if (suffix.empty()) {
+        suffix = fs_mgr_get_slot_suffix();
+    }
+    auto other_suffix = android::fs_mgr::OtherSlotSuffix(suffix);
+    return LoadAndVerifyVbmeta("vbmeta", suffix, other_suffix,
                                {} /* expected_public_key, already checked by bootloader */,
                                HashAlgorithm::kSHA256,
                                IsAvbPermissive(), /* allow_verification_error */
@@ -399,7 +412,7 @@
                                        ? AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR
                                        : AVB_SLOT_VERIFY_FLAGS_NONE;
     AvbSlotVerifyResult verify_result =
-            avb_ops.AvbSlotVerify(fs_mgr_get_slot_suffix(), flags, &avb_handle->vbmeta_images_);
+            avb_ops.AvbSlotVerify(avb_handle->slot_suffix_, flags, &avb_handle->vbmeta_images_);
 
     // Only allow the following verify results:
     //   - AVB_SLOT_VERIFY_RESULT_OK.
@@ -492,7 +505,7 @@
     }
 
     if (!LoadAvbHashtreeToEnableVerity(fstab_entry, wait_for_verity_dev, vbmeta_images_,
-                                       fs_mgr_get_slot_suffix(), fs_mgr_get_other_slot_suffix())) {
+                                       slot_suffix_, other_slot_suffix_)) {
         return AvbHashtreeResult::kFail;
     }
 
@@ -526,8 +539,8 @@
     if (vbmeta_images_.size() < 1) {
         return "";
     }
-    std::string avb_partition_name = DeriveAvbPartitionName(fstab_entry, fs_mgr_get_slot_suffix(),
-                                                            fs_mgr_get_other_slot_suffix());
+    std::string avb_partition_name =
+            DeriveAvbPartitionName(fstab_entry, slot_suffix_, other_slot_suffix_);
     auto avb_prop_name = "com.android.build." + avb_partition_name + ".security_patch";
     return GetAvbPropertyDescriptor(avb_prop_name, vbmeta_images_);
 }
diff --git a/fs_mgr/libfs_avb/include/fs_avb/fs_avb.h b/fs_mgr/libfs_avb/include/fs_avb/fs_avb.h
index 4702e68..924ab24 100644
--- a/fs_mgr/libfs_avb/include/fs_avb/fs_avb.h
+++ b/fs_mgr/libfs_avb/include/fs_avb/fs_avb.h
@@ -83,8 +83,8 @@
     //     is verified and can be trusted.
     //
     // TODO(bowgotsai): remove Open() and switch to LoadAndVerifyVbmeta().
-    static AvbUniquePtr Open();                 // loads inline vbmeta, via libavb.
-    static AvbUniquePtr LoadAndVerifyVbmeta();  // loads inline vbmeta.
+    static AvbUniquePtr Open();  // loads inline vbmeta, via libavb.
+    static AvbUniquePtr LoadAndVerifyVbmeta(const std::string& slot_suffix = {});
 
     // The caller can specify optional preload_avb_key_blobs for public key matching.
     // This is mostly for init to preload AVB keys before chroot into /system.
@@ -137,12 +137,14 @@
     AvbHandle& operator=(AvbHandle&&) noexcept = delete;  // no move assignment
 
   private:
-    AvbHandle() : status_(AvbHandleStatus::kUninitialized) {}
+    AvbHandle();
 
     std::vector<VBMetaData> vbmeta_images_;
     VBMetaInfo vbmeta_info_;  // A summary info for vbmeta_images_.
     AvbHandleStatus status_;
     std::string avb_version_;
+    std::string slot_suffix_;
+    std::string other_slot_suffix_;
 };
 
 }  // namespace fs_mgr
diff --git a/fs_mgr/libfstab/include/fstab/fstab.h b/fs_mgr/libfstab/include/fstab/fstab.h
index 150a47d..09471f0 100644
--- a/fs_mgr/libfstab/include/fstab/fstab.h
+++ b/fs_mgr/libfstab/include/fstab/fstab.h
@@ -145,5 +145,8 @@
 // Otherwise returns false and |*out| is not modified.
 bool GetKernelCmdline(const std::string& key, std::string* out);
 
+// Return the "other" slot for the given slot suffix.
+std::string OtherSlotSuffix(const std::string& suffix);
+
 }  // namespace fs_mgr
 }  // namespace android
diff --git a/fs_mgr/libfstab/slotselect.cpp b/fs_mgr/libfstab/slotselect.cpp
index 97b2ba1..db3f8da 100644
--- a/fs_mgr/libfstab/slotselect.cpp
+++ b/fs_mgr/libfstab/slotselect.cpp
@@ -74,3 +74,13 @@
     }
     return true;
 }
+
+namespace android {
+namespace fs_mgr {
+
+std::string OtherSlotSuffix(const std::string& suffix) {
+    return other_suffix(suffix);
+}
+
+}  // namespace fs_mgr
+}  // namespace android
diff --git a/fs_mgr/libsnapshot/OWNERS b/fs_mgr/libsnapshot/OWNERS
index 1ee4175..c8b1003 100644
--- a/fs_mgr/libsnapshot/OWNERS
+++ b/fs_mgr/libsnapshot/OWNERS
@@ -1,4 +1,4 @@
-# Bug component: 30545
+# Bug component: 1014951
 balsini@google.com
 dvander@google.com
 elsk@google.com
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_compress.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_compress.h
index 8add041..cf65615 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/cow_compress.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_compress.h
@@ -17,7 +17,6 @@
 #pragma once
 
 #include <memory>
-#include <string_view>
 #include "libsnapshot/cow_format.h"
 
 namespace android {
@@ -32,9 +31,9 @@
     static std::unique_ptr<ICompressor> Gz(uint32_t compression_level);
     static std::unique_ptr<ICompressor> Brotli(uint32_t compression_level);
     static std::unique_ptr<ICompressor> Lz4(uint32_t compression_level);
-    static std::unique_ptr<ICompressor> Zstd(uint32_t compression_level);
+    static std::unique_ptr<ICompressor> Zstd(uint32_t compression_level, const int32_t BLOCK_SZ);
 
-    static std::unique_ptr<ICompressor> Create(CowCompression compression);
+    static std::unique_ptr<ICompressor> Create(CowCompression compression, const int32_t BLOCK_SZ);
 
     uint32_t GetCompressionLevel() const { return compression_level_; }
 
diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/cow_compress.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/cow_compress.cpp
index 466b93c..71ac59f 100644
--- a/fs_mgr/libsnapshot/libsnapshot_cow/cow_compress.cpp
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/cow_compress.cpp
@@ -55,7 +55,8 @@
     }
 }
 
-std::unique_ptr<ICompressor> ICompressor::Create(CowCompression compression) {
+std::unique_ptr<ICompressor> ICompressor::Create(CowCompression compression,
+                                                 const int32_t BLOCK_SZ) {
     switch (compression.algorithm) {
         case kCowCompressLz4:
             return ICompressor::Lz4(compression.compression_level);
@@ -64,7 +65,7 @@
         case kCowCompressGz:
             return ICompressor::Gz(compression.compression_level);
         case kCowCompressZstd:
-            return ICompressor::Zstd(compression.compression_level);
+            return ICompressor::Zstd(compression.compression_level, BLOCK_SZ);
         case kCowCompressNone:
             return nullptr;
     }
@@ -175,12 +176,10 @@
 
 class ZstdCompressor final : public ICompressor {
   public:
-    ZstdCompressor(uint32_t compression_level)
+    ZstdCompressor(uint32_t compression_level, const uint32_t MAX_BLOCK_SIZE)
         : ICompressor(compression_level), zstd_context_(ZSTD_createCCtx(), ZSTD_freeCCtx) {
         ZSTD_CCtx_setParameter(zstd_context_.get(), ZSTD_c_compressionLevel, compression_level);
-        // FIXME: hardcoding a value of 12 here for 4k blocks, should change to be either set by
-        // user, or optimized depending on block size
-        ZSTD_CCtx_setParameter(zstd_context_.get(), ZSTD_c_windowLog, 12);
+        ZSTD_CCtx_setParameter(zstd_context_.get(), ZSTD_c_windowLog, log2(MAX_BLOCK_SIZE));
     };
 
     std::basic_string<uint8_t> Compress(const void* data, size_t length) const override {
@@ -326,8 +325,8 @@
     return std::make_unique<Lz4Compressor>(compression_level);
 }
 
-std::unique_ptr<ICompressor> ICompressor::Zstd(uint32_t compression_level) {
-    return std::make_unique<ZstdCompressor>(compression_level);
+std::unique_ptr<ICompressor> ICompressor::Zstd(uint32_t compression_level, const int32_t BLOCK_SZ) {
+    return std::make_unique<ZstdCompressor>(compression_level, BLOCK_SZ);
 }
 
 void CompressWorker::Finalize() {
diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/cow_decompress.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/cow_decompress.cpp
index 3692c1a..2aaf388 100644
--- a/fs_mgr/libsnapshot/libsnapshot_cow/cow_decompress.cpp
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/cow_decompress.cpp
@@ -351,7 +351,7 @@
             return decompressed_size;
         }
         std::vector<unsigned char> ignore_buf(decompressed_size);
-        if (!Decompress(buffer, decompressed_size)) {
+        if (!Decompress(ignore_buf.data(), decompressed_size)) {
             return -1;
         }
         memcpy(buffer, ignore_buf.data() + ignore_bytes, buffer_size);
diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/cow_reader.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/cow_reader.cpp
index f37aed1..1b5d724 100644
--- a/fs_mgr/libsnapshot/libsnapshot_cow/cow_reader.cpp
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/cow_reader.cpp
@@ -17,9 +17,7 @@
 #include <sys/types.h>
 #include <unistd.h>
 
-#include <limits>
 #include <optional>
-#include <set>
 #include <unordered_map>
 #include <unordered_set>
 #include <vector>
@@ -103,7 +101,7 @@
     footer_ = parser.footer();
     fd_size_ = parser.fd_size();
     last_label_ = parser.last_label();
-    ops_ = std::move(parser.ops());
+    ops_ = parser.ops();
     data_loc_ = parser.data_loc();
 
     // If we're resuming a write, we're not ready to merge
diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/test_v2.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/test_v2.cpp
index 0ecad9d..e59bd92 100644
--- a/fs_mgr/libsnapshot/libsnapshot_cow/test_v2.cpp
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/test_v2.cpp
@@ -480,7 +480,7 @@
     std::string expected = "The quick brown fox jumps over the lazy dog.";
     expected.resize(4096, '\0');
 
-    std::unique_ptr<ICompressor> compressor = ICompressor::Create(compression);
+    std::unique_ptr<ICompressor> compressor = ICompressor::Create(compression, 4096);
     auto result = compressor->Compress(expected.data(), expected.size());
     ASSERT_FALSE(result.empty());
 
diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp
index 7115821..ee445a2 100644
--- a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp
@@ -174,8 +174,7 @@
         current_data_pos_ = next_data_pos_;
     }
 
-    std::string batch_write = batch_write_ ? "enabled" : "disabled";
-    LOG_INFO << "Batch writes: " << batch_write;
+    LOG_INFO << "Batch writes: " << (batch_write_ ? "enabled" : "disabled");
 }
 
 void CowWriterV2::InitWorkers() {
@@ -184,7 +183,8 @@
         return;
     }
     for (int i = 0; i < num_compress_threads_; i++) {
-        std::unique_ptr<ICompressor> compressor = ICompressor::Create(compression_);
+        std::unique_ptr<ICompressor> compressor =
+                ICompressor::Create(compression_, header_.block_size);
         auto wt = std::make_unique<CompressWorker>(std::move(compressor), header_.block_size);
         threads_.emplace_back(std::async(std::launch::async, &CompressWorker::RunThread, wt.get()));
         compress_threads_.push_back(std::move(wt));
@@ -341,7 +341,7 @@
     compressed_buf_.clear();
     if (num_threads <= 1) {
         if (!compressor_) {
-            compressor_ = ICompressor::Create(compression_);
+            compressor_ = ICompressor::Create(compression_, header_.block_size);
         }
         return CompressWorker::CompressBlocks(compressor_.get(), options_.block_size, data,
                                               num_blocks, &compressed_buf_);
@@ -416,7 +416,7 @@
                         return data;
                     } else {
                         if (!compressor_) {
-                            compressor_ = ICompressor::Create(compression_);
+                            compressor_ = ICompressor::Create(compression_, header_.block_size);
                         }
 
                         auto data = compressor_->Compress(iter, header_.block_size);
diff --git a/fs_mgr/libsnapshot/tools/Android.bp b/fs_mgr/libsnapshot/tools/Android.bp
new file mode 100644
index 0000000..cfa0cef
--- /dev/null
+++ b/fs_mgr/libsnapshot/tools/Android.bp
@@ -0,0 +1,22 @@
+
+cc_binary {
+    name: "cow_benchmark",
+    host_supported: true,
+    defaults: [
+        "fs_mgr_defaults",
+        "libsnapshot_cow_defaults",
+    ],
+
+    srcs: ["cow_benchmark.cpp"],
+
+    static_libs: [
+        "libsnapshot_cow",
+    ],
+
+    shared_libs: [
+        "libbase",
+        "liblog",
+    ],
+
+    cflags: ["-Werror"],
+}
diff --git a/fs_mgr/libsnapshot/tools/cow_benchmark.cpp b/fs_mgr/libsnapshot/tools/cow_benchmark.cpp
new file mode 100644
index 0000000..da2b879
--- /dev/null
+++ b/fs_mgr/libsnapshot/tools/cow_benchmark.cpp
@@ -0,0 +1,188 @@
+
+#include <memory>
+
+#include <array>
+#include <iostream>
+#include <random>
+
+#include <libsnapshot/cow_compress.h>
+#include <libsnapshot/cow_format.h>
+
+static const uint32_t BLOCK_SZ = 4096;
+static const uint32_t SEED_NUMBER = 10;
+
+namespace android {
+namespace snapshot {
+
+static std::string CompressionToString(CowCompression& compression) {
+    std::string output;
+    switch (compression.algorithm) {
+        case kCowCompressBrotli:
+            output.append("brotli");
+            break;
+        case kCowCompressGz:
+            output.append("gz");
+            break;
+        case kCowCompressLz4:
+            output.append("lz4");
+            break;
+        case kCowCompressZstd:
+            output.append("zstd");
+            break;
+        case kCowCompressNone:
+            return "No Compression";
+    }
+    output.append(" " + std::to_string(compression.compression_level));
+    return output;
+}
+
+void OneShotCompressionTest() {
+    std::cout << "\n-------One Shot Compressor Perf Analysis-------\n";
+
+    std::vector<CowCompression> compression_list = {
+            {kCowCompressLz4, 0},     {kCowCompressBrotli, 1}, {kCowCompressBrotli, 3},
+            {kCowCompressBrotli, 11}, {kCowCompressZstd, 3},   {kCowCompressZstd, 6},
+            {kCowCompressZstd, 9},    {kCowCompressZstd, 22},  {kCowCompressGz, 1},
+            {kCowCompressGz, 3},      {kCowCompressGz, 6},     {kCowCompressGz, 9}};
+    std::vector<std::unique_ptr<ICompressor>> compressors;
+    for (auto i : compression_list) {
+        compressors.emplace_back(ICompressor::Create(i, BLOCK_SZ));
+    }
+
+    // Allocate a buffer of size 8 blocks.
+    std::array<char, 32768> buffer;
+
+    // Generate a random 4k buffer of characters
+    std::default_random_engine gen(SEED_NUMBER);
+    std::uniform_int_distribution<int> distribution(0, 10);
+    for (int i = 0; i < buffer.size(); i++) {
+        buffer[i] = static_cast<char>(distribution(gen));
+    }
+
+    std::vector<std::pair<double, std::string>> latencies;
+    std::vector<std::pair<double, std::string>> ratios;
+
+    for (size_t i = 0; i < compressors.size(); i++) {
+        const auto start = std::chrono::steady_clock::now();
+        std::basic_string<uint8_t> compressed_data =
+                compressors[i]->Compress(buffer.data(), buffer.size());
+        const auto end = std::chrono::steady_clock::now();
+        const auto latency =
+                std::chrono::duration_cast<std::chrono::nanoseconds>(end - start) / 1000.0;
+        const double compression_ratio =
+                static_cast<uint16_t>(compressed_data.size()) * 1.00 / buffer.size();
+
+        std::cout << "Metrics for " << CompressionToString(compression_list[i]) << ": latency -> "
+                  << latency.count() << "ms "
+                  << " compression ratio ->" << compression_ratio << " \n";
+
+        latencies.emplace_back(
+                std::make_pair(latency.count(), CompressionToString(compression_list[i])));
+        ratios.emplace_back(
+                std::make_pair(compression_ratio, CompressionToString(compression_list[i])));
+    }
+
+    int best_speed = 0;
+    int best_ratio = 0;
+
+    for (size_t i = 1; i < latencies.size(); i++) {
+        if (latencies[i].first < latencies[best_speed].first) {
+            best_speed = i;
+        }
+        if (ratios[i].first < ratios[best_ratio].first) {
+            best_ratio = i;
+        }
+    }
+
+    std::cout << "BEST SPEED: " << latencies[best_speed].first << "ms "
+              << latencies[best_speed].second << "\n";
+    std::cout << "BEST RATIO: " << ratios[best_ratio].first << " " << ratios[best_ratio].second
+              << "\n";
+}
+
+void IncrementalCompressionTest() {
+    std::cout << "\n-------Incremental Compressor Perf Analysis-------\n";
+
+    std::vector<CowCompression> compression_list = {
+            {kCowCompressLz4, 0},     {kCowCompressBrotli, 1}, {kCowCompressBrotli, 3},
+            {kCowCompressBrotli, 11}, {kCowCompressZstd, 3},   {kCowCompressZstd, 6},
+            {kCowCompressZstd, 9},    {kCowCompressZstd, 22},  {kCowCompressGz, 1},
+            {kCowCompressGz, 3},      {kCowCompressGz, 6},     {kCowCompressGz, 9}};
+    std::vector<std::unique_ptr<ICompressor>> compressors;
+    for (auto i : compression_list) {
+        compressors.emplace_back(ICompressor::Create(i, BLOCK_SZ));
+    }
+
+    // Allocate a buffer of size 8 blocks.
+    std::array<char, 32768> buffer;
+
+    // Generate a random 4k buffer of characters
+    std::default_random_engine gen(SEED_NUMBER);
+    std::uniform_int_distribution<int> distribution(0, 10);
+    for (int i = 0; i < buffer.size(); i++) {
+        buffer[i] = static_cast<char>(distribution(gen));
+    }
+
+    std::vector<std::pair<double, std::string>> latencies;
+    std::vector<std::pair<double, std::string>> ratios;
+
+    for (size_t i = 0; i < compressors.size(); i++) {
+        std::vector<std::basic_string<uint8_t>> compressed_data_vec;
+        int num_blocks = buffer.size() / BLOCK_SZ;
+        const uint8_t* iter = reinterpret_cast<const uint8_t*>(buffer.data());
+
+        const auto start = std::chrono::steady_clock::now();
+        while (num_blocks > 0) {
+            std::basic_string<uint8_t> compressed_data = compressors[i]->Compress(iter, BLOCK_SZ);
+            compressed_data_vec.emplace_back(compressed_data);
+            num_blocks--;
+            iter += BLOCK_SZ;
+        }
+
+        const auto end = std::chrono::steady_clock::now();
+        const auto latency =
+                std::chrono::duration_cast<std::chrono::nanoseconds>(end - start) / 1000.0;
+
+        size_t size = 0;
+        for (auto& i : compressed_data_vec) {
+            size += i.size();
+        }
+        const double compression_ratio = size * 1.00 / buffer.size();
+
+        std::cout << "Metrics for " << CompressionToString(compression_list[i]) << ": latency -> "
+                  << latency.count() << "ms "
+                  << " compression ratio ->" << compression_ratio << " \n";
+
+        latencies.emplace_back(
+                std::make_pair(latency.count(), CompressionToString(compression_list[i])));
+        ratios.emplace_back(
+                std::make_pair(compression_ratio, CompressionToString(compression_list[i])));
+    }
+
+    int best_speed = 0;
+    int best_ratio = 0;
+
+    for (size_t i = 1; i < latencies.size(); i++) {
+        if (latencies[i].first < latencies[best_speed].first) {
+            best_speed = i;
+        }
+        if (ratios[i].first < ratios[best_ratio].first) {
+            best_ratio = i;
+        }
+    }
+
+    std::cout << "BEST SPEED: " << latencies[best_speed].first << "ms "
+              << latencies[best_speed].second << "\n";
+    std::cout << "BEST RATIO: " << ratios[best_ratio].first << " " << ratios[best_ratio].second
+              << "\n";
+}
+
+}  // namespace snapshot
+}  // namespace android
+
+int main() {
+    android::snapshot::OneShotCompressionTest();
+    android::snapshot::IncrementalCompressionTest();
+
+    return 0;
+}
\ No newline at end of file
diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp
index 15c30be..e4cf582 100644
--- a/healthd/BatteryMonitor.cpp
+++ b/healthd/BatteryMonitor.cpp
@@ -361,7 +361,7 @@
 void BatteryMonitor::updateValues(void) {
     initHealthInfo(mHealthInfo.get());
 
-    if (!mHealthdConfig->batteryPresentPath.isEmpty())
+    if (!mHealthdConfig->batteryPresentPath.empty())
         mHealthInfo->batteryPresent = getBooleanField(mHealthdConfig->batteryPresentPath);
     else
         mHealthInfo->batteryPresent = mBatteryDevicePresent;
@@ -371,43 +371,43 @@
                                         : getIntField(mHealthdConfig->batteryCapacityPath);
     mHealthInfo->batteryVoltageMillivolts = getIntField(mHealthdConfig->batteryVoltagePath) / 1000;
 
-    if (!mHealthdConfig->batteryCurrentNowPath.isEmpty())
+    if (!mHealthdConfig->batteryCurrentNowPath.empty())
         mHealthInfo->batteryCurrentMicroamps = getIntField(mHealthdConfig->batteryCurrentNowPath);
 
-    if (!mHealthdConfig->batteryFullChargePath.isEmpty())
+    if (!mHealthdConfig->batteryFullChargePath.empty())
         mHealthInfo->batteryFullChargeUah = getIntField(mHealthdConfig->batteryFullChargePath);
 
-    if (!mHealthdConfig->batteryCycleCountPath.isEmpty())
+    if (!mHealthdConfig->batteryCycleCountPath.empty())
         mHealthInfo->batteryCycleCount = getIntField(mHealthdConfig->batteryCycleCountPath);
 
-    if (!mHealthdConfig->batteryChargeCounterPath.isEmpty())
+    if (!mHealthdConfig->batteryChargeCounterPath.empty())
         mHealthInfo->batteryChargeCounterUah =
                 getIntField(mHealthdConfig->batteryChargeCounterPath);
 
-    if (!mHealthdConfig->batteryCurrentAvgPath.isEmpty())
+    if (!mHealthdConfig->batteryCurrentAvgPath.empty())
         mHealthInfo->batteryCurrentAverageMicroamps =
                 getIntField(mHealthdConfig->batteryCurrentAvgPath);
 
-    if (!mHealthdConfig->batteryChargeTimeToFullNowPath.isEmpty())
+    if (!mHealthdConfig->batteryChargeTimeToFullNowPath.empty())
         mHealthInfo->batteryChargeTimeToFullNowSeconds =
                 getIntField(mHealthdConfig->batteryChargeTimeToFullNowPath);
 
-    if (!mHealthdConfig->batteryFullChargeDesignCapacityUahPath.isEmpty())
+    if (!mHealthdConfig->batteryFullChargeDesignCapacityUahPath.empty())
         mHealthInfo->batteryFullChargeDesignCapacityUah =
                 getIntField(mHealthdConfig->batteryFullChargeDesignCapacityUahPath);
 
-    if (!mHealthdConfig->batteryHealthStatusPath.isEmpty())
+    if (!mHealthdConfig->batteryHealthStatusPath.empty())
         mBatteryHealthStatus = getIntField(mHealthdConfig->batteryHealthStatusPath);
 
-    if (!mHealthdConfig->batteryStateOfHealthPath.isEmpty())
+    if (!mHealthdConfig->batteryStateOfHealthPath.empty())
         mHealthInfo->batteryHealthData->batteryStateOfHealth =
                 getIntField(mHealthdConfig->batteryStateOfHealthPath);
 
-    if (!mHealthdConfig->batteryManufacturingDatePath.isEmpty())
+    if (!mHealthdConfig->batteryManufacturingDatePath.empty())
         mHealthInfo->batteryHealthData->batteryManufacturingDateSeconds =
                 getIntField(mHealthdConfig->batteryManufacturingDatePath);
 
-    if (!mHealthdConfig->batteryFirstUsageDatePath.isEmpty())
+    if (!mHealthdConfig->batteryFirstUsageDatePath.empty())
         mHealthInfo->batteryHealthData->batteryFirstUsageSeconds =
                 getIntField(mHealthdConfig->batteryFirstUsageDatePath);
 
@@ -506,17 +506,17 @@
                  props.batteryStatus);
 
         len = strlen(dmesgline);
-        if (!healthd_config.batteryCurrentNowPath.isEmpty()) {
+        if (!healthd_config.batteryCurrentNowPath.empty()) {
             len += snprintf(dmesgline + len, sizeof(dmesgline) - len, " c=%d",
                             props.batteryCurrentMicroamps);
         }
 
-        if (!healthd_config.batteryFullChargePath.isEmpty()) {
+        if (!healthd_config.batteryFullChargePath.empty()) {
             len += snprintf(dmesgline + len, sizeof(dmesgline) - len, " fc=%d",
                             props.batteryFullChargeUah);
         }
 
-        if (!healthd_config.batteryCycleCountPath.isEmpty()) {
+        if (!healthd_config.batteryCycleCountPath.empty()) {
             len += snprintf(dmesgline + len, sizeof(dmesgline) - len, " cc=%d",
                             props.batteryCycleCount);
         }
@@ -550,7 +550,7 @@
 
 int BatteryMonitor::getChargeStatus() {
     BatteryStatus result = BatteryStatus::UNKNOWN;
-    if (!mHealthdConfig->batteryStatusPath.isEmpty()) {
+    if (!mHealthdConfig->batteryStatusPath.empty()) {
         std::string buf;
         if (readFromFile(mHealthdConfig->batteryStatusPath, &buf) > 0)
             result = getBatteryStatus(buf.c_str());
@@ -561,7 +561,7 @@
 status_t BatteryMonitor::setChargingPolicy(int value) {
     status_t ret = NAME_NOT_FOUND;
     bool result;
-    if (!mHealthdConfig->chargingPolicyPath.isEmpty()) {
+    if (!mHealthdConfig->chargingPolicyPath.empty()) {
         result = writeToFile(mHealthdConfig->chargingPolicyPath, value);
         if (!result) {
             KLOG_WARNING(LOG_TAG, "setChargingPolicy fail\n");
@@ -575,7 +575,7 @@
 
 int BatteryMonitor::getChargingPolicy() {
     BatteryChargingPolicy result = BatteryChargingPolicy::DEFAULT;
-    if (!mHealthdConfig->chargingPolicyPath.isEmpty()) {
+    if (!mHealthdConfig->chargingPolicyPath.empty()) {
         std::string buf;
         if (readFromFile(mHealthdConfig->chargingPolicyPath, &buf) > 0)
             result = getBatteryChargingPolicy(buf.c_str());
@@ -585,15 +585,15 @@
 
 int BatteryMonitor::getBatteryHealthData(int id) {
     if (id == BATTERY_PROP_MANUFACTURING_DATE) {
-        if (!mHealthdConfig->batteryManufacturingDatePath.isEmpty())
+        if (!mHealthdConfig->batteryManufacturingDatePath.empty())
             return getIntField(mHealthdConfig->batteryManufacturingDatePath);
     }
     if (id == BATTERY_PROP_FIRST_USAGE_DATE) {
-        if (!mHealthdConfig->batteryFirstUsageDatePath.isEmpty())
+        if (!mHealthdConfig->batteryFirstUsageDatePath.empty())
             return getIntField(mHealthdConfig->batteryFirstUsageDatePath);
     }
     if (id == BATTERY_PROP_STATE_OF_HEALTH) {
-        if (!mHealthdConfig->batteryStateOfHealthPath.isEmpty())
+        if (!mHealthdConfig->batteryStateOfHealthPath.empty())
             return getIntField(mHealthdConfig->batteryStateOfHealthPath);
     }
     return 0;
@@ -607,7 +607,7 @@
 
     switch(id) {
     case BATTERY_PROP_CHARGE_COUNTER:
-        if (!mHealthdConfig->batteryChargeCounterPath.isEmpty()) {
+        if (!mHealthdConfig->batteryChargeCounterPath.empty()) {
             val->valueInt64 =
                 getIntField(mHealthdConfig->batteryChargeCounterPath);
             ret = OK;
@@ -617,7 +617,7 @@
         break;
 
     case BATTERY_PROP_CURRENT_NOW:
-        if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
+        if (!mHealthdConfig->batteryCurrentNowPath.empty()) {
             val->valueInt64 =
                 getIntField(mHealthdConfig->batteryCurrentNowPath);
             ret = OK;
@@ -627,7 +627,7 @@
         break;
 
     case BATTERY_PROP_CURRENT_AVG:
-        if (!mHealthdConfig->batteryCurrentAvgPath.isEmpty()) {
+        if (!mHealthdConfig->batteryCurrentAvgPath.empty()) {
             val->valueInt64 =
                 getIntField(mHealthdConfig->batteryCurrentAvgPath);
             ret = OK;
@@ -637,7 +637,7 @@
         break;
 
     case BATTERY_PROP_CAPACITY:
-        if (!mHealthdConfig->batteryCapacityPath.isEmpty()) {
+        if (!mHealthdConfig->batteryCapacityPath.empty()) {
             val->valueInt64 =
                 getIntField(mHealthdConfig->batteryCapacityPath);
             ret = OK;
@@ -704,35 +704,35 @@
              props.batteryVoltageMillivolts, props.batteryTemperatureTenthsCelsius);
     write(fd, vs, strlen(vs));
 
-    if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
+    if (!mHealthdConfig->batteryCurrentNowPath.empty()) {
         v = getIntField(mHealthdConfig->batteryCurrentNowPath);
         snprintf(vs, sizeof(vs), "current now: %d\n", v);
         write(fd, vs, strlen(vs));
     }
 
-    if (!mHealthdConfig->batteryCurrentAvgPath.isEmpty()) {
+    if (!mHealthdConfig->batteryCurrentAvgPath.empty()) {
         v = getIntField(mHealthdConfig->batteryCurrentAvgPath);
         snprintf(vs, sizeof(vs), "current avg: %d\n", v);
         write(fd, vs, strlen(vs));
     }
 
-    if (!mHealthdConfig->batteryChargeCounterPath.isEmpty()) {
+    if (!mHealthdConfig->batteryChargeCounterPath.empty()) {
         v = getIntField(mHealthdConfig->batteryChargeCounterPath);
         snprintf(vs, sizeof(vs), "charge counter: %d\n", v);
         write(fd, vs, strlen(vs));
     }
 
-    if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
+    if (!mHealthdConfig->batteryCurrentNowPath.empty()) {
         snprintf(vs, sizeof(vs), "current now: %d\n", props.batteryCurrentMicroamps);
         write(fd, vs, strlen(vs));
     }
 
-    if (!mHealthdConfig->batteryCycleCountPath.isEmpty()) {
+    if (!mHealthdConfig->batteryCycleCountPath.empty()) {
         snprintf(vs, sizeof(vs), "cycle count: %d\n", props.batteryCycleCount);
         write(fd, vs, strlen(vs));
     }
 
-    if (!mHealthdConfig->batteryFullChargePath.isEmpty()) {
+    if (!mHealthdConfig->batteryFullChargePath.empty()) {
         snprintf(vs, sizeof(vs), "Full charge: %d\n", props.batteryFullChargeUah);
         write(fd, vs, strlen(vs));
     }
@@ -782,7 +782,7 @@
                 if (isScopedPowerSupply(name)) continue;
                 mBatteryDevicePresent = true;
 
-                if (mHealthdConfig->batteryStatusPath.isEmpty()) {
+                if (mHealthdConfig->batteryStatusPath.empty()) {
                     path.clear();
                     path.appendFormat("%s/%s/status", POWER_SUPPLY_SYSFS_PATH,
                                       name);
@@ -790,7 +790,7 @@
                         mHealthdConfig->batteryStatusPath = path;
                 }
 
-                if (mHealthdConfig->batteryHealthPath.isEmpty()) {
+                if (mHealthdConfig->batteryHealthPath.empty()) {
                     path.clear();
                     path.appendFormat("%s/%s/health", POWER_SUPPLY_SYSFS_PATH,
                                       name);
@@ -798,7 +798,7 @@
                         mHealthdConfig->batteryHealthPath = path;
                 }
 
-                if (mHealthdConfig->batteryPresentPath.isEmpty()) {
+                if (mHealthdConfig->batteryPresentPath.empty()) {
                     path.clear();
                     path.appendFormat("%s/%s/present", POWER_SUPPLY_SYSFS_PATH,
                                       name);
@@ -806,7 +806,7 @@
                         mHealthdConfig->batteryPresentPath = path;
                 }
 
-                if (mHealthdConfig->batteryCapacityPath.isEmpty()) {
+                if (mHealthdConfig->batteryCapacityPath.empty()) {
                     path.clear();
                     path.appendFormat("%s/%s/capacity", POWER_SUPPLY_SYSFS_PATH,
                                       name);
@@ -814,7 +814,7 @@
                         mHealthdConfig->batteryCapacityPath = path;
                 }
 
-                if (mHealthdConfig->batteryVoltagePath.isEmpty()) {
+                if (mHealthdConfig->batteryVoltagePath.empty()) {
                     path.clear();
                     path.appendFormat("%s/%s/voltage_now",
                                       POWER_SUPPLY_SYSFS_PATH, name);
@@ -823,7 +823,7 @@
                     }
                 }
 
-                if (mHealthdConfig->batteryFullChargePath.isEmpty()) {
+                if (mHealthdConfig->batteryFullChargePath.empty()) {
                     path.clear();
                     path.appendFormat("%s/%s/charge_full",
                                       POWER_SUPPLY_SYSFS_PATH, name);
@@ -831,7 +831,7 @@
                         mHealthdConfig->batteryFullChargePath = path;
                 }
 
-                if (mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
+                if (mHealthdConfig->batteryCurrentNowPath.empty()) {
                     path.clear();
                     path.appendFormat("%s/%s/current_now",
                                       POWER_SUPPLY_SYSFS_PATH, name);
@@ -839,7 +839,7 @@
                         mHealthdConfig->batteryCurrentNowPath = path;
                 }
 
-                if (mHealthdConfig->batteryCycleCountPath.isEmpty()) {
+                if (mHealthdConfig->batteryCycleCountPath.empty()) {
                     path.clear();
                     path.appendFormat("%s/%s/cycle_count",
                                       POWER_SUPPLY_SYSFS_PATH, name);
@@ -847,27 +847,27 @@
                         mHealthdConfig->batteryCycleCountPath = path;
                 }
 
-                if (mHealthdConfig->batteryCapacityLevelPath.isEmpty()) {
+                if (mHealthdConfig->batteryCapacityLevelPath.empty()) {
                     path.clear();
                     path.appendFormat("%s/%s/capacity_level", POWER_SUPPLY_SYSFS_PATH, name);
                     if (access(path, R_OK) == 0) mHealthdConfig->batteryCapacityLevelPath = path;
                 }
 
-                if (mHealthdConfig->batteryChargeTimeToFullNowPath.isEmpty()) {
+                if (mHealthdConfig->batteryChargeTimeToFullNowPath.empty()) {
                     path.clear();
                     path.appendFormat("%s/%s/time_to_full_now", POWER_SUPPLY_SYSFS_PATH, name);
                     if (access(path, R_OK) == 0)
                         mHealthdConfig->batteryChargeTimeToFullNowPath = path;
                 }
 
-                if (mHealthdConfig->batteryFullChargeDesignCapacityUahPath.isEmpty()) {
+                if (mHealthdConfig->batteryFullChargeDesignCapacityUahPath.empty()) {
                     path.clear();
                     path.appendFormat("%s/%s/charge_full_design", POWER_SUPPLY_SYSFS_PATH, name);
                     if (access(path, R_OK) == 0)
                         mHealthdConfig->batteryFullChargeDesignCapacityUahPath = path;
                 }
 
-                if (mHealthdConfig->batteryCurrentAvgPath.isEmpty()) {
+                if (mHealthdConfig->batteryCurrentAvgPath.empty()) {
                     path.clear();
                     path.appendFormat("%s/%s/current_avg",
                                       POWER_SUPPLY_SYSFS_PATH, name);
@@ -875,7 +875,7 @@
                         mHealthdConfig->batteryCurrentAvgPath = path;
                 }
 
-                if (mHealthdConfig->batteryChargeCounterPath.isEmpty()) {
+                if (mHealthdConfig->batteryChargeCounterPath.empty()) {
                     path.clear();
                     path.appendFormat("%s/%s/charge_counter",
                                       POWER_SUPPLY_SYSFS_PATH, name);
@@ -883,7 +883,7 @@
                         mHealthdConfig->batteryChargeCounterPath = path;
                 }
 
-                if (mHealthdConfig->batteryTemperaturePath.isEmpty()) {
+                if (mHealthdConfig->batteryTemperaturePath.empty()) {
                     path.clear();
                     path.appendFormat("%s/%s/temp", POWER_SUPPLY_SYSFS_PATH,
                                       name);
@@ -892,7 +892,7 @@
                     }
                 }
 
-                if (mHealthdConfig->batteryTechnologyPath.isEmpty()) {
+                if (mHealthdConfig->batteryTechnologyPath.empty()) {
                     path.clear();
                     path.appendFormat("%s/%s/technology",
                                       POWER_SUPPLY_SYSFS_PATH, name);
@@ -900,7 +900,7 @@
                         mHealthdConfig->batteryTechnologyPath = path;
                 }
 
-                if (mHealthdConfig->batteryStateOfHealthPath.isEmpty()) {
+                if (mHealthdConfig->batteryStateOfHealthPath.empty()) {
                     path.clear();
                     path.appendFormat("%s/%s/state_of_health", POWER_SUPPLY_SYSFS_PATH, name);
                     if (access(path, R_OK) == 0) {
@@ -913,32 +913,32 @@
                     }
                 }
 
-                if (mHealthdConfig->batteryHealthStatusPath.isEmpty()) {
+                if (mHealthdConfig->batteryHealthStatusPath.empty()) {
                     path.clear();
                     path.appendFormat("%s/%s/health_status", POWER_SUPPLY_SYSFS_PATH, name);
                     if (access(path, R_OK) == 0) mHealthdConfig->batteryHealthStatusPath = path;
                 }
 
-                if (mHealthdConfig->batteryManufacturingDatePath.isEmpty()) {
+                if (mHealthdConfig->batteryManufacturingDatePath.empty()) {
                     path.clear();
                     path.appendFormat("%s/%s/manufacturing_date", POWER_SUPPLY_SYSFS_PATH, name);
                     if (access(path, R_OK) == 0)
                         mHealthdConfig->batteryManufacturingDatePath = path;
                 }
 
-                if (mHealthdConfig->batteryFirstUsageDatePath.isEmpty()) {
+                if (mHealthdConfig->batteryFirstUsageDatePath.empty()) {
                     path.clear();
                     path.appendFormat("%s/%s/first_usage_date", POWER_SUPPLY_SYSFS_PATH, name);
                     if (access(path, R_OK) == 0) mHealthdConfig->batteryFirstUsageDatePath = path;
                 }
 
-                if (mHealthdConfig->chargingStatePath.isEmpty()) {
+                if (mHealthdConfig->chargingStatePath.empty()) {
                     path.clear();
                     path.appendFormat("%s/%s/charging_state", POWER_SUPPLY_SYSFS_PATH, name);
                     if (access(path, R_OK) == 0) mHealthdConfig->chargingStatePath = path;
                 }
 
-                if (mHealthdConfig->chargingPolicyPath.isEmpty()) {
+                if (mHealthdConfig->chargingPolicyPath.empty()) {
                     path.clear();
                     path.appendFormat("%s/%s/charging_policy", POWER_SUPPLY_SYSFS_PATH, name);
                     if (access(path, R_OK) == 0) mHealthdConfig->chargingPolicyPath = path;
@@ -968,43 +968,43 @@
         hc->periodic_chores_interval_fast = -1;
         hc->periodic_chores_interval_slow = -1;
     } else {
-        if (mHealthdConfig->batteryStatusPath.isEmpty())
+        if (mHealthdConfig->batteryStatusPath.empty())
             KLOG_WARNING(LOG_TAG, "BatteryStatusPath not found\n");
-        if (mHealthdConfig->batteryHealthPath.isEmpty())
+        if (mHealthdConfig->batteryHealthPath.empty())
             KLOG_WARNING(LOG_TAG, "BatteryHealthPath not found\n");
-        if (mHealthdConfig->batteryPresentPath.isEmpty())
+        if (mHealthdConfig->batteryPresentPath.empty())
             KLOG_WARNING(LOG_TAG, "BatteryPresentPath not found\n");
-        if (mHealthdConfig->batteryCapacityPath.isEmpty())
+        if (mHealthdConfig->batteryCapacityPath.empty())
             KLOG_WARNING(LOG_TAG, "BatteryCapacityPath not found\n");
-        if (mHealthdConfig->batteryVoltagePath.isEmpty())
+        if (mHealthdConfig->batteryVoltagePath.empty())
             KLOG_WARNING(LOG_TAG, "BatteryVoltagePath not found\n");
-        if (mHealthdConfig->batteryTemperaturePath.isEmpty())
+        if (mHealthdConfig->batteryTemperaturePath.empty())
             KLOG_WARNING(LOG_TAG, "BatteryTemperaturePath not found\n");
-        if (mHealthdConfig->batteryTechnologyPath.isEmpty())
+        if (mHealthdConfig->batteryTechnologyPath.empty())
             KLOG_WARNING(LOG_TAG, "BatteryTechnologyPath not found\n");
-        if (mHealthdConfig->batteryCurrentNowPath.isEmpty())
+        if (mHealthdConfig->batteryCurrentNowPath.empty())
             KLOG_WARNING(LOG_TAG, "BatteryCurrentNowPath not found\n");
-        if (mHealthdConfig->batteryFullChargePath.isEmpty())
+        if (mHealthdConfig->batteryFullChargePath.empty())
             KLOG_WARNING(LOG_TAG, "BatteryFullChargePath not found\n");
-        if (mHealthdConfig->batteryCycleCountPath.isEmpty())
+        if (mHealthdConfig->batteryCycleCountPath.empty())
             KLOG_WARNING(LOG_TAG, "BatteryCycleCountPath not found\n");
-        if (mHealthdConfig->batteryCapacityLevelPath.isEmpty())
+        if (mHealthdConfig->batteryCapacityLevelPath.empty())
             KLOG_WARNING(LOG_TAG, "batteryCapacityLevelPath not found\n");
-        if (mHealthdConfig->batteryChargeTimeToFullNowPath.isEmpty())
+        if (mHealthdConfig->batteryChargeTimeToFullNowPath.empty())
             KLOG_WARNING(LOG_TAG, "batteryChargeTimeToFullNowPath. not found\n");
-        if (mHealthdConfig->batteryFullChargeDesignCapacityUahPath.isEmpty())
+        if (mHealthdConfig->batteryFullChargeDesignCapacityUahPath.empty())
             KLOG_WARNING(LOG_TAG, "batteryFullChargeDesignCapacityUahPath. not found\n");
-        if (mHealthdConfig->batteryStateOfHealthPath.isEmpty())
+        if (mHealthdConfig->batteryStateOfHealthPath.empty())
             KLOG_WARNING(LOG_TAG, "batteryStateOfHealthPath not found\n");
-        if (mHealthdConfig->batteryHealthStatusPath.isEmpty())
+        if (mHealthdConfig->batteryHealthStatusPath.empty())
             KLOG_WARNING(LOG_TAG, "batteryHealthStatusPath not found\n");
-        if (mHealthdConfig->batteryManufacturingDatePath.isEmpty())
+        if (mHealthdConfig->batteryManufacturingDatePath.empty())
             KLOG_WARNING(LOG_TAG, "batteryManufacturingDatePath not found\n");
-        if (mHealthdConfig->batteryFirstUsageDatePath.isEmpty())
+        if (mHealthdConfig->batteryFirstUsageDatePath.empty())
             KLOG_WARNING(LOG_TAG, "batteryFirstUsageDatePath not found\n");
-        if (mHealthdConfig->chargingStatePath.isEmpty())
+        if (mHealthdConfig->chargingStatePath.empty())
             KLOG_WARNING(LOG_TAG, "chargingStatePath not found\n");
-        if (mHealthdConfig->chargingPolicyPath.isEmpty())
+        if (mHealthdConfig->chargingPolicyPath.empty())
             KLOG_WARNING(LOG_TAG, "chargingPolicyPath not found\n");
     }
 
diff --git a/healthd/BatteryMonitor_v1.cpp b/healthd/BatteryMonitor_v1.cpp
index b2d6518..686c338 100644
--- a/healthd/BatteryMonitor_v1.cpp
+++ b/healthd/BatteryMonitor_v1.cpp
@@ -301,7 +301,7 @@
 void BatteryMonitor::updateValues(void) {
     initHealthInfo(mHealthInfo.get());
 
-    if (!mHealthdConfig->batteryPresentPath.isEmpty())
+    if (!mHealthdConfig->batteryPresentPath.empty())
         mHealthInfo->batteryPresent = getBooleanField(mHealthdConfig->batteryPresentPath);
     else
         mHealthInfo->batteryPresent = mBatteryDevicePresent;
@@ -311,28 +311,28 @@
                                         : getIntField(mHealthdConfig->batteryCapacityPath);
     mHealthInfo->batteryVoltageMillivolts = getIntField(mHealthdConfig->batteryVoltagePath) / 1000;
 
-    if (!mHealthdConfig->batteryCurrentNowPath.isEmpty())
+    if (!mHealthdConfig->batteryCurrentNowPath.empty())
         mHealthInfo->batteryCurrentMicroamps = getIntField(mHealthdConfig->batteryCurrentNowPath);
 
-    if (!mHealthdConfig->batteryFullChargePath.isEmpty())
+    if (!mHealthdConfig->batteryFullChargePath.empty())
         mHealthInfo->batteryFullChargeUah = getIntField(mHealthdConfig->batteryFullChargePath);
 
-    if (!mHealthdConfig->batteryCycleCountPath.isEmpty())
+    if (!mHealthdConfig->batteryCycleCountPath.empty())
         mHealthInfo->batteryCycleCount = getIntField(mHealthdConfig->batteryCycleCountPath);
 
-    if (!mHealthdConfig->batteryChargeCounterPath.isEmpty())
+    if (!mHealthdConfig->batteryChargeCounterPath.empty())
         mHealthInfo->batteryChargeCounterUah =
                 getIntField(mHealthdConfig->batteryChargeCounterPath);
 
-    if (!mHealthdConfig->batteryCurrentAvgPath.isEmpty())
+    if (!mHealthdConfig->batteryCurrentAvgPath.empty())
         mHealthInfo->batteryCurrentAverageMicroamps =
                 getIntField(mHealthdConfig->batteryCurrentAvgPath);
 
-    if (!mHealthdConfig->batteryChargeTimeToFullNowPath.isEmpty())
+    if (!mHealthdConfig->batteryChargeTimeToFullNowPath.empty())
         mHealthInfo->batteryChargeTimeToFullNowSeconds =
                 getIntField(mHealthdConfig->batteryChargeTimeToFullNowPath);
 
-    if (!mHealthdConfig->batteryFullChargeDesignCapacityUahPath.isEmpty())
+    if (!mHealthdConfig->batteryFullChargeDesignCapacityUahPath.empty())
         mHealthInfo->batteryFullChargeDesignCapacityUah =
                 getIntField(mHealthdConfig->batteryFullChargeDesignCapacityUahPath);
 
@@ -420,17 +420,17 @@
                  props.batteryStatus);
 
         len = strlen(dmesgline);
-        if (!healthd_config.batteryCurrentNowPath.isEmpty()) {
+        if (!healthd_config.batteryCurrentNowPath.empty()) {
             len += snprintf(dmesgline + len, sizeof(dmesgline) - len, " c=%d",
                             props.batteryCurrentMicroamps);
         }
 
-        if (!healthd_config.batteryFullChargePath.isEmpty()) {
+        if (!healthd_config.batteryFullChargePath.empty()) {
             len += snprintf(dmesgline + len, sizeof(dmesgline) - len, " fc=%d",
                             props.batteryFullChargeUah);
         }
 
-        if (!healthd_config.batteryCycleCountPath.isEmpty()) {
+        if (!healthd_config.batteryCycleCountPath.empty()) {
             len += snprintf(dmesgline + len, sizeof(dmesgline) - len, " cc=%d",
                             props.batteryCycleCount);
         }
@@ -464,7 +464,7 @@
 
 int BatteryMonitor::getChargeStatus() {
     BatteryStatus result = BatteryStatus::UNKNOWN;
-    if (!mHealthdConfig->batteryStatusPath.isEmpty()) {
+    if (!mHealthdConfig->batteryStatusPath.empty()) {
         std::string buf;
         if (readFromFile(mHealthdConfig->batteryStatusPath, &buf) > 0)
             result = getBatteryStatus(buf.c_str());
@@ -480,7 +480,7 @@
 
     switch(id) {
     case BATTERY_PROP_CHARGE_COUNTER:
-        if (!mHealthdConfig->batteryChargeCounterPath.isEmpty()) {
+        if (!mHealthdConfig->batteryChargeCounterPath.empty()) {
             val->valueInt64 =
                 getIntField(mHealthdConfig->batteryChargeCounterPath);
             ret = OK;
@@ -490,7 +490,7 @@
         break;
 
     case BATTERY_PROP_CURRENT_NOW:
-        if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
+        if (!mHealthdConfig->batteryCurrentNowPath.empty()) {
             val->valueInt64 =
                 getIntField(mHealthdConfig->batteryCurrentNowPath);
             ret = OK;
@@ -500,7 +500,7 @@
         break;
 
     case BATTERY_PROP_CURRENT_AVG:
-        if (!mHealthdConfig->batteryCurrentAvgPath.isEmpty()) {
+        if (!mHealthdConfig->batteryCurrentAvgPath.empty()) {
             val->valueInt64 =
                 getIntField(mHealthdConfig->batteryCurrentAvgPath);
             ret = OK;
@@ -510,7 +510,7 @@
         break;
 
     case BATTERY_PROP_CAPACITY:
-        if (!mHealthdConfig->batteryCapacityPath.isEmpty()) {
+        if (!mHealthdConfig->batteryCapacityPath.empty()) {
             val->valueInt64 =
                 getIntField(mHealthdConfig->batteryCapacityPath);
             ret = OK;
@@ -557,35 +557,35 @@
              props.batteryVoltageMillivolts, props.batteryTemperatureTenthsCelsius);
     write(fd, vs, strlen(vs));
 
-    if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
+    if (!mHealthdConfig->batteryCurrentNowPath.empty()) {
         v = getIntField(mHealthdConfig->batteryCurrentNowPath);
         snprintf(vs, sizeof(vs), "current now: %d\n", v);
         write(fd, vs, strlen(vs));
     }
 
-    if (!mHealthdConfig->batteryCurrentAvgPath.isEmpty()) {
+    if (!mHealthdConfig->batteryCurrentAvgPath.empty()) {
         v = getIntField(mHealthdConfig->batteryCurrentAvgPath);
         snprintf(vs, sizeof(vs), "current avg: %d\n", v);
         write(fd, vs, strlen(vs));
     }
 
-    if (!mHealthdConfig->batteryChargeCounterPath.isEmpty()) {
+    if (!mHealthdConfig->batteryChargeCounterPath.empty()) {
         v = getIntField(mHealthdConfig->batteryChargeCounterPath);
         snprintf(vs, sizeof(vs), "charge counter: %d\n", v);
         write(fd, vs, strlen(vs));
     }
 
-    if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
+    if (!mHealthdConfig->batteryCurrentNowPath.empty()) {
         snprintf(vs, sizeof(vs), "current now: %d\n", props.batteryCurrentMicroamps);
         write(fd, vs, strlen(vs));
     }
 
-    if (!mHealthdConfig->batteryCycleCountPath.isEmpty()) {
+    if (!mHealthdConfig->batteryCycleCountPath.empty()) {
         snprintf(vs, sizeof(vs), "cycle count: %d\n", props.batteryCycleCount);
         write(fd, vs, strlen(vs));
     }
 
-    if (!mHealthdConfig->batteryFullChargePath.isEmpty()) {
+    if (!mHealthdConfig->batteryFullChargePath.empty()) {
         snprintf(vs, sizeof(vs), "Full charge: %d\n", props.batteryFullChargeUah);
         write(fd, vs, strlen(vs));
     }
@@ -635,7 +635,7 @@
                 if (isScopedPowerSupply(name)) continue;
                 mBatteryDevicePresent = true;
 
-                if (mHealthdConfig->batteryStatusPath.isEmpty()) {
+                if (mHealthdConfig->batteryStatusPath.empty()) {
                     path.clear();
                     path.appendFormat("%s/%s/status", POWER_SUPPLY_SYSFS_PATH,
                                       name);
@@ -643,7 +643,7 @@
                         mHealthdConfig->batteryStatusPath = path;
                 }
 
-                if (mHealthdConfig->batteryHealthPath.isEmpty()) {
+                if (mHealthdConfig->batteryHealthPath.empty()) {
                     path.clear();
                     path.appendFormat("%s/%s/health", POWER_SUPPLY_SYSFS_PATH,
                                       name);
@@ -651,7 +651,7 @@
                         mHealthdConfig->batteryHealthPath = path;
                 }
 
-                if (mHealthdConfig->batteryPresentPath.isEmpty()) {
+                if (mHealthdConfig->batteryPresentPath.empty()) {
                     path.clear();
                     path.appendFormat("%s/%s/present", POWER_SUPPLY_SYSFS_PATH,
                                       name);
@@ -659,7 +659,7 @@
                         mHealthdConfig->batteryPresentPath = path;
                 }
 
-                if (mHealthdConfig->batteryCapacityPath.isEmpty()) {
+                if (mHealthdConfig->batteryCapacityPath.empty()) {
                     path.clear();
                     path.appendFormat("%s/%s/capacity", POWER_SUPPLY_SYSFS_PATH,
                                       name);
@@ -667,7 +667,7 @@
                         mHealthdConfig->batteryCapacityPath = path;
                 }
 
-                if (mHealthdConfig->batteryVoltagePath.isEmpty()) {
+                if (mHealthdConfig->batteryVoltagePath.empty()) {
                     path.clear();
                     path.appendFormat("%s/%s/voltage_now",
                                       POWER_SUPPLY_SYSFS_PATH, name);
@@ -676,7 +676,7 @@
                     }
                 }
 
-                if (mHealthdConfig->batteryFullChargePath.isEmpty()) {
+                if (mHealthdConfig->batteryFullChargePath.empty()) {
                     path.clear();
                     path.appendFormat("%s/%s/charge_full",
                                       POWER_SUPPLY_SYSFS_PATH, name);
@@ -684,7 +684,7 @@
                         mHealthdConfig->batteryFullChargePath = path;
                 }
 
-                if (mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
+                if (mHealthdConfig->batteryCurrentNowPath.empty()) {
                     path.clear();
                     path.appendFormat("%s/%s/current_now",
                                       POWER_SUPPLY_SYSFS_PATH, name);
@@ -692,7 +692,7 @@
                         mHealthdConfig->batteryCurrentNowPath = path;
                 }
 
-                if (mHealthdConfig->batteryCycleCountPath.isEmpty()) {
+                if (mHealthdConfig->batteryCycleCountPath.empty()) {
                     path.clear();
                     path.appendFormat("%s/%s/cycle_count",
                                       POWER_SUPPLY_SYSFS_PATH, name);
@@ -700,27 +700,27 @@
                         mHealthdConfig->batteryCycleCountPath = path;
                 }
 
-                if (mHealthdConfig->batteryCapacityLevelPath.isEmpty()) {
+                if (mHealthdConfig->batteryCapacityLevelPath.empty()) {
                     path.clear();
                     path.appendFormat("%s/%s/capacity_level", POWER_SUPPLY_SYSFS_PATH, name);
                     if (access(path, R_OK) == 0) mHealthdConfig->batteryCapacityLevelPath = path;
                 }
 
-                if (mHealthdConfig->batteryChargeTimeToFullNowPath.isEmpty()) {
+                if (mHealthdConfig->batteryChargeTimeToFullNowPath.empty()) {
                     path.clear();
                     path.appendFormat("%s/%s/time_to_full_now", POWER_SUPPLY_SYSFS_PATH, name);
                     if (access(path, R_OK) == 0)
                         mHealthdConfig->batteryChargeTimeToFullNowPath = path;
                 }
 
-                if (mHealthdConfig->batteryFullChargeDesignCapacityUahPath.isEmpty()) {
+                if (mHealthdConfig->batteryFullChargeDesignCapacityUahPath.empty()) {
                     path.clear();
                     path.appendFormat("%s/%s/charge_full_design", POWER_SUPPLY_SYSFS_PATH, name);
                     if (access(path, R_OK) == 0)
                         mHealthdConfig->batteryFullChargeDesignCapacityUahPath = path;
                 }
 
-                if (mHealthdConfig->batteryCurrentAvgPath.isEmpty()) {
+                if (mHealthdConfig->batteryCurrentAvgPath.empty()) {
                     path.clear();
                     path.appendFormat("%s/%s/current_avg",
                                       POWER_SUPPLY_SYSFS_PATH, name);
@@ -728,7 +728,7 @@
                         mHealthdConfig->batteryCurrentAvgPath = path;
                 }
 
-                if (mHealthdConfig->batteryChargeCounterPath.isEmpty()) {
+                if (mHealthdConfig->batteryChargeCounterPath.empty()) {
                     path.clear();
                     path.appendFormat("%s/%s/charge_counter",
                                       POWER_SUPPLY_SYSFS_PATH, name);
@@ -736,7 +736,7 @@
                         mHealthdConfig->batteryChargeCounterPath = path;
                 }
 
-                if (mHealthdConfig->batteryTemperaturePath.isEmpty()) {
+                if (mHealthdConfig->batteryTemperaturePath.empty()) {
                     path.clear();
                     path.appendFormat("%s/%s/temp", POWER_SUPPLY_SYSFS_PATH,
                                       name);
@@ -745,7 +745,7 @@
                     }
                 }
 
-                if (mHealthdConfig->batteryTechnologyPath.isEmpty()) {
+                if (mHealthdConfig->batteryTechnologyPath.empty()) {
                     path.clear();
                     path.appendFormat("%s/%s/technology",
                                       POWER_SUPPLY_SYSFS_PATH, name);
@@ -777,31 +777,31 @@
         hc->periodic_chores_interval_fast = -1;
         hc->periodic_chores_interval_slow = -1;
     } else {
-        if (mHealthdConfig->batteryStatusPath.isEmpty())
+        if (mHealthdConfig->batteryStatusPath.empty())
             KLOG_WARNING(LOG_TAG, "BatteryStatusPath not found\n");
-        if (mHealthdConfig->batteryHealthPath.isEmpty())
+        if (mHealthdConfig->batteryHealthPath.empty())
             KLOG_WARNING(LOG_TAG, "BatteryHealthPath not found\n");
-        if (mHealthdConfig->batteryPresentPath.isEmpty())
+        if (mHealthdConfig->batteryPresentPath.empty())
             KLOG_WARNING(LOG_TAG, "BatteryPresentPath not found\n");
-        if (mHealthdConfig->batteryCapacityPath.isEmpty())
+        if (mHealthdConfig->batteryCapacityPath.empty())
             KLOG_WARNING(LOG_TAG, "BatteryCapacityPath not found\n");
-        if (mHealthdConfig->batteryVoltagePath.isEmpty())
+        if (mHealthdConfig->batteryVoltagePath.empty())
             KLOG_WARNING(LOG_TAG, "BatteryVoltagePath not found\n");
-        if (mHealthdConfig->batteryTemperaturePath.isEmpty())
+        if (mHealthdConfig->batteryTemperaturePath.empty())
             KLOG_WARNING(LOG_TAG, "BatteryTemperaturePath not found\n");
-        if (mHealthdConfig->batteryTechnologyPath.isEmpty())
+        if (mHealthdConfig->batteryTechnologyPath.empty())
             KLOG_WARNING(LOG_TAG, "BatteryTechnologyPath not found\n");
-        if (mHealthdConfig->batteryCurrentNowPath.isEmpty())
+        if (mHealthdConfig->batteryCurrentNowPath.empty())
             KLOG_WARNING(LOG_TAG, "BatteryCurrentNowPath not found\n");
-        if (mHealthdConfig->batteryFullChargePath.isEmpty())
+        if (mHealthdConfig->batteryFullChargePath.empty())
             KLOG_WARNING(LOG_TAG, "BatteryFullChargePath not found\n");
-        if (mHealthdConfig->batteryCycleCountPath.isEmpty())
+        if (mHealthdConfig->batteryCycleCountPath.empty())
             KLOG_WARNING(LOG_TAG, "BatteryCycleCountPath not found\n");
-        if (mHealthdConfig->batteryCapacityLevelPath.isEmpty())
+        if (mHealthdConfig->batteryCapacityLevelPath.empty())
             KLOG_WARNING(LOG_TAG, "batteryCapacityLevelPath not found\n");
-        if (mHealthdConfig->batteryChargeTimeToFullNowPath.isEmpty())
+        if (mHealthdConfig->batteryChargeTimeToFullNowPath.empty())
             KLOG_WARNING(LOG_TAG, "batteryChargeTimeToFullNowPath. not found\n");
-        if (mHealthdConfig->batteryFullChargeDesignCapacityUahPath.isEmpty())
+        if (mHealthdConfig->batteryFullChargeDesignCapacityUahPath.empty())
             KLOG_WARNING(LOG_TAG, "batteryFullChargeDesignCapacityUahPath. not found\n");
     }
 
diff --git a/init/builtins.cpp b/init/builtins.cpp
index a5b762c..a70e866 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -746,6 +746,7 @@
 static Result<void> do_start(const BuiltinArguments& args) {
     Service* svc = ServiceList::GetInstance().FindService(args[1]);
     if (!svc) return Error() << "service " << args[1] << " not found";
+    errno = 0;
     if (auto result = svc->Start(); !result.ok()) {
         return ErrorIgnoreEnoent() << "Could not start service: " << result.error();
     }
@@ -1304,8 +1305,7 @@
     }
 
     if (!bootstrap) {
-        // Now start delayed services
-        ServiceList::GetInstance().MarkServicesUpdate();
+        ServiceList::GetInstance().StartDelayedServices();
     }
     return {};
 }
diff --git a/init/first_stage_init.cpp b/init/first_stage_init.cpp
index 7fabbac..3239eb7 100644
--- a/init/first_stage_init.cpp
+++ b/init/first_stage_init.cpp
@@ -35,6 +35,7 @@
 #include <android-base/chrono_utils.h>
 #include <android-base/file.h>
 #include <android-base/logging.h>
+#include <android-base/stringprintf.h>
 #include <modprobe/modprobe.h>
 #include <private/android_filesystem_config.h>
 
@@ -67,7 +68,7 @@
 void FreeRamdisk(DIR* dir, dev_t dev) {
     int dfd = dirfd(dir);
 
-    dirent* de;
+    dirent* de = nullptr;
     while ((de = readdir(dir)) != nullptr) {
         if (de->d_name == "."s || de->d_name == ".."s) {
             continue;
@@ -76,7 +77,7 @@
         bool is_dir = false;
 
         if (de->d_type == DT_DIR || de->d_type == DT_UNKNOWN) {
-            struct stat info;
+            struct stat info {};
             if (fstatat(dfd, de->d_name, &info, AT_SYMLINK_NOFOLLOW) != 0) {
                 continue;
             }
@@ -153,6 +154,15 @@
         Copy(snapuserd, dst);
     }
 }
+
+std::string GetPageSizeSuffix() {
+    static const size_t page_size = sysconf(_SC_PAGE_SIZE);
+    if (page_size <= 4096) {
+        return "";
+    }
+    return android::base::StringPrintf("_%zuk", page_size / 1024);
+}
+
 }  // namespace
 
 std::string GetModuleLoadList(BootMode boot_mode, const std::string& dir_path) {
@@ -171,7 +181,7 @@
     }
 
     if (module_load_file != "modules.load") {
-        struct stat fileStat;
+        struct stat fileStat {};
         std::string load_path = dir_path + "/" + module_load_file;
         // Fall back to modules.load if the other files aren't accessible
         if (stat(load_path.c_str(), &fileStat)) {
@@ -185,11 +195,11 @@
 #define MODULE_BASE_DIR "/lib/modules"
 bool LoadKernelModules(BootMode boot_mode, bool want_console, bool want_parallel,
                        int& modules_loaded) {
-    struct utsname uts;
+    struct utsname uts {};
     if (uname(&uts)) {
         LOG(FATAL) << "Failed to get kernel version.";
     }
-    int major, minor;
+    int major = 0, minor = 0;
     if (sscanf(uts.release, "%d.%d", &major, &minor) != 2) {
         LOG(FATAL) << "Failed to parse kernel version " << uts.release;
     }
@@ -199,13 +209,21 @@
         LOG(INFO) << "Unable to open /lib/modules, skipping module loading.";
         return true;
     }
-    dirent* entry;
+    dirent* entry = nullptr;
     std::vector<std::string> module_dirs;
+    const std::string release_specific_module_dir = uts.release + GetPageSizeSuffix();
     while ((entry = readdir(base_dir.get()))) {
         if (entry->d_type != DT_DIR) {
             continue;
         }
-        int dir_major, dir_minor;
+        if (entry->d_name == release_specific_module_dir) {
+            LOG(INFO) << "Release specific kernel module dir " << release_specific_module_dir
+                      << " found, loading modules from here with no fallbacks.";
+            module_dirs.clear();
+            module_dirs.emplace_back(entry->d_name);
+            break;
+        }
+        int dir_major = 0, dir_minor = 0;
         if (sscanf(entry->d_name, "%d.%d", &dir_major, &dir_minor) != 2 || dir_major != major ||
             dir_minor != minor) {
             continue;
@@ -228,6 +246,7 @@
         bool retval = m.LoadListedModules(!want_console);
         modules_loaded = m.GetModuleCount();
         if (modules_loaded > 0) {
+            LOG(INFO) << "Loaded " << modules_loaded << " modules from " << dir_path;
             return retval;
         }
     }
@@ -237,6 +256,7 @@
                                   : m.LoadListedModules(!want_console);
     modules_loaded = m.GetModuleCount();
     if (modules_loaded > 0) {
+        LOG(INFO) << "Loaded " << modules_loaded << " modules from " << MODULE_BASE_DIR;
         return retval;
     }
     return true;
@@ -374,7 +394,7 @@
         PLOG(ERROR) << "Could not opendir(\"/\"), not freeing ramdisk";
     }
 
-    struct stat old_root_info;
+    struct stat old_root_info {};
     if (stat("/", &old_root_info) != 0) {
         PLOG(ERROR) << "Could not stat(\"/\"), not freeing ramdisk";
         old_root_dir.reset();
@@ -483,7 +503,7 @@
         }
     }
 
-    struct stat new_root_info;
+    struct stat new_root_info {};
     if (stat("/", &new_root_info) != 0) {
         PLOG(ERROR) << "Could not stat(\"/\"), not freeing ramdisk";
         old_root_dir.reset();
diff --git a/init/service.cpp b/init/service.cpp
index a0b3478..5e900ee 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -420,7 +420,7 @@
         }
     });
 
-    if (is_updatable() && !ServiceList::GetInstance().IsServicesUpdated()) {
+    if (is_updatable() && !IsDefaultMountNamespaceReady()) {
         // Don't delay the service for ExecStart() as the semantic is that
         // the caller might depend on the side effect of the execution.
         return Error() << "Cannot start an updatable service '" << name_
@@ -581,7 +581,7 @@
         }
     });
 
-    if (is_updatable() && !ServiceList::GetInstance().IsServicesUpdated()) {
+    if (is_updatable() && !IsDefaultMountNamespaceReady()) {
         ServiceList::GetInstance().DelayService(*this);
         return Error() << "Cannot start an updatable service '" << name_
                        << "' before configs from APEXes are all loaded. "
diff --git a/init/service.h b/init/service.h
index b858eef..9f09cef 100644
--- a/init/service.h
+++ b/init/service.h
@@ -60,7 +60,7 @@
 #define SVC_GENTLE_KILL 0x2000  // This service should be stopped with SIGTERM instead of SIGKILL
                                 // Will still be SIGKILLed after timeout period of 200 ms
 
-#define NR_SVC_SUPP_GIDS 12    // twelve supplementary groups
+#define NR_SVC_SUPP_GIDS 32    // thirty two supplementary groups
 
 namespace android {
 namespace init {
diff --git a/init/service_list.cpp b/init/service_list.cpp
index 937d82e..1c56e8a 100644
--- a/init/service_list.cpp
+++ b/init/service_list.cpp
@@ -76,10 +76,7 @@
     return post_data_;
 }
 
-void ServiceList::MarkServicesUpdate() {
-    services_update_finished_ = true;
-
-    // start the delayed services
+void ServiceList::StartDelayedServices() {
     for (const auto& name : delayed_service_names_) {
         Service* service = FindService(name);
         if (service == nullptr) {
@@ -94,7 +91,7 @@
 }
 
 void ServiceList::DelayService(const Service& service) {
-    if (services_update_finished_) {
+    if (IsDefaultMountNamespaceReady()) {
         LOG(ERROR) << "Cannot delay the start of service '" << service.name()
                    << "' because all services are already updated. Ignoring.";
         return;
diff --git a/init/service_list.h b/init/service_list.h
index f858bc3..44e8453 100644
--- a/init/service_list.h
+++ b/init/service_list.h
@@ -85,14 +85,10 @@
 
     void MarkPostData();
     bool IsPostData();
-    void MarkServicesUpdate();
-    bool IsServicesUpdated() const { return services_update_finished_; }
     void DelayService(const Service& service);
+    void StartDelayedServices();
 
-    void ResetState() {
-        post_data_ = false;
-        services_update_finished_ = false;
-    }
+    void ResetState() { post_data_ = false; }
 
     auto size() const { return services_.size(); }
 
@@ -100,7 +96,6 @@
     std::vector<std::unique_ptr<Service>> services_;
 
     bool post_data_ = false;
-    bool services_update_finished_ = false;
     std::vector<std::string> delayed_service_names_;
 };
 
diff --git a/libcutils/include/cutils/threads.h b/libcutils/include/cutils/threads.h
deleted file mode 100644
index 9bc3429..0000000
--- a/libcutils/include/cutils/threads.h
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * Copyright (C) 2007 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.
- */
diff --git a/libcutils/include_outside_system/cutils/threads.h b/libcutils/include_outside_system/cutils/threads.h
deleted file mode 120000
index 99330ff..0000000
--- a/libcutils/include_outside_system/cutils/threads.h
+++ /dev/null
@@ -1 +0,0 @@
-../../include/cutils/threads.h
\ No newline at end of file
diff --git a/libsparse/Android.bp b/libsparse/Android.bp
index 5a7d0fc..44907a1 100644
--- a/libsparse/Android.bp
+++ b/libsparse/Android.bp
@@ -41,9 +41,8 @@
     ],
 }
 
-cc_binary {
+cc_binary_host {
     name: "simg2img",
-    host_supported: true,
     srcs: [
         "simg2img.cpp",
         "sparse_crc32.cpp",
@@ -62,9 +61,8 @@
     },
 }
 
-cc_binary {
+cc_binary_host {
     name: "img2simg",
-    host_supported: true,
     srcs: ["img2simg.cpp"],
     static_libs: [
         "libsparse",
diff --git a/libutils/String8.cpp b/libutils/String8.cpp
index 79b7edf..2b72847 100644
--- a/libutils/String8.cpp
+++ b/libutils/String8.cpp
@@ -39,10 +39,6 @@
 
 namespace android {
 
-// Separator used by resource paths. This is not platform dependent contrary
-// to OS_PATH_SEPARATOR.
-#define RES_PATH_SEPARATOR '/'
-
 static inline char* getEmptyString() {
     static SharedBuffer* gEmptyStringBuf = [] {
         SharedBuffer* buf = SharedBuffer::alloc(1);
@@ -582,20 +578,4 @@
     }
 }
 
-String8& String8::convertToResPath()
-{
-#if OS_PATH_SEPARATOR != RES_PATH_SEPARATOR
-    size_t len = length();
-    if (len > 0) {
-        char * buf = lockBuffer(len);
-        for (char * end = buf + len; buf < end; ++buf) {
-            if (*buf == OS_PATH_SEPARATOR)
-                *buf = RES_PATH_SEPARATOR;
-        }
-        unlockBuffer(len);
-    }
-#endif
-    return *this;
-}
-
 }; // namespace android
diff --git a/libutils/String8_fuzz.cpp b/libutils/String8_fuzz.cpp
index e5dcd31..6f7a54f 100644
--- a/libutils/String8_fuzz.cpp
+++ b/libutils/String8_fuzz.cpp
@@ -34,7 +34,7 @@
                     str1->bytes();
                 },
                 [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
-                    str1->isEmpty();
+                    str1->empty();
                 },
                 [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
                     str1->length();
@@ -83,9 +83,6 @@
                     str1->getPathDir();
                 },
                 [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
-                    str1->convertToResPath();
-                },
-                [](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());
diff --git a/libutils/abi-dumps/arm64/source-based/libutils.so.lsdump b/libutils/abi-dumps/arm64/source-based/libutils.so.lsdump
index c89af9e..46badde 100644
--- a/libutils/abi-dumps/arm64/source-based/libutils.so.lsdump
+++ b/libutils/abi-dumps/arm64/source-based/libutils.so.lsdump
@@ -725,9 +725,6 @@
    "name" : "_ZN7android7String813appendFormatVEPKcSt9__va_list"
   },
   {
-   "name" : "_ZN7android7String816convertToResPathEv"
-  },
-  {
    "name" : "_ZN7android7String85clearEv"
   },
   {
@@ -6928,19 +6925,6 @@
    "source_file" : "system/core/libutils/include/utils/String8.h"
   },
   {
-   "function_name" : "android::String8::convertToResPath",
-   "linker_set_key" : "_ZN7android7String816convertToResPathEv",
-   "parameters" :
-   [
-    {
-     "is_this_ptr" : true,
-     "referenced_type" : "_ZTIPN7android7String8E"
-    }
-   ],
-   "return_type" : "_ZTIRN7android7String8E",
-   "source_file" : "system/core/libutils/include/utils/String8.h"
-  },
-  {
    "function_name" : "android::String8::clear",
    "linker_set_key" : "_ZN7android7String85clearEv",
    "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 f88da15..219c766 100644
--- a/libutils/abi-dumps/arm_arm64/source-based/libutils.so.lsdump
+++ b/libutils/abi-dumps/arm_arm64/source-based/libutils.so.lsdump
@@ -725,9 +725,6 @@
    "name" : "_ZN7android7String813appendFormatVEPKcSt9__va_list"
   },
   {
-   "name" : "_ZN7android7String816convertToResPathEv"
-  },
-  {
    "name" : "_ZN7android7String85clearEv"
   },
   {
@@ -6924,19 +6921,6 @@
    "source_file" : "system/core/libutils/include/utils/String8.h"
   },
   {
-   "function_name" : "android::String8::convertToResPath",
-   "linker_set_key" : "_ZN7android7String816convertToResPathEv",
-   "parameters" :
-   [
-    {
-     "is_this_ptr" : true,
-     "referenced_type" : "_ZTIPN7android7String8E"
-    }
-   ],
-   "return_type" : "_ZTIRN7android7String8E",
-   "source_file" : "system/core/libutils/include/utils/String8.h"
-  },
-  {
    "function_name" : "android::String8::clear",
    "linker_set_key" : "_ZN7android7String85clearEv",
    "parameters" :
diff --git a/libutils/include/utils/String16.h b/libutils/include/utils/String16.h
index d719aea..b48b907 100644
--- a/libutils/include/utils/String16.h
+++ b/libutils/include/utils/String16.h
@@ -60,6 +60,10 @@
     static inline std::string   std_string(const String16& str);
 public:
             size_t              size() const;
+    inline  bool                empty() const;
+
+    inline  size_t              length() const;
+
             void                setTo(const String16& other);
             status_t            setTo(const char16_t* other);
             status_t            setTo(const char16_t* other, size_t len);
@@ -250,6 +254,16 @@
     return std::string(String8(str).c_str());
 }
 
+inline bool String16::empty() const
+{
+    return length() == 0;
+}
+
+inline size_t String16::length() const
+{
+    return size();
+}
+
 inline String16& String16::operator=(const String16& other)
 {
     setTo(other);
diff --git a/libutils/include/utils/String8.h b/libutils/include/utils/String8.h
index e58f1a5..ea25c6a 100644
--- a/libutils/include/utils/String8.h
+++ b/libutils/include/utils/String8.h
@@ -52,8 +52,6 @@
     explicit                    String8(const char32_t* o, size_t numChars);
                                 ~String8();
 
-    static inline const String8 empty();
-
     static String8              format(const char* fmt, ...) __attribute__((format (printf, 1, 2)));
     static String8              formatV(const char* fmt, va_list args);
 
@@ -66,6 +64,7 @@
 
     inline  size_t              size() const;
     inline  size_t              bytes() const;
+    inline  bool                empty() const;
     inline  bool                isEmpty() const;
 
             size_t              length() const;
@@ -202,15 +201,6 @@
                                              { String8 p(*this); p.appendPath(leaf); return p; }
     String8 appendPathCopy(const String8& leaf) const { return appendPathCopy(leaf.c_str()); }
 
-    /*
-     * Converts all separators in this string to /, the default path separator.
-     *
-     * If the default OS separator is backslash, this converts all
-     * backslashes to slashes, in-place. Otherwise it does nothing.
-     * Returns self.
-     */
-    String8& convertToResPath();
-
 private:
             status_t            real_append(const char* other, size_t numChars);
             char*               find_extension(void) const;
@@ -240,10 +230,6 @@
     return compare_type(lhs, rhs) < 0;
 }
 
-inline const String8 String8::empty() {
-    return String8();
-}
-
 inline const char* String8::c_str() const
 {
     return mString;
@@ -263,6 +249,11 @@
     return length();
 }
 
+inline bool String8::empty() const
+{
+    return length() == 0;
+}
+
 inline bool String8::isEmpty() const
 {
     return length() == 0;
diff --git a/rootdir/Android.bp b/rootdir/Android.bp
index e98733a..c8a3cd6 100644
--- a/rootdir/Android.bp
+++ b/rootdir/Android.bp
@@ -17,12 +17,30 @@
 }
 
 prebuilt_etc {
+    name: "init.boringssl.zygote64_32.rc",
+    src: "init.boringssl.zygote64_32.rc",
+    sub_dir: "init/hw",
+    symlinks: [
+        "init.boringssl.zygote32.rc",
+        "init.boringssl.no_zygote.rc",
+    ],
+}
+
+prebuilt_etc {
+    name: "init.boringssl.zygote64.rc",
+    src: "init.boringssl.zygote64.rc",
+    sub_dir: "init/hw",
+}
+
+prebuilt_etc {
     name: "init.rc",
     src: "init.rc",
     sub_dir: "init/hw",
     required: [
         "fsverity_init",
         "platform-bootclasspath",
+        "init.boringssl.zygote64.rc",
+        "init.boringssl.zygote64_32.rc",
     ],
 }
 
diff --git a/rootdir/init.boringssl.zygote64.rc b/rootdir/init.boringssl.zygote64.rc
new file mode 100644
index 0000000..3f49fea
--- /dev/null
+++ b/rootdir/init.boringssl.zygote64.rc
@@ -0,0 +1,4 @@
+on init && property:ro.product.cpu.abilist64=*
+    exec_start boringssl_self_test64
+on property:apexd.status=ready && property:ro.product.cpu.abilist64=*
+    exec_start boringssl_self_test_apex64
diff --git a/rootdir/init.boringssl.zygote64_32.rc b/rootdir/init.boringssl.zygote64_32.rc
new file mode 100644
index 0000000..c0be42d
--- /dev/null
+++ b/rootdir/init.boringssl.zygote64_32.rc
@@ -0,0 +1,8 @@
+on init && property:ro.product.cpu.abilist32=*
+    exec_start boringssl_self_test32
+on init && property:ro.product.cpu.abilist64=*
+    exec_start boringssl_self_test64
+on property:apexd.status=ready && property:ro.product.cpu.abilist32=*
+    exec_start boringssl_self_test_apex32
+on property:apexd.status=ready && property:ro.product.cpu.abilist64=*
+    exec_start boringssl_self_test_apex64
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 0d31cdc..487e5da 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -459,14 +459,7 @@
     start vndservicemanager
 
 # Run boringssl self test for each ABI.  Any failures trigger reboot to firmware.
-on init && property:ro.product.cpu.abilist32=*
-    exec_start boringssl_self_test32
-on init && property:ro.product.cpu.abilist64=*
-    exec_start boringssl_self_test64
-on property:apexd.status=ready && property:ro.product.cpu.abilist32=*
-    exec_start boringssl_self_test_apex32
-on property:apexd.status=ready && property:ro.product.cpu.abilist64=*
-    exec_start boringssl_self_test_apex64
+import /system/etc/init/hw/init.boringssl.${ro.zygote}.rc
 
 service boringssl_self_test32 /system/bin/boringssl_self_test32
     reboot_on_failure reboot,boringssl-self-check-failed
diff --git a/trusty/utils/coverage-controller/Android.bp b/trusty/utils/coverage-controller/Android.bp
index 1aa88cc..e6d30d9 100644
--- a/trusty/utils/coverage-controller/Android.bp
+++ b/trusty/utils/coverage-controller/Android.bp
@@ -17,7 +17,7 @@
 }
 
 cc_binary {
-    name: "coverage-controller",
+    name: "trusty-coverage-controller",
     vendor: true,
 
     srcs: ["controller.cpp"],
diff --git a/trusty/utils/coverage-controller/controller.cpp b/trusty/utils/coverage-controller/controller.cpp
index 730c010..0047046 100644
--- a/trusty/utils/coverage-controller/controller.cpp
+++ b/trusty/utils/coverage-controller/controller.cpp
@@ -14,11 +14,16 @@
  * limitations under the License.
  */
 
+#include <android-base/stringprintf.h>
+#include <array>
 #include <getopt.h>
+#include <inttypes.h>
+#include <memory>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
 #include <trusty/line-coverage/coverage.h>
 #include <trusty/tipc.h>
-#include <array>
-#include <memory>
 #include <vector>
 
 #include "controller.h"
@@ -48,10 +53,10 @@
 
             if (complete_cnt != counters[index] && start_cnt == complete_cnt) {
                 WRITE_ONCE(control->cntrl_flags, FLAG_NONE);
-                std::string fmt = "/%d.%lu.profraw";
-                int sz = std::snprintf(nullptr, 0, fmt.c_str(), index, counters[index]);
-                std::string filename(sz+1, '.');
-                std::sprintf(filename.data(), fmt.c_str(), index, counters[index]);
+                std::string filename;
+                filename = android::base::StringPrintf("/%s.%lu.profraw",
+                                                    uuid_list_[index].c_str(),
+                                                    counters[index]);
                 filename.insert(0, output_dir);
                 android::base::Result<void> res = record_list_[index]->SaveFile(filename);
                 counters[index]++;
@@ -79,6 +84,7 @@
     struct line_coverage_client_resp resp;
     uint32_t cur_index = record_list_.size();
     struct uuid zero_uuid = {0, 0, 0, { 0 }};
+    char uuid_str[UUID_STR_SIZE];
     req.hdr.cmd = LINE_COVERAGE_CLIENT_CMD_SEND_LIST;
     int rc = write(coverage_srv_fd, &req, sizeof(req));
         if (rc != (int)sizeof(req)) {
@@ -98,6 +104,21 @@
             }
             if(uuid_set_.find(resp.send_list_args.uuid) == uuid_set_.end()) {
                 uuid_set_.insert(resp.send_list_args.uuid);
+                sprintf(uuid_str,
+                    "%08" PRIx32 "-%04" PRIx16 "-%04" PRIx16 "-%02" PRIx8 "%02" PRIx8
+                    "-%02" PRIx8 "%02" PRIx8 "%02" PRIx8 "%02" PRIx8 "%02" PRIx8 "%02" PRIx8,
+                    resp.send_list_args.uuid.time_low,
+                    resp.send_list_args.uuid.time_mid,
+                    resp.send_list_args.uuid.time_hi_and_version,
+                    resp.send_list_args.uuid.clock_seq_and_node[0],
+                    resp.send_list_args.uuid.clock_seq_and_node[1],
+                    resp.send_list_args.uuid.clock_seq_and_node[2],
+                    resp.send_list_args.uuid.clock_seq_and_node[3],
+                    resp.send_list_args.uuid.clock_seq_and_node[4],
+                    resp.send_list_args.uuid.clock_seq_and_node[5],
+                    resp.send_list_args.uuid.clock_seq_and_node[6],
+                    resp.send_list_args.uuid.clock_seq_and_node[7]);
+                uuid_list_.push_back(uuid_str);
                 record_list_.push_back(std::make_unique<CoverageRecord>(TIPC_DEV,
                                                                     &resp.send_list_args.uuid));
                 counters.push_back(0);
diff --git a/trusty/utils/coverage-controller/controller.h b/trusty/utils/coverage-controller/controller.h
index b771c16..f7789bf 100644
--- a/trusty/utils/coverage-controller/controller.h
+++ b/trusty/utils/coverage-controller/controller.h
@@ -26,6 +26,8 @@
 #define TEST_SRV_PORT "com.android.trusty.sancov.test.srv"
 #define TEST_SRV_MODULE "srv.syms.elf"
 
+#define UUID_STR_SIZE (37)
+
 #define FLAG_NONE               0x0
 #define FLAG_RUN                0x1
 #define FLAG_TOGGLE_CLEAR       0x2
@@ -52,6 +54,7 @@
     private:
         std::vector<std::unique_ptr<line_coverage::CoverageRecord>>record_list_;
         std::set<struct uuid>uuid_set_;
+        std::vector<std::string>uuid_list_;
         std::vector<uint64_t> counters;
         int coverage_srv_fd;