Merge "Clear cached files on external storage." into oc-dev am: 4b567487b7
am: da58bf4b22

Change-Id: Iac74be908685c9d16c39a3178312eef091c7946c
diff --git a/cmds/installd/CacheItem.cpp b/cmds/installd/CacheItem.cpp
index 17eb7ff..515f915 100644
--- a/cmds/installd/CacheItem.cpp
+++ b/cmds/installd/CacheItem.cpp
@@ -67,6 +67,7 @@
 }
 
 int CacheItem::purge() {
+    int res = 0;
     auto path = buildPath();
     if (directory) {
         FTS *fts;
@@ -88,29 +89,47 @@
                 break;
             case FTS_F:
                 if (p->fts_parent->fts_number) {
-                    truncate(p->fts_path, 0);
+                    if (truncate(p->fts_path, 0) != 0) {
+                        PLOG(WARNING) << "Failed to truncate " << p->fts_path;
+                        res = -1;
+                    }
                 } else {
-                    unlink(p->fts_path);
+                    if (unlink(p->fts_path) != 0) {
+                        PLOG(WARNING) << "Failed to unlink " << p->fts_path;
+                        res = -1;
+                    }
                 }
                 break;
             case FTS_DEFAULT:
             case FTS_SL:
             case FTS_SLNONE:
-                unlink(p->fts_path);
+                if (unlink(p->fts_path) != 0) {
+                    PLOG(WARNING) << "Failed to unlink " << p->fts_path;
+                    res = -1;
+                }
                 break;
             case FTS_DP:
-                rmdir(p->fts_path);
+                if (rmdir(p->fts_path) != 0) {
+                    PLOG(WARNING) << "Failed to rmdir " << p->fts_path;
+                    res = -1;
+                }
                 break;
             }
         }
-        return 0;
     } else {
         if (tombstone) {
-            return truncate(path.c_str(), 0);
+            if (truncate(path.c_str(), 0) != 0) {
+                PLOG(WARNING) << "Failed to truncate " << path;
+                res = -1;
+            }
         } else {
-            return unlink(path.c_str());
+            if (unlink(path.c_str()) != 0) {
+                PLOG(WARNING) << "Failed to unlink " << path;
+                res = -1;
+            }
         }
     }
+    return res;
 }
 
 }  // namespace installd
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;
diff --git a/cmds/installd/CacheTracker.h b/cmds/installd/CacheTracker.h
index 91692d7..44359b4 100644
--- a/cmds/installd/CacheTracker.h
+++ b/cmds/installd/CacheTracker.h
@@ -66,6 +66,7 @@
 
     std::vector<std::string> mDataPaths;
 
+    bool loadQuotaStats();
     void loadItemsFrom(const std::string& path);
 
     DISALLOW_COPY_AND_ASSIGN(CacheTracker);
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 49a3b23..19dfb87 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -205,15 +205,20 @@
     out << "installd is happy!" << endl;
 
     {
-        std::lock_guard<std::recursive_mutex> lock(mQuotaDevicesLock);
-        out << endl << "Devices with quota support:" << endl;
-        for (const auto& n : mQuotaDevices) {
+        std::lock_guard<std::recursive_mutex> lock(mMountsLock);
+        out << endl << "Storage mounts:" << endl;
+        for (const auto& n : mStorageMounts) {
+            out << "    " << n.first << " = " << n.second << endl;
+        }
+
+        out << endl << "Quota reverse mounts:" << endl;
+        for (const auto& n : mQuotaReverseMounts) {
             out << "    " << n.first << " = " << n.second << endl;
         }
     }
 
     {
-        std::lock_guard<std::recursive_mutex> lock(mCacheQuotasLock);
+        std::lock_guard<std::recursive_mutex> lock(mQuotasLock);
         out << endl << "Per-UID cache quotas:" << endl;
         for (const auto& n : mCacheQuotas) {
             out << "    " << n.first << " = " << n.second << endl;
@@ -901,7 +906,7 @@
         if (delete_dir_contents_and_dir(path, true) != 0) {
             res = error("Failed to delete " + path);
         }
-        path = create_data_media_path(uuid_, userId);
+        path = findDataMediaPath(uuid, userId);
         if (delete_dir_contents_and_dir(path, true) != 0) {
             res = error("Failed to delete " + path);
         }
@@ -952,13 +957,19 @@
             FTSENT *p;
             auto ce_path = create_data_user_ce_path(uuid_, user);
             auto de_path = create_data_user_de_path(uuid_, user);
-            char *argv[] = { (char*) ce_path.c_str(), (char*) de_path.c_str(), nullptr };
+            auto media_path = findDataMediaPath(uuid, user) + "/Android/data/";
+            char *argv[] = { (char*) ce_path.c_str(), (char*) de_path.c_str(),
+                    (char*) media_path.c_str(), nullptr };
             if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL))) {
                 return error("Failed to fts_open");
             }
             while ((p = fts_read(fts)) != NULL) {
                 if (p->fts_info == FTS_D && p->fts_level == 1) {
                     uid_t uid = p->fts_statp->st_uid;
+                    if (multiuser_get_app_id(uid) == AID_MEDIA_RW) {
+                        uid = (multiuser_get_app_id(p->fts_statp->st_gid) - AID_EXT_GID_START)
+                                + AID_APP_START;
+                    }
                     auto search = trackers.find(uid);
                     if (search != trackers.end()) {
                         search->second->addDataPath(p->fts_path);
@@ -967,7 +978,7 @@
                                 multiuser_get_user_id(uid), multiuser_get_app_id(uid), device));
                         tracker->addDataPath(p->fts_path);
                         {
-                            std::lock_guard<std::recursive_mutex> lock(mCacheQuotasLock);
+                            std::lock_guard<std::recursive_mutex> lock(mQuotasLock);
                             tracker->cacheQuota = mCacheQuotas[uid];
                         }
                         if (tracker->cacheQuota == 0) {
@@ -1745,7 +1756,7 @@
         int32_t userId, int32_t appId, int64_t cacheQuota) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_UUID(uuid);
-    std::lock_guard<std::recursive_mutex> lock(mCacheQuotasLock);
+    std::lock_guard<std::recursive_mutex> lock(mQuotasLock);
 
     int32_t uid = multiuser_get_uid(userId, appId);
     mCacheQuotas[uid] = cacheQuota;
@@ -2219,9 +2230,10 @@
 
 binder::Status InstalldNativeService::invalidateMounts() {
     ENFORCE_UID(AID_SYSTEM);
-    std::lock_guard<std::recursive_mutex> lock(mQuotaDevicesLock);
+    std::lock_guard<std::recursive_mutex> lock(mMountsLock);
 
-    mQuotaDevices.clear();
+    mStorageMounts.clear();
+    mQuotaReverseMounts.clear();
 
     std::ifstream in("/proc/mounts");
     if (!in.is_open()) {
@@ -2231,17 +2243,25 @@
     std::string source;
     std::string target;
     std::string ignored;
-    struct dqblk dq;
     while (!in.eof()) {
         std::getline(in, source, ' ');
         std::getline(in, target, ' ');
         std::getline(in, ignored);
 
+#if !BYPASS_SDCARDFS
+        if (target.compare(0, 21, "/mnt/runtime/default/") == 0) {
+            LOG(DEBUG) << "Found storage mount " << source << " at " << target;
+            mStorageMounts[source] = target;
+        }
+#endif
+
+#if !BYPASS_QUOTA
         if (source.compare(0, 11, "/dev/block/") == 0) {
+            struct dqblk dq;
             if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), source.c_str(), 0,
                     reinterpret_cast<char*>(&dq)) == 0) {
-                LOG(DEBUG) << "Found " << source << " with quota";
-                mQuotaDevices[target] = source;
+                LOG(DEBUG) << "Found quota mount " << source << " at " << target;
+                mQuotaReverseMounts[target] = source;
 
                 // ext4 only enables DQUOT_USAGE_ENABLED by default, so we
                 // need to kick it again to enable DQUOT_LIMITS_ENABLED.
@@ -2255,15 +2275,29 @@
                 }
             }
         }
