OSDN Git Service

Measure external storage using new GIDs.
authorJeff Sharkey <jsharkey@android.com>
Thu, 19 Jan 2017 16:21:36 +0000 (09:21 -0700)
committerJeff Sharkey <jsharkey@android.com>
Thu, 19 Jan 2017 16:24:10 +0000 (09:24 -0700)
We just defined a new range of GIDs that will be used to mark per-app
data files stored on external storage, so start measuring them.

Also measure all OBB files using another new GID that was defined.

Note that we're relying on the per-app cache GIDs to track cache
usage on *both* internal and external storage, which means that stats
and extStats won't always add up.  (The framework already combines
these values together, and we didn't want to waste precious GID
space on explicitly tracking cache files on external storage.)

Test: builds, boots
Bug: 2794881734263266
Change-Id: Ife087df299ff8ee1a75fce1e39b4b737cf9375d5

cmds/installd/InstalldNativeService.cpp
cmds/installd/utils.h

index 9a984b4..914eaae 100644 (file)
@@ -1028,7 +1028,7 @@ static std::string toString(std::vector<int64_t> values) {
 #endif
 
 static void collectQuotaStats(const std::string& device, int32_t userId,
-        int32_t appId, struct stats* stats, struct stats* extStats ATTRIBUTE_UNUSED) {
+        int32_t appId, struct stats* stats, struct stats* extStats) {
     if (device.empty()) return;
 
     struct dqblk dq;
@@ -1055,13 +1055,28 @@ static void collectQuotaStats(const std::string& device, int32_t userId,
             }
         } else {
 #if MEASURE_DEBUG
-        LOG(DEBUG) << "quotactl() for GID " << cacheGid << " " << dq.dqb_curspace;
+            LOG(DEBUG) << "quotactl() for GID " << cacheGid << " " << dq.dqb_curspace;
 #endif
             stats->cacheSize += dq.dqb_curspace;
         }
     }
 
-    int sharedGid = multiuser_get_shared_app_gid(uid);
+    int extGid = multiuser_get_ext_gid(userId, appId);
+    if (extGid != -1) {
+        if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), extGid,
+                reinterpret_cast<char*>(&dq)) != 0) {
+            if (errno != ESRCH) {
+                PLOG(ERROR) << "Failed to quotactl " << device << " for GID " << extGid;
+            }
+        } else {
+#if MEASURE_DEBUG
+            LOG(DEBUG) << "quotactl() for GID " << extGid << " " << dq.dqb_curspace;
+#endif
+            extStats->dataSize += dq.dqb_curspace;
+        }
+    }
+
+    int sharedGid = multiuser_get_shared_gid(userId, appId);
     if (sharedGid != -1) {
         if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), sharedGid,
                 reinterpret_cast<char*>(&dq)) != 0) {
@@ -1070,15 +1085,11 @@ static void collectQuotaStats(const std::string& device, int32_t userId,
             }
         } else {
 #if MEASURE_DEBUG
-        LOG(DEBUG) << "quotactl() for GID " << sharedGid << " " << dq.dqb_curspace;
+            LOG(DEBUG) << "quotactl() for GID " << sharedGid << " " << dq.dqb_curspace;
 #endif
             stats->codeSize += dq.dqb_curspace;
         }
     }
