Merge "libutils_binder: isolate headers" into main
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index 3b8866e..2d55e5a 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -461,6 +461,14 @@
     {"reboot,smpl_timeout,pmic,main", 229},
     {"reboot,ota,.*", 230},
     {"reboot,periodic,.*", 231},
+    {"reboot,early,abl", 232},
+    {"reboot,early,bl2", 233},
+    {"reboot,longkey,pmic_cold", 234},
+    {"reboot,longkey,master_dc", 235},
+    {"reboot,ocp2,pmic,if", 236},
+    {"reboot,ocp,pmic,if", 237},
+    {"reboot,fship", 238},
+    {"reboot,ocp,.*", 239},
 };
 
 // Converts a string value representing the reason the system booted to an
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 56b90b9..ac2a20f 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -1053,8 +1053,10 @@
             return false;
         }
         sparse_file_destroy(s);
+        buf->file_type = FB_BUFFER_SPARSE;
     } else {
         buf->image_size = sz;
+        buf->file_type = FB_BUFFER_FD;
     }
 
     lseek(fd.get(), 0, SEEK_SET);
@@ -1191,6 +1193,15 @@
         should_flash_in_userspace(source, partition)) {
         return;
     }
+
+    // If the image is sparse, moving the footer will simply corrupt the sparse
+    // format, so currently we don't support moving the footer on sparse files.
+    if (buf->file_type == FB_BUFFER_SPARSE) {
+        LOG(ERROR) << "Warning: skip copying " << partition << " image avb footer due to sparse "
+                   << "image.";
+        return;
+    }
+
     // If overflows and negative, it should be < buf->sz.
     int64_t partition_size = static_cast<int64_t>(get_partition_size(partition));
 
