Merge "fs_mgr_overlayfs: Setup remount scratch dir with encoded mountpoint name" into main
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);