+#endif
     }
     return ok();
 }
 
+std::string InstalldNativeService::findDataMediaPath(
+        const std::unique_ptr<std::string>& uuid, userid_t userid) {
+    std::lock_guard<std::recursive_mutex> lock(mMountsLock);
+    const char* uuid_ = uuid ? uuid->c_str() : nullptr;
+    auto path = StringPrintf("%s/media", create_data_path(uuid_).c_str());
+    auto resolved = mStorageMounts[path];
+    if (resolved.empty()) {
+        LOG(WARNING) << "Failed to find storage mount for " << path;
+        resolved = path;
+    }
+    return StringPrintf("%s/%u", resolved.c_str(), userid);
+}
+
 std::string InstalldNativeService::findQuotaDeviceForUuid(
         const std::unique_ptr<std::string>& uuid) {
-    std::lock_guard<std::recursive_mutex> lock(mQuotaDevicesLock);
+    std::lock_guard<std::recursive_mutex> lock(mMountsLock);
     auto path = create_data_path(uuid ? uuid->c_str() : nullptr);
-    return mQuotaDevices[path];
+    return mQuotaReverseMounts[path];
 }
 
 binder::Status InstalldNativeService::isQuotaSupported(
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index 7f73c2a..200fc77 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -121,14 +121,18 @@
 private:
     std::recursive_mutex mLock;
 
-    std::recursive_mutex mQuotaDevicesLock;
-    std::recursive_mutex mCacheQuotasLock;
+    std::recursive_mutex mMountsLock;
+    std::recursive_mutex mQuotasLock;
 
-    /* Map from mount point to underlying device node */
-    std::unordered_map<std::string, std::string> mQuotaDevices;
+    /* Map of all storage mounts from source to target */
+    std::unordered_map<std::string, std::string> mStorageMounts;
+    /* Map of all quota mounts from target to source */
+    std::unordered_map<std::string, std::string> mQuotaReverseMounts;
+
     /* Map from UID to cache quota size */
     std::unordered_map<uid_t, int64_t> mCacheQuotas;
 
+    std::string findDataMediaPath(const std::unique_ptr<std::string>& uuid, userid_t userid);
     std::string findQuotaDeviceForUuid(const std::unique_ptr<std::string>& uuid);
 };
 
diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h
index dd94da9..070da84 100644
--- a/cmds/installd/utils.h
+++ b/cmds/installd/utils.h
@@ -33,6 +33,9 @@
 #define MEASURE_DEBUG 0
 #define FIXUP_DEBUG 0
 
+#define BYPASS_QUOTA 0
+#define BYPASS_SDCARDFS 0
+
 namespace android {
 namespace installd {