Set correct quota project ID on application directories.

Use PrepareAppDirsFromRoot() to setup the quota project ID on
application-specific directories correctly. App directories use
AID_EXT_GID_START + their application ID offset, whereas cache
directories use AID_CACHE_GID_START. This is consistent with the GIDs
sdcardfs used to label these directories with.

Bug: 146419093
Test: verified project IDs with lsattr -p
Change-Id: Idca8a30d185012efb0d19ceb9b346b9a4de34f18
diff --git a/Utils.cpp b/Utils.cpp
index be4d293..dc1c593 100644
--- a/Utils.cpp
+++ b/Utils.cpp
@@ -54,6 +54,7 @@
 #endif
 
 using namespace std::chrono_literals;
+using android::base::EndsWith;
 using android::base::ReadFileToString;
 using android::base::StartsWith;
 using android::base::StringPrintf;
@@ -136,9 +137,13 @@
 
 int PrepareAppDirsFromRoot(std::string path, std::string root, mode_t mode, uid_t uid, gid_t gid) {
     int ret = 0;
+    bool isCacheDir = false;
     if (!StartsWith(path, root)) {
         return -1;
     }
+    // Cache directories (eg "/storage/emulated/Android/data/com.foo/cache/") need special treatment
+    isCacheDir = EndsWith(root, "/Android/data/") && EndsWith(path, "cache/");
+
     std::string to_create_from_root = path.substr(root.length());
 
     size_t pos = 0;
@@ -150,6 +155,21 @@
         if (ret) {
             break;
         }
+        if (!IsFilesystemSupported("sdcardfs")) {
+            long projectId;
+            // All app-specific directories share the same project-ID, except
+            // the cache directory
+            if (isCacheDir && component == "cache") {
+                // Note that this also matches paths like:
+                // /Android/data/com.foo/bar/cache/
+                // This is currently safe because we're never asked to create
+                // such directories.
+                projectId = uid - AID_APP_START + AID_CACHE_GID_START;
+            } else {
+                projectId = uid - AID_APP_START + AID_EXT_GID_START;
+            }
+            ret = SetQuotaProjectId(root, projectId);
+        }
     }
 
     return ret;