diff --git a/fastboot/fastboot.h b/fastboot/fastboot.h
index 2c40890..6a49970 100644
--- a/fastboot/fastboot.h
+++ b/fastboot/fastboot.h
@@ -57,7 +57,8 @@
 };
 
 struct fastboot_buffer {
-    enum fb_buffer_type type;
+    fb_buffer_type type;
+    fb_buffer_type file_type;
     std::vector<SparsePtr> files;
     int64_t sz;
     unique_fd fd;
diff --git a/fs_mgr/fs_mgr_overlayfs_mount.cpp b/fs_mgr/fs_mgr_overlayfs_mount.cpp
index 0dadbff..ae7ed4c 100644
--- a/fs_mgr/fs_mgr_overlayfs_mount.cpp
+++ b/fs_mgr/fs_mgr_overlayfs_mount.cpp
@@ -381,54 +381,86 @@
 
     auto retval = true;
 
-    struct move_entry {
+    struct MoveEntry {
         std::string mount_point;
         std::string dir;
         bool shared_flag;
     };
-    std::vector<move_entry> move;
+
+    std::vector<MoveEntry> moved_mounts;
     auto parent_private = false;
     auto parent_made_private = false;
     auto dev_private = false;
     auto dev_made_private = false;
-    for (auto& entry : ReadMountinfoFromFile("/proc/self/mountinfo")) {
+
+    // There could be multiple mount entries with the same mountpoint.
+    // Group these entries together with stable_sort, and keep only the last entry of a group.
+    // Only move mount the last entry in an over mount group, because the other entries are
+    // overshadowed and only the filesystem mounted with the last entry participates in file
+    // pathname resolution.
+    auto mountinfo = ReadMountinfoFromFile("/proc/self/mountinfo");
+    std::stable_sort(mountinfo.begin(), mountinfo.end(), [](const auto& lhs, const auto& rhs) {
+        return lhs.mount_point < rhs.mount_point;
+    });
+    std::reverse(mountinfo.begin(), mountinfo.end());
+    auto erase_from = std::unique(
+            mountinfo.begin(), mountinfo.end(),
+            [](const auto& lhs, const auto& rhs) { return lhs.mount_point == rhs.mount_point; });
+    mountinfo.erase(erase_from, mountinfo.end());
+    std::reverse(mountinfo.begin(), mountinfo.end());
+    // mountinfo is reversed twice, so still is in lexical sorted order.
+
+    for (const auto& entry : mountinfo) {
         if ((entry.mount_point == mount_point) && !entry.shared_flag) {
             parent_private = true;
         }
         if ((entry.mount_point == "/dev") && !entry.shared_flag) {
             dev_private = true;
         }
+    }
 
+    // Need to make the original mountpoint MS_PRIVATE, so that the overlayfs can be MS_MOVE.
+    // This could happen if its parent mount is remounted later.
+    if (!parent_private) {
+        parent_made_private = fs_mgr_overlayfs_set_shared_mount(mount_point, false);
+    }
+
+    for (const auto& entry : mountinfo) {
+        // Find all immediate submounts.
         if (!android::base::StartsWith(entry.mount_point, mount_point + "/")) {
             continue;
         }
-        if (std::find_if(move.begin(), move.end(), [&entry](const auto& it) {
-                return android::base::StartsWith(entry.mount_point, it.mount_point + "/");
-            }) != move.end()) {
+        // Exclude duplicated or more specific entries.
+        if (std::find_if(moved_mounts.begin(), moved_mounts.end(), [&entry](const auto& it) {
+                return it.mount_point == entry.mount_point ||
+                       android::base::StartsWith(entry.mount_point, it.mount_point + "/");
+            }) != moved_mounts.end()) {
             continue;
         }
+        // mountinfo is in lexical order, so no need to worry about |entry| being a parent mount of
+        // entries of |moved_mounts|.
 
         // use as the bound directory in /dev.
-        AutoSetFsCreateCon createcon;
-        auto new_context = fs_mgr_get_context(entry.mount_point);
-        if (new_context.empty() || !createcon.Set(new_context)) {
-            continue;
-        }
-        move_entry new_entry = {std::move(entry.mount_point), "/dev/TemporaryDir-XXXXXX",
-                                entry.shared_flag};
-        const auto target = mkdtemp(new_entry.dir.data());
-        if (!createcon.Restore()) {
-            return false;
-        }
-        if (!target) {
-            retval = false;
-            PERROR << "temporary directory for MS_BIND";
-            continue;
+        MoveEntry new_entry{entry.mount_point, "/dev/TemporaryDir-XXXXXX", entry.shared_flag};
+        {
+            AutoSetFsCreateCon createcon;
+            auto new_context = fs_mgr_get_context(entry.mount_point);
+            if (new_context.empty() || !createcon.Set(new_context)) {
+                continue;
+            }
+            const auto target = mkdtemp(new_entry.dir.data());
+            if (!target) {
+                retval = false;
+                PERROR << "temporary directory for MS_MOVE";
+                continue;
+            }
+            if (!createcon.Restore()) {
+                retval = false;
+                rmdir(new_entry.dir.c_str());
+                continue;
+            }
         }
 
-        if (!parent_private && !parent_made_private) {
-            parent_made_private = fs_mgr_overlayfs_set_shared_mount(mount_point, false);
-        }
         if (new_entry.shared_flag) {
             new_entry.shared_flag = fs_mgr_overlayfs_set_shared_mount(new_entry.mount_point, false);
         }
@@ -437,9 +469,10 @@
             if (new_entry.shared_flag) {
                 fs_mgr_overlayfs_set_shared_mount(new_entry.mount_point, true);
             }
+            rmdir(new_entry.dir.c_str());
             continue;
         }
-        move.emplace_back(std::move(new_entry));
+        moved_mounts.push_back(std::move(new_entry));
     }
 
     // hijack __mount() report format to help triage
@@ -463,7 +496,7 @@
     }
 
     // Move submounts back.
-    for (const auto& entry : move) {
+    for (const auto& entry : moved_mounts) {
         if (!dev_private && !dev_made_private) {
             dev_made_private = fs_mgr_overlayfs_set_shared_mount("/dev", false);
         }
@@ -658,22 +691,13 @@
             !fs_mgr_wants_overlayfs(&new_entry)) {
             continue;
         }
-        auto new_mount_point = fs_mgr_mount_point(entry.mount_point);
-        auto duplicate_or_more_specific = false;
-        for (auto it = candidates.begin(); it != candidates.end();) {
-            auto it_mount_point = fs_mgr_mount_point(it->mount_point);
-            if ((it_mount_point == new_mount_point) ||
-                (android::base::StartsWith(new_mount_point, it_mount_point + "/"))) {
-                duplicate_or_more_specific = true;
-                break;
-            }
-            if (android::base::StartsWith(it_mount_point, new_mount_point + "/")) {
-                it = candidates.erase(it);
-            } else {
-                ++it;
-            }
+        const auto new_mount_point = fs_mgr_mount_point(new_entry.mount_point);
+        if (std::find_if(candidates.begin(), candidates.end(), [&](const auto& it) {
+                return fs_mgr_mount_point(it.mount_point) == new_mount_point;
+            }) != candidates.end()) {
+            continue;
         }
-        if (!duplicate_or_more_specific) candidates.emplace_back(std::move(new_entry));
+        candidates.push_back(std::move(new_entry));
     }
     return candidates;
 }
@@ -707,7 +731,7 @@
         return false;
     }
     auto ret = true;
-    auto scratch_can_be_mounted = true;
+    auto scratch_can_be_mounted = !fs_mgr_overlayfs_already_mounted(kScratchMountPoint, false);
     for (const auto& entry : fs_mgr_overlayfs_candidate_list(*fstab)) {
         if (fs_mgr_is_verity_enabled(entry)) continue;
         auto mount_point = fs_mgr_mount_point(entry.mount_point);
diff --git a/fs_mgr/fs_mgr_remount.cpp b/fs_mgr/fs_mgr_remount.cpp
index 4b3a5d3..7ba4d2b 100644
--- a/fs_mgr/fs_mgr_remount.cpp
+++ b/fs_mgr/fs_mgr_remount.cpp
@@ -88,17 +88,6 @@
     return entry.mount_point;
 }
 
-const FstabEntry* GetWrappedEntry(const Fstab& overlayfs_candidates, const FstabEntry& entry) {
-    auto mount_point = system_mount_point(entry);
-    auto it = std::find_if(overlayfs_candidates.begin(), overlayfs_candidates.end(),
-                           [&mount_point](const auto& entry) {
-                               return android::base::StartsWith(mount_point,
-                                                                system_mount_point(entry) + "/");
-                           });
-    if (it == overlayfs_candidates.end()) return nullptr;
-    return &(*it);
-}
-
 class MyLogger {
   public:
     explicit MyLogger(bool verbose) : verbose_(verbose) {}
@@ -169,15 +158,25 @@
     // not checkpointing.
     auto vold = GetVold();
     bool checkpointing = false;
-    if (!vold->isCheckpointing(&checkpointing).isOk()) {
-        LOG(ERROR) << "Could not determine checkpointing status.";
-        return false;
-    }
-    if (checkpointing) {
-        LOG(ERROR) << "Cannot use remount when a checkpoint is in progress.";
-        LOG(ERROR) << "To force end checkpointing, call 'vdc checkpoint commitChanges'";
-        LOG(ERROR) << "Warning: this can lead to data corruption if rolled back.";
-        return false;
+    bool show_help = true;
+
+    while (true) {
+        if (!vold->isCheckpointing(&checkpointing).isOk()) {
+            LOG(ERROR) << "Could not determine checkpointing status.";
+            return false;
+        }
+        if (!checkpointing) {
+            break;
+        }
+        if (show_help) {
+            show_help = false;
+            std::cerr << "WARNING: Userdata checkpoint is in progress. To force end checkpointing, "
+                         "call 'vdc checkpoint commitChanges'. This can lead to data corruption if "
+                         "rolled back."
+                      << std::endl;
+            LOG(INFO) << "Waiting for checkpoint to complete and then continue remount.";
+        }
+        std::this_thread::sleep_for(4s);
     }
     return true;
 }
@@ -196,9 +195,6 @@
     if (auto candidate_entry = GetEntryForMountPoint(&candidates, entry.mount_point)) {
         return candidate_entry->fs_type == entry.fs_type;
     }
-    if (GetWrappedEntry(candidates, entry)) {
-        return false;
-    }
     return true;
 }
 
@@ -252,11 +248,6 @@
         }
 
         const FstabEntry* entry = &*it;
-        if (auto wrap = GetWrappedEntry(candidates, *entry); wrap != nullptr) {
-            LOG(INFO) << "partition " << arg << " covered by overlayfs for " << wrap->mount_point
-                      << ", switching";
-            entry = wrap;
-        }
 
         // If it's already remounted, include it so it gets gracefully skipped
         // later on.
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h
index 2721937..debaf36 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h
@@ -172,7 +172,7 @@
 
     android::base::unique_fd owned_fd_;
     android::base::borrowed_fd fd_;
-    CowHeader header_;
+    CowHeaderV3 header_;
     std::optional<CowFooter> footer_;
     uint64_t fd_size_;
     std::optional<uint64_t> last_label_;
@@ -188,7 +188,10 @@
     uint8_t compression_type_ = kCowCompressNone;
 };
 
