fs_mgr_overlayfs: Setup remount scratch dir with encoded mountpoint name

Instead of using the basename(mounpoint) as partition scratch dir name,
which could lead to name collision, use the normalized and encoded
mountpoint as scratch dir name.

Bug: 243503963
Bug: 306124139
Test: adb-remount-test
Change-Id: I5a64f17bc3b88f0ce42bd0c5779c8dd23a07917f
diff --git a/fs_mgr/fs_mgr_overlayfs_control.cpp b/fs_mgr/fs_mgr_overlayfs_control.cpp
index 2cc0d2d..50d8280 100644
--- a/fs_mgr/fs_mgr_overlayfs_control.cpp
+++ b/fs_mgr/fs_mgr_overlayfs_control.cpp
@@ -144,7 +144,8 @@
     if (fs_mgr_overlayfs_already_mounted(mount_point)) {
         return true;
     }
-    auto fsrec_mount_point = overlay + "/" + android::base::Basename(mount_point) + "/";
+    const auto base = GetEncodedBaseDirForMountPoint(mount_point);
+    auto fsrec_mount_point = overlay + "/" + base + "/";
 
     AutoSetFsCreateCon createcon(kOverlayfsFileContext);
     if (!createcon.Ok()) {
@@ -286,10 +287,10 @@
     }
 
     auto cleanup_all = mount_point.empty();
-    const auto partition_name = android::base::Basename(mount_point);
-    const auto oldpath = top + (cleanup_all ? "" : ("/" + partition_name));
+    const auto base = GetEncodedBaseDirForMountPoint(mount_point);
+    const auto oldpath = top + (cleanup_all ? "" : ("/" + base));
     const auto newpath = cleanup_all ? overlay + "/." + kOverlayTopDir + ".teardown"
-                                     : top + "/." + partition_name + ".teardown";
+                                     : top + "/." + base + ".teardown";
     auto ret = fs_mgr_rm_all(newpath);
     if (!rename(oldpath.c_str(), newpath.c_str())) {
         if (change) *change = true;
diff --git a/fs_mgr/fs_mgr_overlayfs_mount.cpp b/fs_mgr/fs_mgr_overlayfs_mount.cpp
index 9f17c06..0dadbff 100644
--- a/fs_mgr/fs_mgr_overlayfs_mount.cpp
+++ b/fs_mgr/fs_mgr_overlayfs_mount.cpp
@@ -60,6 +60,7 @@
 
 constexpr char kLowerdirOption[] = "lowerdir=";
 constexpr char kUpperdirOption[] = "upperdir=";
+constexpr char kWorkdirOption[] = "workdir=";
 
 bool fs_mgr_is_dsu_running() {
     // Since android::gsi::CanBootIntoGsi() or android::gsi::MarkSystemAsGsi() is
@@ -89,6 +90,14 @@
     return {kScratchMountPoint, kCacheMountPoint};
 }
 
+std::string GetEncodedBaseDirForMountPoint(const std::string& mount_point) {
+    std::string normalized_path;
+    if (mount_point.empty() || !android::base::Realpath(mount_point, &normalized_path)) {
+        return "";
+    }
+    return android::base::StringReplace(normalized_path, "/", "@", true);
+}
+
 static bool fs_mgr_is_dir(const std::string& path) {
     struct stat st;
     return !stat(path.c_str(), &st) && S_ISDIR(st.st_mode);
@@ -202,21 +211,6 @@
     return has_shared_blocks;
 }
 
-static std::string fs_mgr_get_overlayfs_candidate(const std::string& mount_point) {
-    if (!fs_mgr_is_dir(mount_point)) return "";
-    const auto base = android::base::Basename(mount_point) + "/";
-    for (const auto& overlay_mount_point : OverlayMountPoints()) {
-        auto dir = overlay_mount_point + "/" + kOverlayTopDir + "/" + base;
-        auto upper = dir + kUpperName;
-        if (!fs_mgr_is_dir(upper)) continue;
-        auto work = dir + kWorkName;
-        if (!fs_mgr_is_dir(work)) continue;
-        if (access(work.c_str(), R_OK | W_OK)) continue;
-        return dir;
-    }
-    return "";
-}
-
 const std::string fs_mgr_mount_point(const std::string& mount_point) {
     if ("/"s != mount_point) return mount_point;
     return "/system";
@@ -225,16 +219,30 @@
 // default options for mount_point, returns empty string for none available.
 static std::string fs_mgr_get_overlayfs_options(const FstabEntry& entry) {
     const auto mount_point = fs_mgr_mount_point(entry.mount_point);
-    auto candidate = fs_mgr_get_overlayfs_candidate(mount_point);
-    if (candidate.empty()) return "";
-    auto ret = kLowerdirOption + mount_point + "," + kUpperdirOption + candidate + kUpperName +
-               ",workdir=" + candidate + kWorkName + android::fs_mgr::CheckOverlayfs().mount_flags;
-    for (const auto& flag : android::base::Split(entry.fs_options, ",")) {
-        if (android::base::StartsWith(flag, "context=")) {
-            ret += "," + flag;
-        }
+    if (!fs_mgr_is_dir(mount_point)) {
+        return "";
     }
-    return ret;
+    const auto base = GetEncodedBaseDirForMountPoint(mount_point);
+    if (base.empty()) {
+        return "";
+    }
+    for (const auto& overlay_mount_point : OverlayMountPoints()) {
+        const auto dir = overlay_mount_point + "/" + kOverlayTopDir + "/" + base + "/";
+        const auto upper = dir + kUpperName;
+        const auto work = dir + kWorkName;
+        if (!fs_mgr_is_dir(upper) || !fs_mgr_is_dir(work) || access(work.c_str(), R_OK | W_OK)) {
+            continue;
+        }
+        auto ret = kLowerdirOption + mount_point + "," + kUpperdirOption + upper + "," +
+                   kWorkdirOption + work + android::fs_mgr::CheckOverlayfs().mount_flags;
+        for (const auto& flag : android::base::Split(entry.fs_options, ",")) {
+            if (android::base::StartsWith(flag, "context=")) {
+                ret += "," + flag;
+            }
+        }
+        return ret;
+    }
+    return "";
 }
 
 bool AutoSetFsCreateCon::Set(const std::string& context) {
diff --git a/fs_mgr/fs_mgr_overlayfs_mount.h b/fs_mgr/fs_mgr_overlayfs_mount.h
index f0afac1..98b9007 100644
--- a/fs_mgr/fs_mgr_overlayfs_mount.h
+++ b/fs_mgr/fs_mgr_overlayfs_mount.h
@@ -58,3 +58,4 @@
 bool fs_mgr_overlayfs_already_mounted(const std::string& mount_point, bool overlay_only = true);
 bool fs_mgr_wants_overlayfs(android::fs_mgr::FstabEntry* entry);
 android::fs_mgr::Fstab fs_mgr_overlayfs_candidate_list(const android::fs_mgr::Fstab& fstab);
+std::string GetEncodedBaseDirForMountPoint(const std::string& mount_point);