-
-#if MEASURE_EXTERNAL
-    // TODO: measure using external GIDs
-#endif
 }
 
 static void collectManualStats(const std::string& path, struct stats* stats) {
@@ -1164,6 +1175,40 @@ static void collectManualStatsForUser(const std::string& path, struct stats* sta
     closedir(d);
 }
 
+static void collectManualExternalStatsForUser(const std::string& path, struct stats* stats) {
+    FTS *fts;
+    FTSENT *p;
+    char *argv[] = { (char*) path.c_str(), nullptr };
+    if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_XDEV, NULL))) {
+        PLOG(ERROR) << "Failed to fts_open " << path;
+        return;
+    }
+    while ((p = fts_read(fts)) != NULL) {
+        switch (p->fts_info) {
+        case FTS_D:
+            if (p->fts_level == 4
+                    && !strcmp(p->fts_name, "cache")
+                    && !strcmp(p->fts_parent->fts_parent->fts_name, "data")
+                    && !strcmp(p->fts_parent->fts_parent->fts_parent->fts_name, "Android")) {
+                p->fts_number = 1;
+            }
+            p->fts_number = p->fts_parent->fts_number;
+            // Fall through to count the directory
+        case FTS_DEFAULT:
+        case FTS_F:
+        case FTS_SL:
+        case FTS_SLNONE:
+            int64_t size = (p->fts_statp->st_blocks * 512);
+            if (p->fts_number == 1) {
+                stats->cacheSize += size;
+            }
+            stats->dataSize += size;
+            break;
+        }
+    }
+    fts_close(fts);
+}
+
 binder::Status InstalldNativeService::getAppSize(const std::unique_ptr<std::string>& uuid,
         const std::vector<std::string>& packageNames, int32_t userId, int32_t flags,
         int32_t appId, const std::vector<int64_t>& ceDataInodes,
@@ -1250,14 +1295,12 @@ binder::Status InstalldNativeService::getAppSize(const std::unique_ptr<std::stri
             calculate_tree_size(refProfilePath, &stats.codeSize);
             ATRACE_END();
 
-#if MEASURE_EXTERNAL
             ATRACE_BEGIN("external");
             auto extPath = create_data_media_package_path(uuid_, userId, pkgname, "data");
             collectManualStats(extPath, &extStats);
             auto mediaPath = create_data_media_package_path(uuid_, userId, pkgname, "media");
             calculate_tree_size(mediaPath, &extStats.dataSize);
             ATRACE_END();
-#endif
         }
 
         ATRACE_BEGIN("dalvik");
@@ -1306,17 +1349,28 @@ binder::Status InstalldNativeService::getUserSize(const std::unique_ptr<std::str
 
     const char* uuid_ = uuid ? uuid->c_str() : nullptr;
 
-    ATRACE_BEGIN("obb");
-    auto obbPath = create_data_path(uuid_) + "/media/obb";
-    calculate_tree_size(obbPath, &extStats.codeSize);
-    ATRACE_END();
-
     auto device = findQuotaDeviceForUuid(uuid);
     if (device.empty()) {
         flags &= ~FLAG_USE_QUOTA;
     }
 
     if (flags & FLAG_USE_QUOTA) {
+        struct dqblk dq;
+
+        ATRACE_BEGIN("obb");
+        if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), AID_MEDIA_OBB,
+                reinterpret_cast<char*>(&dq)) != 0) {
+            if (errno != ESRCH) {
+                PLOG(ERROR) << "Failed to quotactl " << device << " for GID " << AID_MEDIA_OBB;
+            }
+        } else {
+#if MEASURE_DEBUG
+            LOG(DEBUG) << "quotactl() for GID " << AID_MEDIA_OBB << " " << dq.dqb_curspace;
+#endif
+            extStats.codeSize += dq.dqb_curspace;
+        }
+        ATRACE_END();
+
         ATRACE_BEGIN("code");
         calculate_tree_size(create_data_app_path(uuid_), &stats.codeSize, -1, -1, true);
         ATRACE_END();
@@ -1335,11 +1389,20 @@ binder::Status InstalldNativeService::getUserSize(const std::unique_ptr<std::str
         calculate_tree_size(refProfilePath, &stats.codeSize, -1, -1, true);
         ATRACE_END();
 
-#if MEASURE_EXTERNAL
         ATRACE_BEGIN("external");
-        // TODO: measure external storage paths
-        ATRACE_END();
+        uid_t uid = multiuser_get_uid(userId, AID_MEDIA_RW);
+        if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device.c_str(), uid,
+                reinterpret_cast<char*>(&dq)) != 0) {
+            if (errno != ESRCH) {
+                PLOG(ERROR) << "Failed to quotactl " << device << " for UID " << uid;
+            }
+        } else {
+#if MEASURE_DEBUG
+            LOG(DEBUG) << "quotactl() for UID " << uid << " " << dq.dqb_curspace;
 #endif
+            extStats.dataSize += dq.dqb_curspace;
+        }
+        ATRACE_END();
 
         ATRACE_BEGIN("dalvik");
         calculate_tree_size(create_data_dalvik_cache_path(), &stats.codeSize,
@@ -1360,6 +1423,11 @@ binder::Status InstalldNativeService::getUserSize(const std::unique_ptr<std::str
         }
         ATRACE_END();
     } else {
+        ATRACE_BEGIN("obb");
+        auto obbPath = create_data_path(uuid_) + "/media/obb";
+        calculate_tree_size(obbPath, &extStats.codeSize);
+        ATRACE_END();
+
         ATRACE_BEGIN("code");
         calculate_tree_size(create_data_app_path(uuid_), &stats.codeSize);
         ATRACE_END();
@@ -1378,11 +1446,14 @@ binder::Status InstalldNativeService::getUserSize(const std::unique_ptr<std::str
         calculate_tree_size(refProfilePath, &stats.codeSize);
         ATRACE_END();
 
-#if MEASURE_EXTERNAL
         ATRACE_BEGIN("external");
-        // TODO: measure external storage paths
-        ATRACE_END();
+        auto dataMediaPath = create_data_media_path(uuid_, userId);
+        collectManualExternalStatsForUser(dataMediaPath, &extStats);
+#if MEASURE_DEBUG
+        LOG(DEBUG) << "Measured external data " << extStats.dataSize << " cache "
+                << extStats.cacheSize;
 #endif
+        ATRACE_END();
 
         ATRACE_BEGIN("dalvik");
         calculate_tree_size(create_data_dalvik_cache_path(), &stats.codeSize);
index f2f0cbb..5e396c7 100644 (file)
@@ -31,7 +31,6 @@
 #include <installd_constants.h>
 
 #define MEASURE_DEBUG 0
-#define MEASURE_EXTERNAL 0
 
 namespace android {
 namespace installd {