Merge "Add a method in vold to unmount app data and obb dir for testing"
diff --git a/VoldNativeService.cpp b/VoldNativeService.cpp
index 03dee48..9f4f7b0 100644
--- a/VoldNativeService.cpp
+++ b/VoldNativeService.cpp
@@ -377,7 +377,17 @@
     ENFORCE_SYSTEM_OR_ROOT;
     ACQUIRE_LOCK;
 
-    return translate(VolumeManager::Instance()->remountAppStorageDirs(uid, pid, packageNames));
+    return translate(VolumeManager::Instance()->handleAppStorageDirs(uid, pid,
+            false /* doUnmount */, packageNames));
+}
+
+binder::Status VoldNativeService::unmountAppStorageDirs(int uid, int pid,
+        const std::vector<std::string>& packageNames) {
+    ENFORCE_SYSTEM_OR_ROOT;
+    ACQUIRE_LOCK;
+
+    return translate(VolumeManager::Instance()->handleAppStorageDirs(uid, pid,
+            true /* doUnmount */, packageNames));
 }
 
 binder::Status VoldNativeService::setupAppDir(const std::string& path, int32_t appUid) {
diff --git a/VoldNativeService.h b/VoldNativeService.h
index 8fd6261..47991c2 100644
--- a/VoldNativeService.h
+++ b/VoldNativeService.h
@@ -66,6 +66,8 @@
     binder::Status remountUid(int32_t uid, int32_t remountMode);
     binder::Status remountAppStorageDirs(int uid, int pid,
                                const std::vector<std::string>& packageNames);
+    binder::Status unmountAppStorageDirs(int uid, int pid,
+                               const std::vector<std::string>& packageNames);
 
     binder::Status ensureAppDirsCreated(const std::vector<std::string>& paths, int32_t appUid);
     binder::Status setupAppDir(const std::string& path, int32_t appUid);
diff --git a/VolumeManager.cpp b/VolumeManager.cpp
index ce7a8b1..ac7356c 100644
--- a/VolumeManager.cpp
+++ b/VolumeManager.cpp
@@ -683,6 +683,43 @@
     return true;
 }
 
+// In each app's namespace, unmount obb and data dirs
+static bool umountStorageDirs(int nsFd, const char* android_data_dir, const char* android_obb_dir,
+        int uid, const char* targets[], int size) {
+    // This code is executed after a fork so it's very important that the set of
+    // methods we call here is strictly limited.
+    if (setns(nsFd, CLONE_NEWNS) != 0) {
+        async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Failed to setns %s", strerror(errno));
+        return false;
+    }
+
+    // Unmount of Android/data/foo needs to be done before Android/data below.
+    bool result = true;
+    for (int i = 0; i < size; i++) {
+        if (TEMP_FAILURE_RETRY(umount2(targets[i], MNT_DETACH)) < 0 && errno != EINVAL &&
+                errno != ENOENT) {
+            async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Failed to umount %s: %s",
+                                  targets[i], strerror(errno));
+            result = false;
+        }
+    }
+
+    // Mount tmpfs on Android/data and Android/obb
+    if (TEMP_FAILURE_RETRY(umount2(android_data_dir, MNT_DETACH)) < 0 && errno != EINVAL &&
+                errno != ENOENT) {
+        async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Failed to umount %s :%s",
+                        android_data_dir, strerror(errno));
+        result = false;
+    }
+    if (TEMP_FAILURE_RETRY(umount2(android_obb_dir, MNT_DETACH)) < 0 && errno != EINVAL &&
+                errno != ENOENT) {
+        async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Failed to umount %s :%s",
+                android_obb_dir, strerror(errno));
+        result = false;
+    }
+    return result;
+}
+
 // In each app's namespace, mount tmpfs on obb and data dir, and bind mount obb and data
 // package dirs.
 static bool remountStorageDirs(int nsFd, const char* android_data_dir, const char* android_obb_dir,
@@ -741,8 +778,8 @@
             userId, dirName.c_str(), packageName.c_str());
 }
 
