Merge "fs_mgr: Don't run clean_scratch_files on non-dynamic devices" into main
diff --git a/fastboot/README.md b/fastboot/README.md
index 28e623c..6996d4a 100644
--- a/fastboot/README.md
+++ b/fastboot/README.md
@@ -25,7 +25,7 @@
 ## Transport and Framing
 
 1. Host sends a command, which is an ascii string in a single
-   packet no greater than 64 bytes.
+   packet no greater than 4096 bytes.
 
 2. Client response with a single packet no greater than 256 bytes.
    The first four bytes of the response are "OKAY", "FAIL", "DATA",
diff --git a/fs_mgr/libfiemap/metadata.cpp b/fs_mgr/libfiemap/metadata.cpp
index 22b8afb..0a56f6a 100644
--- a/fs_mgr/libfiemap/metadata.cpp
+++ b/fs_mgr/libfiemap/metadata.cpp
@@ -111,13 +111,7 @@
         return true;
     }
 
-    unique_fd fd(open(metadata_file.c_str(), O_CREAT | O_RDWR | O_TRUNC | O_CLOEXEC | O_BINARY | O_SYNC, 0644));
-    if (fd < 0) {
-        LOG(ERROR) << "open failed: " << metadata_file;
-        return false;
-    }
-
-    if (!WriteToImageFile(fd, *exported.get())) {
+    if (!WriteToImageFile(metadata_file, *exported.get())) {
         LOG(ERROR) << "Unable to save new metadata";
         return false;
     }
diff --git a/fs_mgr/liblp/images.cpp b/fs_mgr/liblp/images.cpp
index 02b64ac..a2dbb10 100644
--- a/fs_mgr/liblp/images.cpp
+++ b/fs_mgr/liblp/images.cpp
@@ -123,13 +123,46 @@
     return true;
 }
 
