Merge "fastboot: Fix flashing failure when a sparse image has an avb footer." 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/fs_mgr/fs_mgr_overlayfs_mount.cpp b/fs_mgr/fs_mgr_overlayfs_mount.cpp
index 66faecd..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;
 }
diff --git a/fs_mgr/fs_mgr_remount.cpp b/fs_mgr/fs_mgr_remount.cpp
index 4b3a5d3..18892f9 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) {}
@@ -196,9 +185,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 +238,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.