Measure external storage using new GIDs.
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: 27948817, 34263266
Change-Id: Ife087df299ff8ee1a75fce1e39b4b737cf9375d5
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 9a984b4..914eaae 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -1028,7 +1028,7 @@
#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 @@
}
} 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 @@
}
} 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 @@
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 @@
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 @@
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 @@
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 @@
}
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 @@
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);