-bool WriteToImageFile(const std::string& file, const LpMetadata& input) {
-    unique_fd fd(open(file.c_str(), O_CREAT | O_RDWR | O_TRUNC | O_CLOEXEC | O_BINARY, 0644));
-    if (fd < 0) {
-        PERROR << __PRETTY_FUNCTION__ << " open failed: " << file;
+#if !defined(_WIN32)
+bool FsyncDirectory(const char* dirname) {
+    android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(dirname, O_RDONLY | O_CLOEXEC)));
+    if (fd == -1) {
+        PLOG(ERROR) << "Failed to open " << dirname;
         return false;
     }
-    return WriteToImageFile(fd, input);
+    if (fsync(fd) == -1) {
+        if (errno == EROFS || errno == EINVAL) {
+            PLOG(WARNING) << "Skip fsync " << dirname
+                          << " on a file system does not support synchronization";
+        } else {
+            PLOG(ERROR) << "Failed to fsync " << dirname;
+            return false;
+        }
+    }
+    return true;
+}
+#endif
+
+bool WriteToImageFile(const std::string& file, const LpMetadata& input) {
+    const auto parent_dir = base::Dirname(file);
+    TemporaryFile tmpfile(parent_dir);
+    if (!WriteToImageFile(tmpfile.fd, input)) {
+        PLOG(ERROR) << "Failed to write geometry data to tmpfile " << tmpfile.path;
+        return false;
+    }
+
+#if !defined(_WIN32)
+    fsync(tmpfile.fd);
+#endif
+    const auto err = rename(tmpfile.path, file.c_str());
+    if (err != 0) {
+        PLOG(ERROR) << "Failed to rename tmp geometry file " << tmpfile.path << " to " << file;
+        return false;
+    }
+#if !defined(_WIN32)
+    FsyncDirectory(parent_dir.c_str());
+#endif
+    return true;
 }
 
 ImageBuilder::ImageBuilder(const LpMetadata& metadata, uint32_t block_size,
@@ -208,7 +241,8 @@
         std::string file_name = "super_" + name + ".img";
         std::string file_path = output_dir + "/" + file_name;
 
-        static const int kOpenFlags = O_CREAT | O_RDWR | O_TRUNC | O_CLOEXEC | O_NOFOLLOW | O_BINARY;
+        static const int kOpenFlags =
+                O_CREAT | O_RDWR | O_TRUNC | O_CLOEXEC | O_NOFOLLOW | O_BINARY;
         unique_fd fd(open(file_path.c_str(), kOpenFlags, 0644));
         if (fd < 0) {
             PERROR << "open failed: " << file_path;
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h
index b271dad..c9777a3 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h
@@ -161,6 +161,9 @@
 
 // The on disk format of cow (currently ==  CowOperation)
 struct CowOperationV3 {
+    // The operation code (see the constants and structures below).
+    uint8_t type;
+
     // If this operation reads from the data section of the COW, this contains
     // the length.
     uint16_t data_length;
@@ -168,10 +171,6 @@
     // The block of data in the new image that this operation modifies.
     uint32_t new_block;
 
-    // source_info with have the following layout
-    // |---4 bits ---| ---12 bits---| --- 48 bits ---|
-    // |--- type --- | -- unused -- | --- source --- |
-    //
     // The value of |source| depends on the operation code.
     //
     // CopyOp: a 32-bit block location in the source image.
@@ -180,6 +179,8 @@
     // ZeroOp: unused
     // LabelOp: a 64-bit opaque identifier.
     //
+    // For ops other than Label:
+    //  Bits 47-62 are reserved and must be zero.
     // A block is compressed if it’s data is < block_sz
     uint64_t source_info;
 } __attribute__((packed));
@@ -211,21 +212,9 @@
 static constexpr uint8_t kCowReadAheadInProgress = 1;
 static constexpr uint8_t kCowReadAheadDone = 2;
 
-// this is a mask to grab the last 48 bits of a 64 bit integer
-static constexpr uint64_t kCowOpSourceInfoDataMask = (0x1ULL << 48) - 1;
-// this is a mask to grab the first 4 bits of a 64 bit integer
-static constexpr uint64_t kCowOpSourceInfoTypeBit = 60;
-static constexpr uint64_t kCowOpSourceInfoTypeNumBits = 4;
-static constexpr uint64_t kCowOpSourceInfoTypeMask = (1 << kCowOpSourceInfoTypeNumBits) - 1;
+static constexpr uint64_t kCowOpSourceInfoDataMask = (1ULL << 48) - 1;
 
-static constexpr void SetCowOpSourceInfoType(CowOperation* op, const uint8_t type) {
-    op->source_info |= uint64_t(type) << kCowOpSourceInfoTypeBit;
-}
-static constexpr uint64_t GetCowOpSourceInfoType(const CowOperation& op) {
-    return (op.source_info >> kCowOpSourceInfoTypeBit) & kCowOpSourceInfoTypeMask;
-}
-
-static constexpr uint64_t GetCowOpSourceInfoData(const CowOperation& op) {
+static inline uint64_t GetCowOpSourceInfoData(const CowOperation& op) {
     return op.source_info & kCowOpSourceInfoDataMask;
 }
 
diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/cow_format.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/cow_format.cpp
index 1be592d..5ab4f7a 100644
--- a/fs_mgr/libsnapshot/libsnapshot_cow/cow_format.cpp
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/cow_format.cpp
@@ -81,19 +81,16 @@
 
 std::ostream& operator<<(std::ostream& os, CowOperation const& op) {
     os << "CowOperation(";
-    EmitCowTypeString(os, GetCowOpSourceInfoType(op));
-    if (GetCowOpSourceInfoType(op) == kCowReplaceOp || GetCowOpSourceInfoType(op) == kCowXorOp ||
-        GetCowOpSourceInfoType(op) == kCowSequenceOp) {
+    EmitCowTypeString(os, op.type);
+    if (op.type == kCowReplaceOp || op.type == kCowXorOp || op.type == kCowSequenceOp) {
         os << ", data_length:" << op.data_length;
     }
-    if (GetCowOpSourceInfoType(op) != kCowClusterOp &&
-        GetCowOpSourceInfoType(op) != kCowSequenceOp && GetCowOpSourceInfoType(op) != kCowLabelOp) {
+    if (op.type != kCowClusterOp && op.type != kCowSequenceOp && op.type != kCowLabelOp) {
         os << ", new_block:" << op.new_block;
     }
-    if (GetCowOpSourceInfoType(op) == kCowXorOp || GetCowOpSourceInfoType(op) == kCowReplaceOp ||
-        GetCowOpSourceInfoType(op) == kCowCopyOp) {
+    if (op.type == kCowXorOp || op.type == kCowReplaceOp || op.type == kCowCopyOp) {
         os << ", source:" << (op.source_info & kCowOpSourceInfoDataMask);
-    } else if (GetCowOpSourceInfoType(op) == kCowClusterOp) {
+    } else if (op.type == kCowClusterOp) {
         os << ", cluster_data:" << (op.source_info & kCowOpSourceInfoDataMask);
     } else {
         os << ", label:0x" << android::base::StringPrintf("%" PRIx64, op.source_info);
@@ -123,7 +120,7 @@
 }
 
 bool IsMetadataOp(const CowOperation& op) {
-    switch (GetCowOpSourceInfoType(op)) {
+    switch (op.type) {
         case kCowLabelOp:
         case kCowClusterOp:
         case kCowFooterOp:
@@ -135,7 +132,7 @@
 }
 
 bool IsOrderedOp(const CowOperation& op) {
-    switch (GetCowOpSourceInfoType(op)) {
+    switch (op.type) {
         case kCowCopyOp:
         case kCowXorOp:
             return true;
diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/cow_reader.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/cow_reader.cpp
index 996037e..607d610 100644
--- a/fs_mgr/libsnapshot/libsnapshot_cow/cow_reader.cpp
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/cow_reader.cpp
@@ -24,7 +24,6 @@
 
 #include <android-base/file.h>
 #include <android-base/logging.h>
-#include <libsnapshot/cow_format.h>
 #include <libsnapshot/cow_reader.h>
 #include <zlib.h>
 
@@ -140,7 +139,7 @@
         const auto& v2_op = parser.ops()->at(i);
 
         auto& new_op = ops_->at(i);
-        SetCowOpSourceInfoType(&new_op, v2_op.type);
+        new_op.type = v2_op.type;
         new_op.data_length = v2_op.data_length;
 
         if (v2_op.new_block > std::numeric_limits<uint32_t>::max()) {
@@ -150,7 +149,7 @@
         new_op.new_block = v2_op.new_block;
 
         uint64_t source_info = v2_op.source;
-        if (GetCowOpSourceInfoType(new_op) != kCowLabelOp) {
+        if (new_op.type != kCowLabelOp) {
             source_info &= kCowOpSourceInfoDataMask;
             if (source_info != v2_op.source) {
                 LOG(ERROR) << "Out-of-range source value in COW op: " << v2_op;
@@ -167,7 +166,7 @@
                 return false;
             }
         }
-        new_op.source_info |= source_info;
+        new_op.source_info = source_info;
     }
 
     // If we're resuming a write, we're not ready to merge
@@ -290,7 +289,7 @@
     for (size_t i = 0; i < ops_->size(); i++) {
         auto& current_op = ops_->data()[i];
 
-        if (GetCowOpSourceInfoType(current_op) == kCowSequenceOp) {
+        if (current_op.type == kCowSequenceOp) {
             size_t seq_len = current_op.data_length / sizeof(uint32_t);
 
             merge_op_blocks->resize(merge_op_blocks->size() + seq_len);
@@ -602,7 +601,7 @@
 }
 
 bool CowReader::GetRawBytes(const CowOperation* op, void* buffer, size_t len, size_t* read) {
-    switch (GetCowOpSourceInfoType(*op)) {
+    switch (op->type) {
         case kCowSequenceOp:
         case kCowReplaceOp:
         case kCowXorOp:
@@ -695,7 +694,7 @@
     }
 
     uint64_t offset;
-    if (GetCowOpSourceInfoType(*op) == kCowXorOp) {
+    if (op->type == kCowXorOp) {
         offset = data_loc_->at(op->new_block);
     } else {
         offset = GetCowOpSourceInfoData(*op);
@@ -712,7 +711,7 @@
 }
 
 bool CowReader::GetSourceOffset(const CowOperation* op, uint64_t* source_offset) {
-    switch (GetCowOpSourceInfoType(*op)) {
+    switch (op->type) {
         case kCowCopyOp:
             *source_offset = GetCowOpSourceInfoData(*op) * header_.block_size;
             return true;
diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/inspect_cow.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/inspect_cow.cpp
index aaaf20c..83b5a12 100644
--- a/fs_mgr/libsnapshot/libsnapshot_cow/inspect_cow.cpp
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/inspect_cow.cpp
@@ -26,7 +26,6 @@
 #include <android-base/logging.h>
 #include <android-base/unique_fd.h>
 #include <gflags/gflags.h>
-#include <libsnapshot/cow_format.h>
 #include <libsnapshot/cow_reader.h>
 #include "parser_v2.h"
 
@@ -199,7 +198,7 @@
 
         if (!FLAGS_silent && FLAGS_show_ops) std::cout << *op << "\n";
 
-        if ((FLAGS_decompress || extract_to >= 0) && GetCowOpSourceInfoType(*op) == kCowReplaceOp) {
+        if ((FLAGS_decompress || extract_to >= 0) && op->type == kCowReplaceOp) {
             if (reader.ReadData(op, buffer.data(), buffer.size()) < 0) {
                 std::cerr << "Failed to decompress for :" << *op << "\n";
                 success = false;
@@ -213,13 +212,12 @@
                     return false;
                 }
             }
-        } else if (extract_to >= 0 && !IsMetadataOp(*op) &&
-                   GetCowOpSourceInfoType(*op) != kCowZeroOp) {
+        } else if (extract_to >= 0 && !IsMetadataOp(*op) && op->type != kCowZeroOp) {
             PLOG(ERROR) << "Cannot extract op yet: " << *op;
             return false;
         }
 
-        if (GetCowOpSourceInfoType(*op) == kCowSequenceOp && FLAGS_show_merge_sequence) {
+        if (op->type == kCowSequenceOp && FLAGS_show_merge_sequence) {
             size_t read;
             std::vector<uint32_t> merge_op_blocks;
             size_t seq_len = op->data_length / sizeof(uint32_t);
@@ -237,13 +235,13 @@
             }
         }
 
-        if (GetCowOpSourceInfoType(*op) == kCowCopyOp) {
+        if (op->type == kCowCopyOp) {
             copy_ops++;
-        } else if (GetCowOpSourceInfoType(*op) == kCowReplaceOp) {
+        } else if (op->type == kCowReplaceOp) {
             replace_ops++;
-        } else if (GetCowOpSourceInfoType(*op) == kCowZeroOp) {
+        } else if (op->type == kCowZeroOp) {
             zero_ops++;
-        } else if (GetCowOpSourceInfoType(*op) == kCowXorOp) {
+        } else if (op->type == kCowXorOp) {
             xor_ops++;
         }
 
diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/snapshot_reader.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/snapshot_reader.cpp
index d7ee432..a3e40d9 100644
--- a/fs_mgr/libsnapshot/libsnapshot_cow/snapshot_reader.cpp
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/snapshot_reader.cpp
@@ -147,7 +147,7 @@
         op = ops_[chunk];
     }
 
-    if (!op || GetCowOpSourceInfoType(*op) == kCowCopyOp) {
+    if (!op || op->type == kCowCopyOp) {
         borrowed_fd fd = GetSourceFd();
         if (fd < 0) {
             // GetSourceFd sets errno.
@@ -169,15 +169,15 @@
             // ReadFullyAtOffset sets errno.
             return -1;
         }
-    } else if (GetCowOpSourceInfoType(*op) == kCowZeroOp) {
+    } else if (op->type == kCowZeroOp) {
         memset(buffer, 0, bytes_to_read);
-    } else if (GetCowOpSourceInfoType(*op) == kCowReplaceOp) {
+    } else if (op->type == kCowReplaceOp) {
         if (cow_->ReadData(op, buffer, bytes_to_read, start_offset) < bytes_to_read) {
             LOG(ERROR) << "CompressedSnapshotReader failed to read replace op";
             errno = EIO;
             return -1;
         }
-    } else if (GetCowOpSourceInfoType(*op) == kCowXorOp) {
+    } else if (op->type == kCowXorOp) {
         borrowed_fd fd = GetSourceFd();
         if (fd < 0) {
             // GetSourceFd sets errno.
@@ -208,8 +208,7 @@
             ((char*)buffer)[i] ^= data[i];
         }
     } else {
-        LOG(ERROR) << "CompressedSnapshotReader unknown op type: "
-                   << uint32_t(GetCowOpSourceInfoType(*op));
+        LOG(ERROR) << "CompressedSnapshotReader unknown op type: " << uint32_t(op->type);
         errno = EINVAL;
         return -1;
     }
diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/test_v2.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/test_v2.cpp
index d962875..35d74ba 100644
--- a/fs_mgr/libsnapshot/libsnapshot_cow/test_v2.cpp
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/test_v2.cpp
@@ -25,7 +25,6 @@
 #include <libsnapshot/cow_reader.h>
 #include <libsnapshot/cow_writer.h>
 #include "cow_decompress.h"
-#include "libsnapshot/cow_format.h"
 #include "writer_v2.h"
 
 using android::base::unique_fd;
@@ -86,7 +85,7 @@
     size_t i = 0;
     while (!iter->AtEnd()) {
         auto op = iter->Get();
-        ASSERT_EQ(GetCowOpSourceInfoType(*op), kCowCopyOp);
+        ASSERT_EQ(op->type, kCowCopyOp);
         ASSERT_EQ(op->data_length, 0);
         ASSERT_EQ(op->new_block, 10 + i);
         ASSERT_EQ(GetCowOpSourceInfoData(*op), 1000 + i);
@@ -132,7 +131,7 @@
     ASSERT_FALSE(iter->AtEnd());
     auto op = iter->Get();
 
-    ASSERT_EQ(GetCowOpSourceInfoType(*op), kCowCopyOp);
+    ASSERT_EQ(op->type, kCowCopyOp);
     ASSERT_EQ(op->data_length, 0);
     ASSERT_EQ(op->new_block, 10);
     ASSERT_EQ(GetCowOpSourceInfoData(*op), 20);
@@ -143,7 +142,7 @@
     ASSERT_FALSE(iter->AtEnd());
     op = iter->Get();
 
-    ASSERT_EQ(GetCowOpSourceInfoType(*op), kCowReplaceOp);
+    ASSERT_EQ(op->type, kCowReplaceOp);
     ASSERT_EQ(op->data_length, 4096);
     ASSERT_EQ(op->new_block, 50);
     ASSERT_TRUE(ReadData(reader, op, sink.data(), sink.size()));
@@ -154,7 +153,7 @@
     op = iter->Get();
 
     // Note: the zero operation gets split into two blocks.
-    ASSERT_EQ(GetCowOpSourceInfoType(*op), kCowZeroOp);
+    ASSERT_EQ(op->type, kCowZeroOp);
     ASSERT_EQ(op->data_length, 0);
     ASSERT_EQ(op->new_block, 51);
     ASSERT_EQ(GetCowOpSourceInfoData(*op), 0);
@@ -163,7 +162,7 @@
     ASSERT_FALSE(iter->AtEnd());
     op = iter->Get();
 
-    ASSERT_EQ(GetCowOpSourceInfoType(*op), kCowZeroOp);
+    ASSERT_EQ(op->type, kCowZeroOp);
     ASSERT_EQ(op->data_length, 0);
     ASSERT_EQ(op->new_block, 52);
     ASSERT_EQ(GetCowOpSourceInfoData(*op), 0);
@@ -207,7 +206,7 @@
     ASSERT_FALSE(iter->AtEnd());
     auto op = iter->Get();
 
-    ASSERT_EQ(GetCowOpSourceInfoType(*op), kCowCopyOp);
+    ASSERT_EQ(op->type, kCowCopyOp);
     ASSERT_EQ(op->data_length, 0);
     ASSERT_EQ(op->new_block, 10);
     ASSERT_EQ(GetCowOpSourceInfoData(*op), 20);
@@ -218,7 +217,7 @@
     ASSERT_FALSE(iter->AtEnd());
     op = iter->Get();
 
-    ASSERT_EQ(GetCowOpSourceInfoType(*op), kCowXorOp);
+    ASSERT_EQ(op->type, kCowXorOp);
     ASSERT_EQ(op->data_length, 4096);
     ASSERT_EQ(op->new_block, 50);
     ASSERT_EQ(GetCowOpSourceInfoData(*op), 98314);  // 4096 * 24 + 10
@@ -230,7 +229,7 @@
     op = iter->Get();
 
     // Note: the zero operation gets split into two blocks.
-    ASSERT_EQ(GetCowOpSourceInfoType(*op), kCowZeroOp);
+    ASSERT_EQ(op->type, kCowZeroOp);
     ASSERT_EQ(op->data_length, 0);
     ASSERT_EQ(op->new_block, 51);
     ASSERT_EQ(GetCowOpSourceInfoData(*op), 0);
@@ -239,7 +238,7 @@
     ASSERT_FALSE(iter->AtEnd());
     op = iter->Get();
 
-    ASSERT_EQ(GetCowOpSourceInfoType(*op), kCowZeroOp);
+    ASSERT_EQ(op->type, kCowZeroOp);
     ASSERT_EQ(op->data_length, 0);
     ASSERT_EQ(op->new_block, 52);
     ASSERT_EQ(GetCowOpSourceInfoData(*op), 0);
@@ -274,7 +273,7 @@
 
     std::string sink(data.size(), '\0');
 
-    ASSERT_EQ(GetCowOpSourceInfoType(*op), kCowReplaceOp);
+    ASSERT_EQ(op->type, kCowReplaceOp);
     ASSERT_EQ(op->data_length, 56);  // compressed!
     ASSERT_EQ(op->new_block, 50);
     ASSERT_TRUE(ReadData(reader, op, sink.data(), sink.size()));
@@ -326,7 +325,7 @@
     while (!iter->AtEnd()) {
         auto op = iter->Get();
 
-        if (GetCowOpSourceInfoType(*op) == kCowXorOp) {
+        if (op->type == kCowXorOp) {
             total_blocks += 1;
             std::string sink(xor_data.size(), '\0');
             ASSERT_EQ(op->new_block, 50);
@@ -335,7 +334,7 @@
             ASSERT_EQ(sink, xor_data);
         }
 
-        if (GetCowOpSourceInfoType(*op) == kCowReplaceOp) {
+        if (op->type == kCowReplaceOp) {
             total_blocks += 1;
             if (op->new_block == 100) {
                 data.resize(options.block_size);
@@ -400,7 +399,7 @@
     while (!iter->AtEnd()) {
         auto op = iter->Get();
 
-        if (GetCowOpSourceInfoType(*op) == kCowReplaceOp) {
+        if (op->type == kCowReplaceOp) {
             total_blocks += 1;
             if (op->new_block == 50) {
                 data.resize(options.block_size);
@@ -520,7 +519,7 @@
 
     std::string sink(data.size(), '\0');
 
-    ASSERT_EQ(GetCowOpSourceInfoType(*op), kCowReplaceOp);
+    ASSERT_EQ(op->type, kCowReplaceOp);
     ASSERT_EQ(op->data_length, 56);  // compressed!
     ASSERT_EQ(op->new_block, 50);
     ASSERT_TRUE(ReadData(reader, op, sink.data(), sink.size()));
@@ -530,7 +529,7 @@
     ASSERT_FALSE(iter->AtEnd());
     op = iter->Get();
 
-    ASSERT_EQ(GetCowOpSourceInfoType(*op), kCowClusterOp);
+    ASSERT_EQ(op->type, kCowClusterOp);
 
     iter->Next();
     ASSERT_FALSE(iter->AtEnd());
@@ -547,7 +546,7 @@
     ASSERT_FALSE(iter->AtEnd());
     op = iter->Get();
 
-    ASSERT_EQ(GetCowOpSourceInfoType(*op), kCowClusterOp);
+    ASSERT_EQ(op->type, kCowClusterOp);
 
     iter->Next();
     ASSERT_TRUE(iter->AtEnd());
@@ -581,7 +580,7 @@
     std::string sink(options.block_size, '\0');
 
     auto op = iter->Get();
-    ASSERT_EQ(GetCowOpSourceInfoType(*op), kCowReplaceOp);
+    ASSERT_EQ(op->type, kCowReplaceOp);
     ASSERT_EQ(op->new_block, 51);
     ASSERT_TRUE(ReadData(reader, op, sink.data(), sink.size()));
 }
@@ -654,7 +653,7 @@
 
     ASSERT_FALSE(iter->AtEnd());
     auto op = iter->Get();
-    ASSERT_EQ(GetCowOpSourceInfoType(*op), kCowReplaceOp);
+    ASSERT_EQ(op->type, kCowReplaceOp);
     ASSERT_TRUE(ReadData(reader, op, sink.data(), sink.size()));
     ASSERT_EQ(sink, data);
 
@@ -664,14 +663,14 @@
 
     ASSERT_FALSE(iter->AtEnd());
     op = iter->Get();
-    ASSERT_EQ(GetCowOpSourceInfoType(*op), kCowLabelOp);
+    ASSERT_EQ(op->type, kCowLabelOp);
     ASSERT_EQ(GetCowOpSourceInfoData(*op), 3);
 
     iter->Next();
 
     ASSERT_FALSE(iter->AtEnd());
     op = iter->Get();
-    ASSERT_EQ(GetCowOpSourceInfoType(*op), kCowReplaceOp);
+    ASSERT_EQ(op->type, kCowReplaceOp);
     ASSERT_TRUE(ReadData(reader, op, sink.data(), sink.size()));
     ASSERT_EQ(sink, data2);
 
@@ -717,14 +716,14 @@
 
     ASSERT_FALSE(iter->AtEnd());
     auto op = iter->Get();
-    ASSERT_EQ(GetCowOpSourceInfoType(*op), kCowLabelOp);
+    ASSERT_EQ(op->type, kCowLabelOp);
     ASSERT_EQ(GetCowOpSourceInfoData(*op), 0);
 
     iter->Next();
 
     ASSERT_FALSE(iter->AtEnd());
     op = iter->Get();
-    ASSERT_EQ(GetCowOpSourceInfoType(*op), kCowZeroOp);
+    ASSERT_EQ(op->type, kCowZeroOp);
 
     iter->Next();
 
@@ -775,7 +774,7 @@
 
     ASSERT_FALSE(iter->AtEnd());
     auto op = iter->Get();
-    ASSERT_EQ(GetCowOpSourceInfoType(*op), kCowLabelOp);
+    ASSERT_EQ(op->type, kCowLabelOp);
     ASSERT_EQ(GetCowOpSourceInfoData(*op), 5);
 
     iter->Next();
@@ -826,7 +825,7 @@
 
     ASSERT_FALSE(iter->AtEnd());
     auto op = iter->Get();
-    ASSERT_EQ(GetCowOpSourceInfoType(*op), kCowReplaceOp);
+    ASSERT_EQ(op->type, kCowReplaceOp);
     ASSERT_TRUE(ReadData(reader, op, sink.data(), sink.size()));
     ASSERT_EQ(sink, data.substr(0, options.block_size));
 
@@ -836,7 +835,7 @@
 
     ASSERT_FALSE(iter->AtEnd());
     op = iter->Get();
-    ASSERT_EQ(GetCowOpSourceInfoType(*op), kCowReplaceOp);
+    ASSERT_EQ(op->type, kCowReplaceOp);
     ASSERT_TRUE(ReadData(reader, op, sink.data(), sink.size()));
     ASSERT_EQ(sink, data.substr(options.block_size, 2 * options.block_size));
 
@@ -844,25 +843,25 @@
 
     ASSERT_FALSE(iter->AtEnd());
     op = iter->Get();
-    ASSERT_EQ(GetCowOpSourceInfoType(*op), kCowLabelOp);
+    ASSERT_EQ(op->type, kCowLabelOp);
     ASSERT_EQ(GetCowOpSourceInfoData(*op), 4);
 
     iter->Next();
 
     ASSERT_FALSE(iter->AtEnd());
     op = iter->Get();
-    ASSERT_EQ(GetCowOpSourceInfoType(*op), kCowZeroOp);
+    ASSERT_EQ(op->type, kCowZeroOp);
 
     iter->Next();
 
     ASSERT_FALSE(iter->AtEnd());
     op = iter->Get();
-    ASSERT_EQ(GetCowOpSourceInfoType(*op), kCowZeroOp);
+    ASSERT_EQ(op->type, kCowZeroOp);
 
     iter->Next();
     ASSERT_FALSE(iter->AtEnd());
     op = iter->Get();
-    ASSERT_EQ(GetCowOpSourceInfoType(*op), kCowLabelOp);
+    ASSERT_EQ(op->type, kCowLabelOp);
     ASSERT_EQ(GetCowOpSourceInfoData(*op), 5);
 
     iter->Next();
@@ -907,7 +906,7 @@
 
     ASSERT_FALSE(iter->AtEnd());
     auto op = iter->Get();
-    ASSERT_EQ(GetCowOpSourceInfoType(*op), kCowReplaceOp);
+    ASSERT_EQ(op->type, kCowReplaceOp);
     ASSERT_TRUE(ReadData(reader, op, sink.data(), sink.size()));
     ASSERT_EQ(sink, data.substr(0, options.block_size));
 
@@ -915,51 +914,51 @@
 
     ASSERT_FALSE(iter->AtEnd());
     op = iter->Get();
-    ASSERT_EQ(GetCowOpSourceInfoType(*op), kCowLabelOp);
+    ASSERT_EQ(op->type, kCowLabelOp);
     ASSERT_EQ(GetCowOpSourceInfoData(*op), 4);
 
     iter->Next();
 
     ASSERT_FALSE(iter->AtEnd());
     op = iter->Get();
-    ASSERT_EQ(GetCowOpSourceInfoType(*op), kCowZeroOp);
+    ASSERT_EQ(op->type, kCowZeroOp);
 
     iter->Next();
 
     ASSERT_FALSE(iter->AtEnd());
     op = iter->Get();
-    ASSERT_EQ(GetCowOpSourceInfoType(*op), kCowClusterOp);
+    ASSERT_EQ(op->type, kCowClusterOp);
 
     iter->Next();
 
     ASSERT_FALSE(iter->AtEnd());
     op = iter->Get();
-    ASSERT_EQ(GetCowOpSourceInfoType(*op), kCowZeroOp);
+    ASSERT_EQ(op->type, kCowZeroOp);
 
     iter->Next();
 
     ASSERT_FALSE(iter->AtEnd());
     op = iter->Get();
-    ASSERT_EQ(GetCowOpSourceInfoType(*op), kCowLabelOp);
+    ASSERT_EQ(op->type, kCowLabelOp);
     ASSERT_EQ(GetCowOpSourceInfoData(*op), 5);
 
     iter->Next();
 
     ASSERT_FALSE(iter->AtEnd());
     op = iter->Get();
-    ASSERT_EQ(GetCowOpSourceInfoType(*op), kCowCopyOp);
+    ASSERT_EQ(op->type, kCowCopyOp);
 
     iter->Next();
 
     ASSERT_FALSE(iter->AtEnd());
     op = iter->Get();
-    ASSERT_EQ(GetCowOpSourceInfoType(*op), kCowClusterOp);
+    ASSERT_EQ(op->type, kCowClusterOp);
 
     iter->Next();
 
     ASSERT_FALSE(iter->AtEnd());
     op = iter->Get();
-    ASSERT_EQ(GetCowOpSourceInfoType(*op), kCowLabelOp);
+    ASSERT_EQ(op->type, kCowLabelOp);
     ASSERT_EQ(GetCowOpSourceInfoData(*op), 6);
 
     iter->Next();
@@ -1006,14 +1005,14 @@
 
     ASSERT_FALSE(iter->AtEnd());
     auto op = iter->Get();
-    ASSERT_EQ(GetCowOpSourceInfoType(*op), kCowLabelOp);
+    ASSERT_EQ(op->type, kCowLabelOp);
     ASSERT_EQ(GetCowOpSourceInfoData(*op), 50);
 
     iter->Next();
 
     ASSERT_FALSE(iter->AtEnd());
     op = iter->Get();
-    ASSERT_EQ(GetCowOpSourceInfoType(*op), kCowReplaceOp);
+    ASSERT_EQ(op->type, kCowReplaceOp);
     ASSERT_TRUE(ReadData(reader, op, sink.data(), sink.size()));
     ASSERT_EQ(sink, data2);
 
@@ -1021,7 +1020,7 @@
 
     ASSERT_FALSE(iter->AtEnd());
     op = iter->Get();
-    ASSERT_EQ(GetCowOpSourceInfoType(*op), kCowClusterOp);
+    ASSERT_EQ(op->type, kCowClusterOp);
 
     iter->Next();
 
@@ -1118,12 +1117,12 @@
         num_in_cluster++;
         max_in_cluster = std::max(max_in_cluster, num_in_cluster);
 
-        if (GetCowOpSourceInfoType(*op) == kCowReplaceOp) {
+        if (op->type == kCowReplaceOp) {
             num_replace++;
 
             ASSERT_EQ(op->new_block, num_replace);
             ASSERT_TRUE(CompareDataBlock(&reader, op, "Block " + std::to_string(num_replace)));
-        } else if (GetCowOpSourceInfoType(*op) == kCowClusterOp) {
+        } else if (op->type == kCowClusterOp) {
             num_in_cluster = 0;
             num_clusters++;
         }
@@ -1179,12 +1178,12 @@
         num_in_cluster++;
         max_in_cluster = std::max(max_in_cluster, num_in_cluster);
 
-        if (GetCowOpSourceInfoType(*op) == kCowReplaceOp) {
+        if (op->type == kCowReplaceOp) {
             num_replace++;
 
             ASSERT_EQ(op->new_block, num_replace);
             ASSERT_TRUE(CompareDataBlock(&reader, op, "Block " + std::to_string(num_replace)));
-        } else if (GetCowOpSourceInfoType(*op) == kCowClusterOp) {
+        } else if (op->type == kCowClusterOp) {
             num_in_cluster = 0;
             num_clusters++;
         }
@@ -1230,12 +1229,12 @@
 
         num_in_cluster++;
         max_in_cluster = std::max(max_in_cluster, num_in_cluster);
-        if (GetCowOpSourceInfoType(*op) == kCowReplaceOp) {
+        if (op->type == kCowReplaceOp) {
             num_replace++;
 
             ASSERT_EQ(op->new_block, num_replace);
             ASSERT_TRUE(CompareDataBlock(&reader, op, "Block " + std::to_string(num_replace)));
-        } else if (GetCowOpSourceInfoType(*op) == kCowClusterOp) {
+        } else if (op->type == kCowClusterOp) {
             num_in_cluster = 0;
             num_clusters++;
         }
diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/test_v3.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/test_v3.cpp
index a4d617f..2373d4d 100644
--- a/fs_mgr/libsnapshot/libsnapshot_cow/test_v3.cpp
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/test_v3.cpp
@@ -49,14 +49,5 @@
     std::unique_ptr<TemporaryFile> cow_;
 };
 
-TEST_F(CowOperationV3Test, CowTypeTest) {
-    CowOperationV3 new_op;
-    CowOperationV2 old_op;
-    old_op.type = kCowReplaceOp;
-    ASSERT_NE(GetCowOpSourceInfoType(new_op), old_op.type);
-    SetCowOpSourceInfoType(&new_op, old_op.type);
-    ASSERT_EQ(GetCowOpSourceInfoType(new_op), old_op.type);
-}
-
 }  // namespace snapshot
 }  // namespace android
\ No newline at end of file
diff --git a/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd.cpp b/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd.cpp
index 0be6ff5..6dc082e 100644
--- a/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd.cpp
@@ -25,7 +25,6 @@
 #include <csignal>
 #include <optional>
 #include <set>
-#include "libsnapshot/cow_format.h"
 
 #include <android-base/file.h>
 #include <android-base/logging.h>
@@ -407,9 +406,9 @@
             break;
         }
 
-        if (GetCowOpSourceInfoType(*cow_op) == kCowReplaceOp) {
+        if (cow_op->type == kCowReplaceOp) {
             replace_ops++;
-        } else if (GetCowOpSourceInfoType(*cow_op) == kCowZeroOp) {
+        } else if (cow_op->type == kCowZeroOp) {
             zero_ops++;
         }
 
@@ -541,7 +540,7 @@
             chunk_vec_.push_back(std::make_pair(ChunkToSector(data_chunk_id), cow_op));
             offset += sizeof(struct disk_exception);
             num_ops += 1;
-            if (GetCowOpSourceInfoType(*cow_op) == kCowCopyOp) {
+            if (cow_op->type == kCowCopyOp) {
                 copy_ops++;
             }
 
diff --git a/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd_readahead.cpp b/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd_readahead.cpp
index b2a4f2c..ab0b309 100644
--- a/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd_readahead.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd_readahead.cpp
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-#include "libsnapshot/cow_format.h"
 #include "snapuserd.h"
 
 #include <csignal>
@@ -193,7 +192,7 @@
         const CowOperation* cow_op = GetRAOpIter();
         CHECK_NE(cow_op, nullptr);
         *source_offset = GetCowOpSourceInfoData(*cow_op);
-        if (GetCowOpSourceInfoData(*cow_op) == kCowCopyOp) {
+        if (cow_op->type == kCowCopyOp) {
             *source_offset *= BLOCK_SZ;
         }
         RAIterNext();
@@ -212,7 +211,7 @@
             const CowOperation* op = GetRAOpIter();
             CHECK_NE(op, nullptr);
             uint64_t next_offset = GetCowOpSourceInfoData(*op);
-            if (GetCowOpSourceInfoData(*op) == kCowCopyOp) {
+            if (op->type == kCowCopyOp) {
                 next_offset *= BLOCK_SZ;
             }
             if (next_offset + nr_consecutive * BLOCK_SZ != *source_offset) {
diff --git a/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd_worker.cpp b/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd_worker.cpp
index 0930a5d..571b352 100644
--- a/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd_worker.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd_worker.cpp
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-#include "libsnapshot/cow_format.h"
 #include "snapuserd.h"
 
 #include <csignal>
@@ -178,7 +177,7 @@
         return false;
     }
 
-    switch (GetCowOpSourceInfoType(*cow_op)) {
+    switch (cow_op->type) {
         case kCowReplaceOp: {
             return ProcessReplaceOp(cow_op);
         }
@@ -192,8 +191,7 @@
         }
 
         default: {
-            SNAP_LOG(ERROR) << "Unsupported operation-type found: "
-                            << GetCowOpSourceInfoType(*cow_op);
+            SNAP_LOG(ERROR) << "Unsupported operation-type found: " << cow_op->type;
         }
     }
     return false;
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/merge_worker.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/merge_worker.cpp
index d06ba58..11b8d7c 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/merge_worker.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/merge_worker.cpp
@@ -17,7 +17,6 @@
 
 #include <pthread.h>
 
-#include "libsnapshot/cow_format.h"
 #include "snapuserd_core.h"
 #include "utility.h"
 
@@ -115,13 +114,13 @@
                 SNAP_LOG(ERROR) << "AcquireBuffer failed in MergeReplaceOps";
                 return false;
             }
-            if (GetCowOpSourceInfoType(*cow_op) == kCowReplaceOp) {
+            if (cow_op->type == kCowReplaceOp) {
                 if (!reader_->ReadData(cow_op, buffer, BLOCK_SZ)) {
                     SNAP_LOG(ERROR) << "Failed to read COW in merge";
                     return false;
                 }
             } else {
-                CHECK(GetCowOpSourceInfoType(*cow_op) == kCowZeroOp);
+                CHECK(cow_op->type == kCowZeroOp);
                 memset(buffer, 0, BLOCK_SZ);
             }
         }
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.cpp
index ffa23ea..5cb13e8 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.cpp
@@ -18,7 +18,6 @@
 
 #include <pthread.h>
 
-#include "libsnapshot/cow_format.h"
 #include "snapuserd_core.h"
 #include "utility.h"
 
@@ -64,7 +63,7 @@
                     << " Op: " << *cow_op;
     if (!android::base::ReadFullyAtOffset(backing_store_fd_, buffer, BLOCK_SZ, offset)) {
         std::string op;
-        if (GetCowOpSourceInfoType(*cow_op) == kCowCopyOp)
+        if (cow_op->type == kCowCopyOp)
             op = "Copy-op";
         else {
             op = "Xor-op";
@@ -134,7 +133,7 @@
         }
         case MERGE_GROUP_STATE::GROUP_MERGE_PENDING: {
             bool ret;
-            if (GetCowOpSourceInfoType(*cow_op) == kCowCopyOp) {
+            if (cow_op->type == kCowCopyOp) {
                 ret = ProcessCopyOp(cow_op, buffer);
             } else {
                 ret = ProcessXorOp(cow_op, buffer);
@@ -168,7 +167,7 @@
         return false;
     }
 
-    switch (GetCowOpSourceInfoType(*cow_op)) {
+    switch (cow_op->type) {
         case kCowReplaceOp: {
             return ProcessReplaceOp(cow_op, buffer);
         }
@@ -184,7 +183,7 @@
         }
 
         default: {
-            SNAP_LOG(ERROR) << "Unknown operation-type found: " << GetCowOpSourceInfoType(*cow_op);
+            SNAP_LOG(ERROR) << "Unknown operation-type found: " << cow_op->type;
         }
     }
     return false;
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp
index 536ff2f..e886ec3 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp
@@ -24,7 +24,6 @@
 #include <android-base/strings.h>
 #include <snapuserd/dm_user_block_server.h>
 
-#include "libsnapshot/cow_format.h"
 #include "merge_worker.h"
 #include "read_worker.h"
 
@@ -197,13 +196,13 @@
     while (!cowop_iter->AtEnd()) {
         const CowOperation* cow_op = cowop_iter->Get();
 
-        if (GetCowOpSourceInfoType(*cow_op) == kCowCopyOp) {
+        if (cow_op->type == kCowCopyOp) {
             copy_ops += 1;
-        } else if (GetCowOpSourceInfoType(*cow_op) == kCowReplaceOp) {
+        } else if (cow_op->type == kCowReplaceOp) {
             replace_ops += 1;
-        } else if (GetCowOpSourceInfoType(*cow_op) == kCowZeroOp) {
+        } else if (cow_op->type == kCowZeroOp) {
             zero_ops += 1;
-        } else if (GetCowOpSourceInfoType(*cow_op) == kCowXorOp) {
+        } else if (cow_op->type == kCowXorOp) {
             xor_ops += 1;
         }
 
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h
index f88406d..6a1dab8 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h
@@ -43,7 +43,6 @@
 #include <libdm/dm.h>
 #include <libsnapshot/cow_reader.h>
 #include <libsnapshot/cow_writer.h>
-#include <liburing.h>
 #include <snapuserd/block_server.h>
 #include <snapuserd/snapuserd_buffer.h>
 #include <snapuserd/snapuserd_kernel.h>
@@ -247,7 +246,6 @@
     bool perform_verification_ = true;
     bool resume_merge_ = false;
 
-    std::unique_ptr<struct io_uring> ring_;
     std::unique_ptr<UpdateVerify> update_verify_;
     std::shared_ptr<IBlockServerOpener> block_server_opener_;
 };
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp
index d7d43a6..998d233 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp
@@ -18,7 +18,6 @@
 
 #include <pthread.h>
 
-#include "libsnapshot/cow_format.h"
 #include "snapuserd_core.h"
 #include "utility.h"
 
@@ -78,7 +77,7 @@
         SNAP_LOG(ERROR) << "PrepareNextReadAhead operation has no source offset: " << *cow_op;
         return nr_consecutive;
     }
-    if (GetCowOpSourceInfoType(*cow_op) == kCowXorOp) {
+    if (cow_op->type == kCowXorOp) {
         xor_op_vec.push_back(cow_op);
     }
 
@@ -107,7 +106,7 @@
             break;
         }
 
-        if (GetCowOpSourceInfoType(*op) == kCowXorOp) {
+        if (op->type == kCowXorOp) {
             xor_op_vec.push_back(op);
         }
 
diff --git a/init/Android.bp b/init/Android.bp
index 4c25ad7..e5512e6 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -389,10 +389,6 @@
     ],
 
     static_executable: true,
-    lto: {
-        // b/169004486 ThinLTO breaks x86 static executables.
-        never: true,
-    },
     system_shared_libs: [],
 
     cflags: [
diff --git a/init/persistent_properties.cpp b/init/persistent_properties.cpp
index 8db7267..8efb72c 100644
--- a/init/persistent_properties.cpp
+++ b/init/persistent_properties.cpp
@@ -46,13 +46,6 @@
 
 constexpr const char kLegacyPersistentPropertyDir[] = "/data/property";
 
-void AddPersistentProperty(const std::string& name, const std::string& value,
-                           PersistentProperties* persistent_properties) {
-    auto persistent_property_record = persistent_properties->add_properties();
-    persistent_property_record->set_name(name);
-    persistent_property_record->set_value(value);
-}
-
 Result<PersistentProperties> LoadLegacyPersistentProperties() {
     std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(kLegacyPersistentPropertyDir), closedir);
     if (!dir) {
@@ -161,9 +154,9 @@
         return Error() << "Unable to parse persistent property file: Could not parse protobuf";
     }
     for (auto& prop : persistent_properties.properties()) {
-        if (!StartsWith(prop.name(), "persist.")) {
+        if (!StartsWith(prop.name(), "persist.") && !StartsWith(prop.name(), "next_boot.")) {
             return Error() << "Unable to load persistent property file: property '" << prop.name()
-                           << "' doesn't start with 'persist.'";
+                           << "' doesn't start with 'persist.' or 'next_boot.'";
         }
     }
     return persistent_properties;
@@ -171,6 +164,13 @@
 
 }  // namespace
 
+void AddPersistentProperty(const std::string& name, const std::string& value,
+                           PersistentProperties* persistent_properties) {
+    auto persistent_property_record = persistent_properties->add_properties();
+    persistent_property_record->set_name(name);
+    persistent_property_record->set_value(value);
+}
+
 Result<PersistentProperties> LoadPersistentPropertyFile() {
     auto file_contents = ReadPersistentPropertyFile();
     if (!file_contents.ok()) return file_contents.error();
diff --git a/init/persistent_properties.h b/init/persistent_properties.h
index 3845a0d..a6f80e6 100644
--- a/init/persistent_properties.h
+++ b/init/persistent_properties.h
@@ -25,6 +25,8 @@
 namespace android {
 namespace init {
 
+void AddPersistentProperty(const std::string& name, const std::string& value,
+                           PersistentProperties* persistent_properties);
 PersistentProperties LoadPersistentProperties();
 void WritePersistentProperty(const std::string& name, const std::string& value);
 
diff --git a/init/property_service.cpp b/init/property_service.cpp
index cdd0afe..38cbea3 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -412,9 +412,8 @@
         }
     }
 
-    // Don't write properties to disk until after we have read all default
-    // properties to prevent them from being overwritten by default values.
-    if (socket && persistent_properties_loaded && StartsWith(name, "persist.")) {
+    bool need_persist = StartsWith(name, "persist.") || StartsWith(name, "next_boot.");
+    if (socket && persistent_properties_loaded && need_persist) {
         if (persist_write_thread) {
             persist_write_thread->Write(name, value, std::move(*socket));
             return {};
@@ -1398,11 +1397,43 @@
         case InitMessage::kLoadPersistentProperties: {
             load_override_properties();
             // Read persistent properties after all default values have been loaded.
+            // Apply staged and persistent properties
+            bool has_staged_prop = false;
+            auto const staged_prefix = std::string_view("next_boot.");
+            auto const staged_persist_prefix = std::string_view("next_boot.persist.");
+            auto persist_props_map = std::unordered_map<std::string, std::string>();
+
             auto persistent_properties = LoadPersistentProperties();
-            for (const auto& persistent_property_record : persistent_properties.properties()) {
-                InitPropertySet(persistent_property_record.name(),
-                                persistent_property_record.value());
+            for (const auto& property_record : persistent_properties.properties()) {
+                auto const& prop_name = property_record.name();
+                auto const& prop_value = property_record.value();
+
+                if (StartsWith(prop_name, staged_prefix)) {
+                  has_staged_prop = true;
+                  auto actual_prop_name = prop_name.substr(staged_prefix.size());
+                  InitPropertySet(actual_prop_name, prop_value);
+                  if (StartsWith(prop_name, staged_persist_prefix)) {
+                    persist_props_map[actual_prop_name] = prop_value;
+                  }
+                } else if (!persist_props_map.count(prop_name)) {
+                  InitPropertySet(prop_name, prop_value);
+                }
             }
+
+            // Update persist prop file if there are staged props
+            if (has_staged_prop) {
+                PersistentProperties updated_persist_props;
+                for (auto const& [prop_name, prop_value] : persist_props_map) {
+                    AddPersistentProperty(prop_name, prop_value, &updated_persist_props);
+                }
+
+                // write current updated persist prop file
+                auto result = WritePersistentPropertyFile(updated_persist_props);
+                if (!result.ok()) {
+                    LOG(ERROR) << "Could not store persistent property: " << result.error();
+                }
+            }
+
             // Apply debug ramdisk special settings after persistent properties are loaded.
             if (android::base::GetBoolProperty("ro.force.debuggable", false)) {
                 // Always enable usb adb if device is booted with debug ramdisk.
diff --git a/libutils/CallStack.cpp b/libutils/CallStack.cpp
index 11f2c92..fe827eb 100644
--- a/libutils/CallStack.cpp
+++ b/libutils/CallStack.cpp
@@ -18,7 +18,7 @@
 
 #include <utils/Printer.h>
 #include <utils/Errors.h>
-#include <utils/Log.h>
+#include <log/log.h>
 
 #include <unwindstack/AndroidUnwinder.h>
 
diff --git a/libutils/FileMap.cpp b/libutils/FileMap.cpp
index 0abb861..3acbce9 100644
--- a/libutils/FileMap.cpp
+++ b/libutils/FileMap.cpp
@@ -21,7 +21,7 @@
 #define LOG_TAG "filemap"
 
 #include <utils/FileMap.h>
-#include <utils/Log.h>
+#include <log/log.h>
 
 #if defined(__MINGW32__) && !defined(__USE_MINGW_ANSI_STDIO)
 # define PRId32 "I32d"
diff --git a/libutils/Printer.cpp b/libutils/Printer.cpp
index c9ae210..4bd49f1 100644
--- a/libutils/Printer.cpp
+++ b/libutils/Printer.cpp
@@ -19,7 +19,7 @@
 
 #include <utils/Printer.h>
 #include <utils/String8.h>
-#include <utils/Log.h>
+#include <log/log.h>
 
 #include <stdlib.h>
 
diff --git a/libutils/RefBase_fuzz.cpp b/libutils/RefBase_fuzz.cpp
index 8291be9..05f47a0 100644
--- a/libutils/RefBase_fuzz.cpp
+++ b/libutils/RefBase_fuzz.cpp
@@ -19,7 +19,7 @@
 #include <thread>
 
 #include "fuzzer/FuzzedDataProvider.h"
-#include "utils/Log.h"
+#include "log/log.h"
 #include "utils/RWLock.h"
 #include "utils/RefBase.h"
 #include "utils/StrongPointer.h"
diff --git a/libutils/StopWatch.cpp b/libutils/StopWatch.cpp
index 28e2d76..c88d60f 100644
--- a/libutils/StopWatch.cpp
+++ b/libutils/StopWatch.cpp
@@ -24,7 +24,7 @@
 #endif
 #include <inttypes.h>
 
-#include <utils/Log.h>
+#include <log/log.h>
 
 namespace android {
 
diff --git a/libutils/String16.cpp b/libutils/String16.cpp
index 38d483e..07a3d23 100644
--- a/libutils/String16.cpp
+++ b/libutils/String16.cpp
@@ -16,7 +16,7 @@
 
 #include <utils/String16.h>
 
-#include <utils/Log.h>
+#include <log/log.h>
 
 #include <ctype.h>
 
diff --git a/libutils/String8.cpp b/libutils/String8.cpp
index 4301f0e..6a75484 100644
--- a/libutils/String8.cpp
+++ b/libutils/String8.cpp
@@ -20,7 +20,7 @@
 #include <utils/String8.h>
 
 #include <utils/Compat.h>
-#include <utils/Log.h>
+#include <log/log.h>
 #include <utils/String16.h>
 
 #include <ctype.h>
diff --git a/libutils/String8_test.cpp b/libutils/String8_test.cpp
index e1fd13a..6f7882a 100644
--- a/libutils/String8_test.cpp
+++ b/libutils/String8_test.cpp
@@ -16,7 +16,7 @@
 
 #define LOG_TAG "String8_test"
 
-#include <utils/Log.h>
+#include <log/log.h>
 #include <utils/String8.h>
 #include <utils/String16.h>
 
diff --git a/libutils/SystemClock.cpp b/libutils/SystemClock.cpp
index 9c71141..df3a898 100644
--- a/libutils/SystemClock.cpp
+++ b/libutils/SystemClock.cpp
@@ -30,7 +30,7 @@
 #include <cutils/compiler.h>
 
 #include <utils/Timers.h>
-#include <utils/Log.h>
+#include <log/log.h>
 
 namespace android {
 
diff --git a/libutils/Threads.cpp b/libutils/Threads.cpp
index e756fec..90ea29b 100644
--- a/libutils/Threads.cpp
+++ b/libutils/Threads.cpp
@@ -34,7 +34,7 @@
 #include <sys/prctl.h>
 #endif
 
-#include <utils/Log.h>
+#include <log/log.h>
 
 #if defined(__ANDROID__)
 #include <processgroup/processgroup.h>
diff --git a/libutils/Timers.cpp b/libutils/Timers.cpp
index 4cfac57..98082c9 100644
--- a/libutils/Timers.cpp
+++ b/libutils/Timers.cpp
@@ -21,7 +21,7 @@
 #include <time.h>
 
 #include <android-base/macros.h>
-#include <utils/Log.h>
+#include <log/log.h>
 
 static constexpr size_t clock_id_max = 5;
 
diff --git a/libutils/Tokenizer.cpp b/libutils/Tokenizer.cpp
index 9fc955c..aa097ae 100644
--- a/libutils/Tokenizer.cpp
+++ b/libutils/Tokenizer.cpp
@@ -19,7 +19,7 @@
 #include <utils/Tokenizer.h>
 #include <fcntl.h>
 #include <sys/stat.h>
-#include <utils/Log.h>
+#include <log/log.h>
 
 #ifndef DEBUG_TOKENIZER
 // Enables debug output for the tokenizer.
diff --git a/libutils/Vector_fuzz.cpp b/libutils/Vector_fuzz.cpp
index 6fd2baf..3cef487 100644
--- a/libutils/Vector_fuzz.cpp
+++ b/libutils/Vector_fuzz.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 #include <fuzzer/FuzzedDataProvider.h>
-#include <utils/Log.h>
+#include <log/log.h>
 #include <utils/Vector.h>
 
 #include <functional>
diff --git a/libutils/misc.cpp b/libutils/misc.cpp
index f77e189..e1b5f01 100644
--- a/libutils/misc.cpp
+++ b/libutils/misc.cpp
@@ -20,7 +20,7 @@
 
 #include <pthread.h>
 
-#include <utils/Log.h>
+#include <log/log.h>
 #include <utils/Vector.h>
 
 #if defined(__ANDROID__) && !defined(__ANDROID_RECOVERY__)
diff --git a/trusty/apploader/fuzz/app_fuzzer.cpp b/trusty/apploader/fuzz/app_fuzzer.cpp
index aa0caca..0a037f9 100644
--- a/trusty/apploader/fuzz/app_fuzzer.cpp
+++ b/trusty/apploader/fuzz/app_fuzzer.cpp
@@ -43,10 +43,6 @@
         {0xb5, 0xe8, 0xa7, 0xe9, 0xef, 0x17, 0x3a, 0x97},
 };
 
-static inline uintptr_t RoundPageUp(uintptr_t val) {
-    return (val + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
-}
-
 static bool SendLoadMsg(int chan, int dma_buf, size_t dma_buf_size) {
     apploader_header hdr = {
             .cmd = APPLOADER_CMD_LOAD_APPLICATION,
@@ -107,7 +103,7 @@
         android::trusty::fuzz::Abort();
     }
 
-    uint64_t shm_len = size ? RoundPageUp(size) : PAGE_SIZE;
+    uint64_t shm_len = size ? size : 4096;
     BufferAllocator alloc;
     unique_fd dma_buf(alloc.Alloc(kDmabufSystemHeapName, shm_len));
     if (dma_buf < 0) {
diff --git a/trusty/confirmationui/TrustyApp.cpp b/trusty/confirmationui/TrustyApp.cpp
index cee8655..2356eef 100644
--- a/trusty/confirmationui/TrustyApp.cpp
+++ b/trusty/confirmationui/TrustyApp.cpp
@@ -30,10 +30,6 @@
 
 using ::android::base::unique_fd;
 
-static inline uintptr_t RoundPageUp(uintptr_t val) {
-    return (val + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
-}
-
 ssize_t TrustyApp::TrustyRpc(const uint8_t* obegin, const uint8_t* oend, uint8_t* ibegin,
                              uint8_t* iend) {
     uint32_t olen = oend - obegin;
@@ -99,7 +95,7 @@
         return;
     }
 
-    uint32_t shm_len = RoundPageUp(CONFIRMATIONUI_MAX_MSG_SIZE);
+    uint32_t shm_len = CONFIRMATIONUI_MAX_MSG_SIZE;
     BufferAllocator allocator;
     unique_fd dma_buf(allocator.Alloc("system", shm_len));
     if (dma_buf < 0) {
diff --git a/trusty/coverage/coverage.cpp b/trusty/coverage/coverage.cpp
index 3c6b5c5..8fc2f5c 100644
--- a/trusty/coverage/coverage.cpp
+++ b/trusty/coverage/coverage.cpp
@@ -43,10 +43,6 @@
 using std::to_string;
 using std::unique_ptr;
 
-static inline uintptr_t RoundPageUp(uintptr_t val) {
-    return (val + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
-}
-
 CoverageRecord::CoverageRecord(string tipc_dev, struct uuid* uuid)
     : tipc_dev_(std::move(tipc_dev)),
       coverage_srv_fd_(-1),
@@ -136,7 +132,7 @@
         return Error() << "failed to open coverage client: " << ret.error();
     }
     record_len_ = resp.open_args.record_len;
-    shm_len_ = RoundPageUp(record_len_);
+    shm_len_ = record_len_;
 
     BufferAllocator allocator;
 
diff --git a/trusty/fuzz/include/trusty/fuzz/utils.h b/trusty/fuzz/include/trusty/fuzz/utils.h
index c906412..cf4962e 100644
--- a/trusty/fuzz/include/trusty/fuzz/utils.h
+++ b/trusty/fuzz/include/trusty/fuzz/utils.h
@@ -21,7 +21,7 @@
 #include <android-base/result.h>
 #include <android-base/unique_fd.h>
 
-#define TIPC_MAX_MSG_SIZE PAGE_SIZE
+#define TIPC_MAX_MSG_SIZE 4096
 
 namespace android {
 namespace trusty {
diff --git a/trusty/keymaster/include/trusty_keymaster/ipc/trusty_keymaster_ipc.h b/trusty/keymaster/include/trusty_keymaster/ipc/trusty_keymaster_ipc.h
index 16207e6..efad254 100644
--- a/trusty/keymaster/include/trusty_keymaster/ipc/trusty_keymaster_ipc.h
+++ b/trusty/keymaster/include/trusty_keymaster/ipc/trusty_keymaster_ipc.h
@@ -22,9 +22,9 @@
 
 __BEGIN_DECLS
 
-const uint32_t TRUSTY_KEYMASTER_RECV_BUF_SIZE = 2 * PAGE_SIZE;
+const uint32_t TRUSTY_KEYMASTER_RECV_BUF_SIZE = 2 * 4096;
 const uint32_t TRUSTY_KEYMASTER_SEND_BUF_SIZE =
-        (PAGE_SIZE - sizeof(struct keymaster_message) - 16 /* tipc header */);
+        (4096 - sizeof(struct keymaster_message) - 16 /* tipc header */);
 
 int trusty_keymaster_connect(void);
 int trusty_keymaster_call(uint32_t cmd, void* in, uint32_t in_size, uint8_t* out,
diff --git a/trusty/libtrusty/tipc-test/tipc_test.c b/trusty/libtrusty/tipc-test/tipc_test.c
index 81c9881..0f50787 100644
--- a/trusty/libtrusty/tipc-test/tipc_test.c
+++ b/trusty/libtrusty/tipc-test/tipc_test.c
@@ -44,6 +44,7 @@
 static const char *closer3_name = "com.android.ipc-unittest.srv.closer3";
 static const char *main_ctrl_name = "com.android.ipc-unittest.ctrl";
 static const char* receiver_name = "com.android.trusty.memref.receiver";
+static const size_t memref_chunk_size = 4096;
 
 static const char* _sopts = "hsvDS:t:r:m:b:";
 /* clang-format off */
@@ -878,7 +879,7 @@
     volatile char* buf = MAP_FAILED;
     BufferAllocator* allocator = NULL;
 
-    const size_t num_pages = 10;
+    const size_t num_chunks = 10;
 
     fd = tipc_connect(dev_name, receiver_name);
     if (fd < 0) {
@@ -894,7 +895,7 @@
         goto cleanup;
     }
 
-    size_t buf_size = PAGE_SIZE * num_pages;
+    size_t buf_size = memref_chunk_size * num_chunks;
     dma_buf = DmabufHeapAlloc(allocator, "system", buf_size, 0, 0 /* legacy align */);
     if (dma_buf < 0) {
         ret = dma_buf;
@@ -927,13 +928,17 @@
     tipc_close(fd);
 
     ret = 0;
-    for (size_t skip = 0; skip < num_pages; skip++) {
-        ret |= strcmp("Hello from Trusty!", (const char*)&buf[skip * PAGE_SIZE]) ? (-1) : 0;
+    for (size_t skip = 0; skip < num_chunks; skip++) {
+        int cmp = strcmp("Hello from Trusty!",
+                         (const char*)&buf[skip * memref_chunk_size]) ? (-1) : 0;
+        if (cmp)
+            fprintf(stderr, "Failed: Unexpected content at page %zu in dmabuf\n", skip);
+        ret |= cmp;
     }
 
 cleanup:
     if (buf != MAP_FAILED) {
-        munmap((char*)buf, PAGE_SIZE);
+        munmap((char*)buf, buf_size);
     }
     close(dma_buf);
     if (allocator) {
diff --git a/trusty/line-coverage/coverage.cpp b/trusty/line-coverage/coverage.cpp
index 57b7025..5f7b3a3 100644
--- a/trusty/line-coverage/coverage.cpp
+++ b/trusty/line-coverage/coverage.cpp
@@ -50,10 +50,6 @@
 using ::android::base::Error;
 using ::std::string;
 
-static inline uintptr_t RoundPageUp(uintptr_t val) {
-    return (val + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
-}
-
 CoverageRecord::CoverageRecord(string tipc_dev, struct uuid* uuid)
     : tipc_dev_(std::move(tipc_dev)),
       coverage_srv_fd_(-1),
@@ -129,7 +125,7 @@
         return Error() << "failed to open coverage client: " << ret.error();
     }
     record_len_ = resp.open_args.record_len;
-    shm_len_ = RoundPageUp(record_len_);
+    shm_len_ = record_len_;
 
     BufferAllocator allocator;
 
diff --git a/trusty/utils/acvp/trusty_modulewrapper.cpp b/trusty/utils/acvp/trusty_modulewrapper.cpp
index 85b7159..817b600 100644
--- a/trusty/utils/acvp/trusty_modulewrapper.cpp
+++ b/trusty/utils/acvp/trusty_modulewrapper.cpp
@@ -31,6 +31,7 @@
 #include <sys/mman.h>
 #include <trusty/tipc.h>
 #include <unistd.h>
+#include <algorithm>
 
 #include "acvp_ipc.h"
 
@@ -42,9 +43,6 @@
 using android::base::unique_fd;
 using android::base::WriteFully;
 
-static inline size_t AlignUpToPage(size_t size) {
-    return (size + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
-}
 
 namespace {
 
@@ -104,15 +102,12 @@
     struct acvp_req request;
     request.num_args = args.size();
 
-    size_t total_args_size = 0;
+    int total_args_size = 0;
     for (auto arg : args) {
         total_args_size += arg.size();
     }
 
-    shm_size_ = ACVP_MIN_SHARED_MEMORY;
-    if (total_args_size > shm_size_) {
-        shm_size_ = AlignUpToPage(total_args_size);
-    }
+    shm_size_ = std::max(ACVP_MIN_SHARED_MEMORY, total_args_size);
     request.buffer_size = shm_size_;
 
     struct iovec iov = {