Setup Android/, Android/data and Android/obb dirs correctly.

Normally sdcardfs takes care of setting up these directories on-demand,
for example when an app requests its private data directory to be
created. On devices without sdcardfs however, we ourselves need to make
sure to setup the UID/GID of these directories correctly.

Introduce a new PrepareAndroidDirs() function which sets the dirs up
correctly. On devices without sdcardfs, that means:

Path              UID         GID         mode
/Android          media_rw    media_rw     771
/Android/data     media_rw    ext_data_rw  771
/Android/obb      media_rw    ext_obb_rw   771

Bug: 146419093
Test: wipe Android/, reboot, with and without sdcardfs, verify
      contents

Change-Id: I3a879089422c7fc449b6a3e6f1c4b386b86687a4
diff --git a/VolumeManager.cpp b/VolumeManager.cpp
index 3de89ab..e6d593a 100644
--- a/VolumeManager.cpp
+++ b/VolumeManager.cpp
@@ -81,7 +81,9 @@
 using android::vold::CreateDir;
 using android::vold::DeleteDirContents;
 using android::vold::DeleteDirContentsAndDir;
-using android::vold::PrepareDirsFromRoot;
+using android::vold::IsFilesystemSupported;
+using android::vold::PrepareAndroidDirs;
+using android::vold::PrepareAppDirsFromRoot;
 using android::vold::PrivateVolume;
 using android::vold::Symlink;
 using android::vold::Unlink;
@@ -822,6 +824,29 @@
     return 0;
 }
 
+static gid_t getAppDirGid(const std::string& appDir) {
+    // Create app-specific dirs with the correct UID/GID
+    gid_t gid = AID_MEDIA_RW;
+    if (!IsFilesystemSupported("sdcardfs")) {
+        if (appDir == android::vold::kAppDataDir) {
+            gid = AID_EXT_DATA_RW;
+        } else if (appDir == android::vold::kAppObbDir) {
+            gid = AID_EXT_OBB_RW;
+        } else if (appDir == android::vold::kAppMediaDir) {
+            gid = AID_MEDIA_RW;
+        } else {
+            gid = AID_MEDIA_RW;
+        }
+    }
+
+    return gid;
+}
+
+static bool isValidAppDirRoot(const std::string& appDirRoot) {
+    return appDirRoot == android::vold::kAppDataDir || appDirRoot == android::vold::kAppMediaDir ||
+           appDirRoot == android::vold::kAppObbDir;
+}
+
 int VolumeManager::setupAppDir(const std::string& path, const std::string& appDirRoot,
                                int32_t appUid) {
     // Only offer to create directories for paths managed by vold
@@ -868,14 +893,25 @@
     const std::string lowerAppDirRoot =
             volume->getInternalPath() + appDirRoot.substr(volume->getPath().length());
 
-    // First create the root which holds app dirs, if needed.
-    int ret = PrepareDirsFromRoot(lowerAppDirRoot, volume->getInternalPath(), 0771, AID_MEDIA_RW,
-                                  AID_MEDIA_RW);
+    // Do some sanity checking on the app dir (relative from root)
+    const std::string volumeRoot = volume->getRootPath();  // eg /data/media/0
+
+    // eg, if lowerAppDirRoot = /data/media/0/Android/data, this is /Android/data
+    const std::string relativeAppRoot = lowerAppDirRoot.substr(volumeRoot.length());
+    if (!isValidAppDirRoot(relativeAppRoot)) {
+        LOG(ERROR) << path << " is not a valid application directory.";
+        return -EINVAL;
+    }
+
+    // Make sure the Android/ directories exist and are setup correctly
+    int ret = PrepareAndroidDirs(volumeRoot);
     if (ret != 0) {
+        LOG(ERROR) << "Failed to prepare Android/ directories.";
         return ret;
     }
-    // Then, create app-specific dirs with the correct UID/GID
-    return PrepareDirsFromRoot(lowerPath, lowerAppDirRoot, 0770, appUid, AID_MEDIA_RW);
+
+    gid_t gid = getAppDirGid(relativeAppRoot);
+    return PrepareAppDirsFromRoot(lowerPath, lowerAppDirRoot, 0770, appUid, gid);
 }
 
 int VolumeManager::createObb(const std::string& sourcePath, const std::string& sourceKey,