Clear cached files on external storage.

When clearing cached files belonging to an app, include any cached
files on external storage.  Since we need to keep sdcardfs in the
loop about any file deletions, we always mutate by going through the
sdcardfs layer instead of behind its back.

Test: cts-tradefed run commandAndExit cts-dev -m CtsAppSecurityHostTestCases -t android.appsecurity.cts.StorageHostTest
Bug: 37486230, 37566983, 37913442, 37914374
Change-Id: If174bf7eaf682da83cf0ab1b4938fe9a5956d464
diff --git a/cmds/installd/CacheTracker.cpp b/cmds/installd/CacheTracker.cpp
index 4bfc834..e293948 100644
--- a/cmds/installd/CacheTracker.cpp
+++ b/cmds/installd/CacheTracker.cpp
@@ -51,22 +51,12 @@
 }
 
 void CacheTracker::loadStats() {
-    int cacheGid = multiuser_get_cache_gid(mUserId, mAppId);
-    if (cacheGid != -1 && !mQuotaDevice.empty()) {
-        ATRACE_BEGIN("loadStats quota");
-        struct dqblk dq;
-        if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), mQuotaDevice.c_str(), cacheGid,
-                reinterpret_cast<char*>(&dq)) != 0) {
-            ATRACE_END();
-            if (errno != ESRCH) {
-                PLOG(ERROR) << "Failed to quotactl " << mQuotaDevice << " for GID " << cacheGid;
-            }
-        } else {
-            cacheUsed = dq.dqb_curspace;
-            ATRACE_END();
-            return;
-        }
+    ATRACE_BEGIN("loadStats quota");
+    cacheUsed = 0;
+    if (loadQuotaStats()) {
+        return;
     }
+    ATRACE_END();
 
     ATRACE_BEGIN("loadStats tree");
     cacheUsed = 0;
@@ -79,6 +69,36 @@
     ATRACE_END();
 }
 
+bool CacheTracker::loadQuotaStats() {
+    int cacheGid = multiuser_get_cache_gid(mUserId, mAppId);
+    int extCacheGid = multiuser_get_ext_cache_gid(mUserId, mAppId);
+    if (!mQuotaDevice.empty() && cacheGid != -1 && extCacheGid != -1) {
+        struct dqblk dq;
+        if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), mQuotaDevice.c_str(), cacheGid,
+                reinterpret_cast<char*>(&dq)) != 0) {
+            if (errno != ESRCH) {
+                PLOG(ERROR) << "Failed to quotactl " << mQuotaDevice << " for GID " << cacheGid;
+            }
+            return false;
+        } else {
+            cacheUsed += dq.dqb_curspace;
+        }
+
+        if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), mQuotaDevice.c_str(), extCacheGid,
+                reinterpret_cast<char*>(&dq)) != 0) {
+            if (errno != ESRCH) {
+                PLOG(ERROR) << "Failed to quotactl " << mQuotaDevice << " for GID " << cacheGid;
+            }
+            return false;
+        } else {
+            cacheUsed += dq.dqb_curspace;
+        }
+        return true;
+    } else {
+        return false;
+    }
+}
+
 void CacheTracker::loadItemsFrom(const std::string& path) {
     FTS *fts;
     FTSENT *p;