-bool ReadCowHeader(android::base::borrowed_fd fd, CowHeader* header);
+// Though this function takes in a CowHeaderV3, the struct could be populated as a v1/v2 CowHeader.
+// The extra fields will just be filled as 0. V3 header is strictly a superset of v1/v2 header and
+// contains all of the latter's field
+bool ReadCowHeader(android::base::borrowed_fd fd, CowHeaderV3* header);
 
 }  // namespace snapshot
 }  // namespace android
diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/cow_reader.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/cow_reader.cpp
index 607d610..3b84c95 100644
--- a/fs_mgr/libsnapshot/libsnapshot_cow/cow_reader.cpp
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/cow_reader.cpp
@@ -28,12 +28,13 @@
 #include <zlib.h>
 
 #include "cow_decompress.h"
+#include "libsnapshot/cow_format.h"
 #include "parser_v2.h"
 
 namespace android {
 namespace snapshot {
 
-bool ReadCowHeader(android::base::borrowed_fd fd, CowHeader* header) {
+bool ReadCowHeader(android::base::borrowed_fd fd, CowHeaderV3* header) {
     if (lseek(fd.get(), 0, SEEK_SET) < 0) {
         PLOG(ERROR) << "lseek header failed";
         return false;
@@ -49,9 +50,9 @@
                    << "Expected: " << kCowMagicNumber;
         return false;
     }
-    if (header->prefix.header_size > sizeof(CowHeader)) {
+    if (header->prefix.header_size > sizeof(CowHeaderV3)) {
         LOG(ERROR) << "Unknown CowHeader size (got " << header->prefix.header_size
-                   << " bytes, expected at most " << sizeof(CowHeader) << " bytes)";
+                   << " bytes, expected at most " << sizeof(CowHeaderV3) << " bytes)";
         return false;
     }
 
diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/inspect_cow.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/inspect_cow.cpp
index 83b5a12..a291469 100644
--- a/fs_mgr/libsnapshot/libsnapshot_cow/inspect_cow.cpp
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/inspect_cow.cpp
@@ -90,7 +90,7 @@
 }
 
 static bool ShowRawOpStream(borrowed_fd fd) {
-    CowHeader header;
+    CowHeaderV3 header;
     if (!ReadCowHeader(fd, &header)) {
         LOG(ERROR) << "parse header failed";
         return false;
diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/test_v3.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/test_v3.cpp
index 2373d4d..cc8dd83 100644
--- a/fs_mgr/libsnapshot/libsnapshot_cow/test_v3.cpp
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/test_v3.cpp
@@ -26,7 +26,9 @@
 #include <libsnapshot/cow_writer.h>
 #include "cow_decompress.h"
 #include "libsnapshot/cow_format.h"
+#include "writer_v2.h"
 #include "writer_v3.h"
+
 using android::base::unique_fd;
 using testing::AssertionFailure;
 using testing::AssertionResult;
@@ -49,5 +51,27 @@
     std::unique_ptr<TemporaryFile> cow_;
 };
 
+TEST_F(CowOperationV3Test, CowHeaderV2Test) {
+    CowOptions options;
+    options.cluster_ops = 5;
+    options.num_merge_ops = 1;
+    options.block_size = 4096;
+    std::string data = "This is some data, believe it";
+    data.resize(options.block_size, '\0');
+    auto writer_v2 = std::make_unique<CowWriterV2>(options, GetCowFd());
+    ASSERT_TRUE(writer_v2->Initialize());
+    ASSERT_TRUE(writer_v2->Finalize());
+
+    CowReader reader;
+    ASSERT_TRUE(reader.Parse(cow_->fd));
+
+    const auto& header = reader.GetHeader();
+    ASSERT_EQ(header.prefix.magic, kCowMagicNumber);
+    ASSERT_EQ(header.prefix.major_version, kCowVersionMajor);
+    ASSERT_EQ(header.prefix.minor_version, kCowVersionMinor);
+    ASSERT_EQ(header.block_size, options.block_size);
+    ASSERT_EQ(header.cluster_ops, options.cluster_ops);
+}
+
 }  // namespace snapshot
 }  // namespace android
\ No newline at end of file
diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp
index 63bed07..83a9b1b 100644
--- a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp
@@ -269,9 +269,11 @@
 }
 
 bool CowWriterV2::OpenForAppend(uint64_t label) {
-    if (!ReadCowHeader(fd_, &header_)) {
+    CowHeaderV3 header_v3;
+    if (!ReadCowHeader(fd_, &header_v3)) {
         return false;
     }
+    header_ = header_v3;
 
     CowParserV2 parser;
     if (!parser.Parse(fd_, header_, {label})) {
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index f5732fc..eb4beb7 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -3658,7 +3658,7 @@
         return nullptr;
     }
 
-    CowHeader header;
+    CowHeaderV3 header;
     if (!ReadCowHeader(cow_fd, &header)) {
         LOG(ERROR) << "OpenCompressedSnapshotWriter: read header failed";
         return nullptr;
diff --git a/init/persistent_properties.cpp b/init/persistent_properties.cpp
index 8efb72c..e89244f 100644
--- a/init/persistent_properties.cpp
+++ b/init/persistent_properties.cpp
@@ -115,24 +115,6 @@
     }
 }
 
-PersistentProperties LoadPersistentPropertiesFromMemory() {
-    PersistentProperties persistent_properties;
-    __system_property_foreach(
-        [](const prop_info* pi, void* cookie) {
-            __system_property_read_callback(
-                pi,
-                [](void* cookie, const char* name, const char* value, unsigned serial) {
-                    if (StartsWith(name, "persist.")) {
-                        auto properties = reinterpret_cast<PersistentProperties*>(cookie);
-                        AddPersistentProperty(name, value, properties);
-                    }
-                },
-                cookie);
-        },
-        &persistent_properties);
-    return persistent_properties;
-}
-
 Result<std::string> ReadPersistentPropertyFile() {
     const std::string temp_filename = persistent_property_filename + ".tmp";
     if (access(temp_filename.c_str(), F_OK) == 0) {
@@ -221,6 +203,24 @@
     return {};
 }
 
+PersistentProperties LoadPersistentPropertiesFromMemory() {
+    PersistentProperties persistent_properties;
+    __system_property_foreach(
+            [](const prop_info* pi, void* cookie) {
+                __system_property_read_callback(
+                        pi,
+                        [](void* cookie, const char* name, const char* value, unsigned serial) {
+                            if (StartsWith(name, "persist.")) {
+                                auto properties = reinterpret_cast<PersistentProperties*>(cookie);
+                                AddPersistentProperty(name, value, properties);
+                            }
+                        },
+                        cookie);
+            },
+            &persistent_properties);
+    return persistent_properties;
+}
+
 // Persistent properties are not written often, so we rather not keep any data in memory and read
 // then rewrite the persistent property file for each update.
 void WritePersistentProperty(const std::string& name, const std::string& value) {
diff --git a/init/persistent_properties.h b/init/persistent_properties.h
index a6f80e6..7e9d438 100644
--- a/init/persistent_properties.h
+++ b/init/persistent_properties.h
@@ -29,6 +29,7 @@
                            PersistentProperties* persistent_properties);
 PersistentProperties LoadPersistentProperties();
 void WritePersistentProperty(const std::string& name, const std::string& value);
+PersistentProperties LoadPersistentPropertiesFromMemory();
 
 // Exposed only for testing
 Result<PersistentProperties> LoadPersistentPropertyFile();
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 38cbea3..b08a904 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -1400,8 +1400,6 @@
             // 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& property_record : persistent_properties.properties()) {
@@ -1412,23 +1410,16 @@
                   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)) {
+                } else {
                   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);
-                }
-
+                PersistentProperties props = LoadPersistentPropertiesFromMemory();
                 // write current updated persist prop file
-                auto result = WritePersistentPropertyFile(updated_persist_props);
+                auto result = WritePersistentPropertyFile(props);
                 if (!result.ok()) {
                     LOG(ERROR) << "Could not store persistent property: " << result.error();
                 }
diff --git a/init/selinux.cpp b/init/selinux.cpp
index 9095b85..1f211dd 100644
--- a/init/selinux.cpp
+++ b/init/selinux.cpp
@@ -503,10 +503,6 @@
                         << ") failed";
         }
     }
-
-    if (auto result = WriteFile("/sys/fs/selinux/checkreqprot", "0"); !result.ok()) {
-        LOG(FATAL) << "Unable to write to /sys/fs/selinux/checkreqprot: " << result.error();
-    }
 }
 
 constexpr size_t kKlogMessageSize = 1024;