-// Fork the process and remount storage
-bool VolumeManager::forkAndRemountStorage(int uid, int pid,
+// Fork the process and remount / unmount app data and obb dirs
+bool VolumeManager::forkAndRemountStorage(int uid, int pid, bool doUnmount,
                                           const std::vector<std::string>& packageNames) {
     userid_t userId = multiuser_get_user_id(uid);
     std::string mnt_path = StringPrintf("/proc/%d/ns/mnt", pid);
@@ -798,11 +835,20 @@
     // Fork a child to mount Android/obb android Android/data dirs, as we don't want it to affect
     // original vold process mount namespace.
     if (!(child = fork())) {
-        if (remountStorageDirs(nsFd, android_data_dir, android_obb_dir, uid,
-                sources_cstr, targets_cstr, size)) {
-            _exit(0);
+        if (doUnmount) {
+            if (umountStorageDirs(nsFd, android_data_dir, android_obb_dir, uid,
+                    targets_cstr, size)) {
+                _exit(0);
+            } else {
+                _exit(1);
+            }
         } else {
-            _exit(1);
+            if (remountStorageDirs(nsFd, android_data_dir, android_obb_dir, uid,
+                    sources_cstr, targets_cstr, size)) {
+                _exit(0);
+            } else {
+                _exit(1);
+            }
         }
     }
 
@@ -827,8 +873,8 @@
     return true;
 }
 
-int VolumeManager::remountAppStorageDirs(int uid, int pid,
-        const std::vector<std::string>& packageNames) {
+int VolumeManager::handleAppStorageDirs(int uid, int pid,
+        bool doUnmount, const std::vector<std::string>& packageNames) {
     // Only run the remount if fuse is mounted for that user.
     userid_t userId = multiuser_get_user_id(uid);
     bool fuseMounted = false;
@@ -842,7 +888,7 @@
         }
     }
     if (fuseMounted) {
-        forkAndRemountStorage(uid, pid, packageNames);
+        forkAndRemountStorage(uid, pid, doUnmount, packageNames);
     }
     return 0;
 }
diff --git a/VolumeManager.h b/VolumeManager.h
index 9640303..3573b1a 100644
--- a/VolumeManager.h
+++ b/VolumeManager.h
@@ -115,7 +115,8 @@
     int onSecureKeyguardStateChanged(bool isShowing);
 
     int remountUid(uid_t uid, int32_t remountMode) { return 0; }
-    int remountAppStorageDirs(int uid, int pid, const std::vector<std::string>& packageNames);
+    int handleAppStorageDirs(int uid, int pid,
+            bool doUnmount, const std::vector<std::string>& packageNames);
 
     /* Aborts all FUSE filesystems, in case the FUSE daemon is no longer up. */
     int abortFuse();
@@ -129,7 +130,8 @@
     int updateVirtualDisk();
     int setDebug(bool enable);
 
-    bool forkAndRemountStorage(int uid, int pid, const std::vector<std::string>& packageNames);
+    bool forkAndRemountStorage(int uid, int pid, bool doUnmount,
+        const std::vector<std::string>& packageNames);
 
     static VolumeManager* Instance();
 
diff --git a/binder/android/os/IVold.aidl b/binder/android/os/IVold.aidl
index de381d3..19ce9ba 100644
--- a/binder/android/os/IVold.aidl
+++ b/binder/android/os/IVold.aidl
@@ -54,6 +54,7 @@
 
     void remountUid(int uid, int remountMode);
     void remountAppStorageDirs(int uid, int pid, in @utf8InCpp String[] packageNames);
+    void unmountAppStorageDirs(int uid, int pid, in @utf8InCpp String[] packageNames);
 
     void setupAppDir(@utf8InCpp String path, int appUid);
     void fixupAppDir(@utf8InCpp String path, int appUid);