Merge fuse unmount paths to reduce fuse unmount total time

Previously, we were waiting unnecessarily for long times trying to unmount
different fuse paths with no luck at the end. Made sure that we merge
these unmount flows so that we don't sleep separately for each unmount.
Additionally, added polling logic to not sleep the whole duration
without trying to unmount. Further more, made sure that we try to kill
apps using storage/emulated when unmounting fuse paths.

More details about the change can be found here go/mount-performance-improvement

Test: atest AdoptableHostTest, atest StorageManagerTest
Bug: 318335297
Bug: 402367661
Bug: 369519866
Flag: android.vold.flags.enhance_fuse_unmount
Change-Id: Id8af00fd1bff1de4078e4acd148a918738b4cea6
diff --git a/model/PublicVolume.cpp b/model/PublicVolume.cpp
index 747598a..5a30fca 100644
--- a/model/PublicVolume.cpp
+++ b/model/PublicVolume.cpp
@@ -36,9 +36,11 @@
 #include <sys/sysmacros.h>
 #include <sys/types.h>
 #include <sys/wait.h>
+#include <android_vold_flags.h>
 
 using android::base::GetBoolProperty;
 using android::base::StringPrintf;
+namespace flags = android::vold::flags;
 
 namespace android {
 namespace vold {
@@ -309,30 +311,57 @@
     // the FUSE process first, most file system operations will return
     // ENOTCONN until the unmount completes. This is an exotic and unusual
     // error code and might cause broken behaviour in applications.
-    KillProcessesUsingPath(getPath());
+
+    // We don't kill processes here if enhance_fuse_unmount as we make sure that we kill processes
+    // only if unmounting failed
+    if (!mFuseMounted || !flags::enhance_fuse_unmount()) {
+        KillProcessesUsingPath(getPath());
+    }
 
     if (mFuseMounted) {
         std::string stableName = getStableName();
 
         // Unmount bind mounts for running users
         auto vol_manager = VolumeManager::Instance();
-        int user_id = getMountUserId();
-        for (int started_user : vol_manager->getStartedUsers()) {
+        userid_t user_id = getMountUserId();
+        std::vector<std::string> bind_mount_paths;
+        for (userid_t started_user : vol_manager->getStartedUsers()) {
             if (started_user == user_id) {
                 // No need to remove bind mount for the user that owns the mount
                 continue;
             }
-            LOG(INFO) << "Removing Public Volume Bind Mount for: " << started_user;
+            if (user_id != VolumeManager::Instance()->getSharedStorageUser(started_user)) {
+                // No need to remove bind mount
+                // if the user does not share storage with the mount owner
+                continue;
+            }
+
             auto mountPath = GetFuseMountPathForUser(started_user, stableName);
-            ForceUnmount(mountPath);
-            rmdir(mountPath.c_str());
+            if (flags::enhance_fuse_unmount()) {
+                // Add it to list so that we unmount it as part of UnmountUserFuseEnhanced
+                bind_mount_paths.push_back(mountPath);
+            } else {
+                LOG(INFO) << "Removing Public Volume Bind Mount for: " << started_user;
+                ForceUnmount(mountPath);
+                rmdir(mountPath.c_str());
+            }
         }
 
-        if (UnmountUserFuse(getMountUserId(), getInternalPath(), stableName) != OK) {
-            PLOG(INFO) << "UnmountUserFuse failed on public fuse volume";
-            return -errno;
+        if (flags::enhance_fuse_unmount()) {
+            status_t result = UnmountUserFuseEnhanced(getMountUserId(), getInternalPath(),
+                                                      stableName, getPath(), bind_mount_paths);
+            if (result != OK) {
+                PLOG(INFO) << "UnmountUserFuseEnhanced failed on public fuse volume";
+                return result;
+            }
+        } else {
+            if (UnmountUserFuse(getMountUserId(), getInternalPath(), stableName) != OK) {
+                PLOG(INFO) << "UnmountUserFuse failed on public fuse volume";
+                return -errno;
+            }
         }
 
+
         mFuseMounted = false;
     }