summaryrefslogtreecommitdiff
path: root/cmds/installd/InstalldNativeService.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'cmds/installd/InstalldNativeService.cpp')
-rw-r--r--cmds/installd/InstalldNativeService.cpp443
1 files changed, 362 insertions, 81 deletions
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index ed5fc4aaee..72efd55912 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -53,12 +53,12 @@
#include "otapreopt_utils.h"
#include "utils.h"
+#include "MatchExtensionGen.h"
+
#ifndef LOG_TAG
#define LOG_TAG "installd"
#endif
-#define MEASURE_EXTERNAL 0
-
using android::base::StringPrintf;
namespace android {
@@ -756,7 +756,7 @@ binder::Status InstalldNativeService::destroyUserData(const std::unique_ptr<std:
if (delete_dir_contents_and_dir(path, true) != 0) {
res = error("Failed to delete " + path);
}
- path = create_data_user_profiles_path(userId);
+ path = create_data_user_profile_path(userId);
if (delete_dir_contents_and_dir(path, true) != 0) {
res = error("Failed to delete " + path);
}
@@ -849,54 +849,54 @@ binder::Status InstalldNativeService::rmdex(const std::string& codePath,
}
}
-static bool uuidEquals(const std::unique_ptr<std::string>& a,
- const std::unique_ptr<std::string>& b) {
- if (!a && !b) {
- return true;
- } else if (!a && b) {
- return false;
- } else if (a && !b) {
- return false;
- } else {
- return *a == *b;
- }
-}
-
struct stats {
int64_t codeSize;
int64_t dataSize;
int64_t cacheSize;
};
-static void collectQuotaStats(const std::unique_ptr<std::string>& uuid, int32_t userId,
- int32_t appId, struct stats* stats) {
- struct dqblk dq;
+#if MEASURE_DEBUG
+static std::string toString(std::vector<int64_t> values) {
+ std::stringstream res;
+ res << "[";
+ for (size_t i = 0; i < values.size(); i++) {
+ res << values[i];
+ if (i < values.size() - 1) {
+ res << ",";
+ }
+ }
+ res << "]";
+ return res.str();
+}
+#endif
+static std::string findDeviceForUuid(const std::unique_ptr<std::string>& uuid) {
auto path = create_data_path(uuid ? uuid->c_str() : nullptr);
- std::string device;
- {
- std::ifstream in("/proc/mounts");
- if (!in.is_open()) {
- PLOG(ERROR) << "Failed to read mounts";
- return;
- }
- std::string source;
- std::string target;
- while (!in.eof()) {
- std::getline(in, source, ' ');
- std::getline(in, target, ' ');
- if (target == path) {
- device = source;
- break;
- }
- // Skip to next line
- std::getline(in, source);
+ std::ifstream in("/proc/mounts");
+ if (!in.is_open()) {
+ PLOG(ERROR) << "Failed to read mounts";
+ return "";
+ }
+ std::string source;
+ std::string target;
+ while (!in.eof()) {
+ std::getline(in, source, ' ');
+ std::getline(in, target, ' ');
+ if (target == path) {
+ return source;
}
+ // Skip to next line
+ std::getline(in, source);
}
- if (device.empty()) {
- PLOG(ERROR) << "Failed to resolve block device for " << path;
- return;
- }
+ PLOG(ERROR) << "Failed to resolve block device for " << path;
+ return "";
+}
+
+static void collectQuotaStats(const std::string& device, int32_t userId,
+ int32_t appId, struct stats* stats, struct stats* extStats ATTRIBUTE_UNUSED) {
+ if (device.empty()) return;
+
+ struct dqblk dq;
uid_t uid = multiuser_get_uid(userId, appId);
if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device.c_str(), uid,
@@ -905,6 +905,9 @@ static void collectQuotaStats(const std::unique_ptr<std::string>& uuid, int32_t
PLOG(ERROR) << "Failed to quotactl " << device << " for UID " << uid;
}
} else {
+#if MEASURE_DEBUG
+ LOG(DEBUG) << "quotactl() for UID " << uid << " " << dq.dqb_curspace;
+#endif
stats->dataSize += dq.dqb_curspace;
}
@@ -916,6 +919,9 @@ static void collectQuotaStats(const std::unique_ptr<std::string>& uuid, int32_t
PLOG(ERROR) << "Failed to quotactl " << device << " for GID " << cacheGid;
}
} else {
+#if MEASURE_DEBUG
+ LOG(DEBUG) << "quotactl() for GID " << cacheGid << " " << dq.dqb_curspace;
+#endif
stats->cacheSize += dq.dqb_curspace;
}
}
@@ -928,12 +934,24 @@ static void collectQuotaStats(const std::unique_ptr<std::string>& uuid, int32_t
PLOG(ERROR) << "Failed to quotactl " << device << " for GID " << sharedGid;
}
} else {
+#if MEASURE_DEBUG
+ 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(std::string& path, struct stats* stats) {
+static void collectQuotaStats(const std::unique_ptr<std::string>& uuid, int32_t userId,
+ int32_t appId, struct stats* stats, struct stats* extStats) {
+ collectQuotaStats(findDeviceForUuid(uuid), userId, appId, stats, extStats);
+}
+
+static void collectManualStats(const std::string& path, struct stats* stats) {
DIR *d;
int dfd;
struct dirent *de;
@@ -983,80 +1001,343 @@ static void collectManualStats(std::string& path, struct stats* stats) {
closedir(d);
}
+static void collectManualStatsForUser(const std::string& path, struct stats* stats,
+ bool exclude_apps = false) {
+ DIR *d;
+ int dfd;
+ struct dirent *de;
+ struct stat s;
+
+ d = opendir(path.c_str());
+ if (d == nullptr) {
+ if (errno != ENOENT) {
+ PLOG(WARNING) << "Failed to open " << path;
+ }
+ return;
+ }
+ dfd = dirfd(d);
+ while ((de = readdir(d))) {
+ if (de->d_type == DT_DIR) {
+ const char *name = de->d_name;
+ if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) != 0) {
+ continue;
+ }
+ if (!strcmp(name, ".") || !strcmp(name, "..")) {
+ continue;
+ } else if (exclude_apps && (s.st_uid >= AID_APP_START && s.st_uid <= AID_APP_END)) {
+ continue;
+ } else {
+ collectManualStats(StringPrintf("%s/%s", path.c_str(), name), stats);
+ }
+ }
+ }
+ closedir(d);
+}
+
binder::Status InstalldNativeService::getAppSize(const std::unique_ptr<std::string>& uuid,
- const std::string& packageName, int32_t userId, int32_t flags, int32_t appId,
- int64_t ceDataInode, const std::string& codePath,
- const std::unique_ptr<std::string>& externalUuid, std::vector<int64_t>* _aidl_return) {
+ const std::vector<std::string>& packageNames, int32_t userId, int32_t flags,
+ int32_t appId, const std::vector<int64_t>& ceDataInodes,
+ const std::vector<std::string>& codePaths, std::vector<int64_t>* _aidl_return) {
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_UUID(uuid);
- CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+ for (auto packageName : packageNames) {
+ CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+ }
- const char* uuid_ = uuid ? uuid->c_str() : nullptr;
- const char* extuuid_ = externalUuid ? externalUuid->c_str() : nullptr;
- const char* pkgname = packageName.c_str();
+ // When modifying this logic, always verify using tests:
+ // runtest -x frameworks/base/services/tests/servicestests/src/com/android/server/pm/InstallerTest.java -m testGetAppSize
+
+#if MEASURE_DEBUG
+ LOG(INFO) << "Measuring user " << userId << " app " << appId;
+#endif
// Here's a summary of the common storage locations across the platform,
// and how they're each tagged:
//
// /data/app/com.example UID system
// /data/app/com.example/oat UID system
- // /data/user/0/com.example UID u0_a10 GID u0_a10
- // /data/user/0/com.example/cache UID u0_a10 GID u0_a10_cache
- // /data/media/0/Android/data/com.example UID u0_a10 GID u0_a10
- // /data/media/0/Android/data/com.example/cache UID u0_a10 GID u0_a10_cache
- // /data/media/0/Android/obb/com.example UID system
+ // /data/user/0/com.example UID u0_a10 GID u0_a10
+ // /data/user/0/com.example/cache UID u0_a10 GID u0_a10_cache
+ // /data/media/0/foo.txt UID u0_media_rw
+ // /data/media/0/bar.jpg UID u0_media_rw GID u0_media_image
+ // /data/media/0/Android/data/com.example UID u0_media_rw GID u0_a10_ext
+ // /data/media/0/Android/data/com.example/cache UID u0_media_rw GID u0_a10_ext_cache
+ // /data/media/obb/com.example UID system
struct stats stats;
+ struct stats extStats;
memset(&stats, 0, sizeof(stats));
+ memset(&extStats, 0, sizeof(extStats));
- auto obbCodePath = create_data_media_package_path(extuuid_, userId, pkgname, "obb");
- calculate_tree_size(obbCodePath, &stats.codeSize);
-
- if (flags & FLAG_USE_QUOTA) {
- calculate_tree_size(codePath, &stats.codeSize,
- 0, multiuser_get_shared_gid(userId, appId));
+ const char* uuid_ = uuid ? uuid->c_str() : nullptr;
- collectQuotaStats(uuid, userId, appId, &stats);
+ for (auto packageName : packageNames) {
+ auto obbCodePath = create_data_media_obb_path(uuid_, packageName.c_str());
+ calculate_tree_size(obbCodePath, &extStats.codeSize);
+ }
- // If external storage lives on a different storage device, also
- // collect quota stats from that block device
- if (!uuidEquals(uuid, externalUuid)) {
- collectQuotaStats(externalUuid, userId, appId, &stats);
+ if (flags & FLAG_USE_QUOTA && appId >= AID_APP_START) {
+ for (auto codePath : codePaths) {
+ calculate_tree_size(codePath, &stats.codeSize, -1,
+ multiuser_get_shared_gid(userId, appId));
}
+
+ collectQuotaStats(uuid, userId, appId, &stats, &extStats);
+
} else {
- calculate_tree_size(codePath, &stats.codeSize);
+ for (auto codePath : codePaths) {
+ calculate_tree_size(codePath, &stats.codeSize);
+ }
- auto cePath = create_data_user_ce_package_path(uuid_, userId, pkgname, ceDataInode);
- collectManualStats(cePath, &stats);
+ for (size_t i = 0; i < packageNames.size(); i++) {
+ const char* pkgname = packageNames[i].c_str();
- auto dePath = create_data_user_de_package_path(uuid_, userId, pkgname);
- collectManualStats(dePath, &stats);
+ auto cePath = create_data_user_ce_package_path(uuid_, userId, pkgname, ceDataInodes[i]);
+ collectManualStats(cePath, &stats);
- auto userProfilePath = create_data_user_profile_package_path(userId, pkgname);
- calculate_tree_size(userProfilePath, &stats.dataSize);
+ auto dePath = create_data_user_de_package_path(uuid_, userId, pkgname);
+ collectManualStats(dePath, &stats);
- auto refProfilePath = create_data_ref_profile_package_path(pkgname);
- calculate_tree_size(refProfilePath, &stats.codeSize);
+ auto userProfilePath = create_data_user_profile_package_path(userId, pkgname);
+ calculate_tree_size(userProfilePath, &stats.dataSize);
- calculate_tree_size(create_data_dalvik_cache_path(), &stats.codeSize,
- multiuser_get_shared_gid(userId, appId), 0);
+ auto refProfilePath = create_data_ref_profile_package_path(pkgname);
+ calculate_tree_size(refProfilePath, &stats.codeSize);
+
+#if MEASURE_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);
+#endif
+ }
+
+ int32_t sharedGid = multiuser_get_shared_gid(userId, appId);
+ if (sharedGid != -1) {
+ calculate_tree_size(create_data_dalvik_cache_path(), &stats.codeSize,
+ sharedGid, -1);
+ }
calculate_tree_size(create_data_misc_foreign_dex_path(userId), &stats.dataSize,
- multiuser_get_uid(userId, appId), 0);
+ multiuser_get_uid(userId, appId), -1);
+ }
+
+ std::vector<int64_t> ret;
+ ret.push_back(stats.codeSize);
+ ret.push_back(stats.dataSize);
+ ret.push_back(stats.cacheSize);
+ ret.push_back(extStats.codeSize);
+ ret.push_back(extStats.dataSize);
+ ret.push_back(extStats.cacheSize);
+#if MEASURE_DEBUG
+ LOG(DEBUG) << "Final result " << toString(ret);
+#endif
+ *_aidl_return = ret;
+ return ok();
+}
+
+binder::Status InstalldNativeService::getUserSize(const std::unique_ptr<std::string>& uuid,
+ int32_t userId, int32_t flags, const std::vector<int32_t>& appIds,
+ std::vector<int64_t>* _aidl_return) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_UUID(uuid);
+
+ // When modifying this logic, always verify using tests:
+ // runtest -x frameworks/base/services/tests/servicestests/src/com/android/server/pm/InstallerTest.java -m testGetUserSize
+
+#if MEASURE_DEBUG
+ LOG(INFO) << "Measuring user " << userId;
+#endif
+
+ struct stats stats;
+ struct stats extStats;
+ memset(&stats, 0, sizeof(stats));
+ memset(&extStats, 0, sizeof(extStats));
+
+ const char* uuid_ = uuid ? uuid->c_str() : nullptr;
+
+ auto obbPath = create_data_path(uuid_) + "/media/obb";
+ calculate_tree_size(obbPath, &extStats.codeSize);
+
+ if (flags & FLAG_USE_QUOTA) {
+ calculate_tree_size(create_data_app_path(uuid_), &stats.codeSize, -1, -1, true);
+
+ auto cePath = create_data_user_ce_path(uuid_, userId);
+ collectManualStatsForUser(cePath, &stats, true);
+
+ auto dePath = create_data_user_de_path(uuid_, userId);
+ collectManualStatsForUser(dePath, &stats, true);
+
+ auto userProfilePath = create_data_user_profile_path(userId);
+ calculate_tree_size(userProfilePath, &stats.dataSize, -1, -1, true);
+
+ auto refProfilePath = create_data_ref_profile_path();
+ calculate_tree_size(refProfilePath, &stats.codeSize, -1, -1, true);
#if MEASURE_EXTERNAL
- auto extPath = create_data_media_package_path(extuuid_, userId, pkgname, "data");
- collectManualStats(extPath, &stats);
+ // TODO: measure external storage paths
+#endif
- auto mediaPath = create_data_media_package_path(extuuid_, userId, pkgname, "media");
- calculate_tree_size(mediaPath, &stats.dataSize);
+ calculate_tree_size(create_data_dalvik_cache_path(), &stats.codeSize,
+ -1, -1, true);
+
+ calculate_tree_size(create_data_misc_foreign_dex_path(userId), &stats.dataSize,
+ -1, -1, true);
+
+ auto device = findDeviceForUuid(uuid);
+ for (auto appId : appIds) {
+ if (appId >= AID_APP_START) {
+ collectQuotaStats(device, userId, appId, &stats, &extStats);
+#if MEASURE_DEBUG
+ // Sleep to make sure we don't lose logs
+ usleep(1);
#endif
+ }
+ }
+ } else {
+ calculate_tree_size(create_data_app_path(uuid_), &stats.codeSize);
+
+ auto cePath = create_data_user_ce_path(uuid_, userId);
+ collectManualStatsForUser(cePath, &stats);
+
+ auto dePath = create_data_user_de_path(uuid_, userId);
+ collectManualStatsForUser(dePath, &stats);
+
+ auto userProfilePath = create_data_user_profile_path(userId);
+ calculate_tree_size(userProfilePath, &stats.dataSize);
+
+ auto refProfilePath = create_data_ref_profile_path();
+ calculate_tree_size(refProfilePath, &stats.codeSize);
+
+#if MEASURE_EXTERNAL
+ // TODO: measure external storage paths
+#endif
+
+ calculate_tree_size(create_data_dalvik_cache_path(), &stats.codeSize);
+
+ calculate_tree_size(create_data_misc_foreign_dex_path(userId), &stats.dataSize);
}
std::vector<int64_t> ret;
ret.push_back(stats.codeSize);
ret.push_back(stats.dataSize);
ret.push_back(stats.cacheSize);
+ ret.push_back(extStats.codeSize);
+ ret.push_back(extStats.dataSize);
+ ret.push_back(extStats.cacheSize);
+#if MEASURE_DEBUG
+ LOG(DEBUG) << "Final result " << toString(ret);
+#endif
+ *_aidl_return = ret;
+ return ok();
+}
+
+binder::Status InstalldNativeService::getExternalSize(const std::unique_ptr<std::string>& uuid,
+ int32_t userId, int32_t flags, std::vector<int64_t>* _aidl_return) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_UUID(uuid);
+
+ // When modifying this logic, always verify using tests:
+ // runtest -x frameworks/base/services/tests/servicestests/src/com/android/server/pm/InstallerTest.java -m testGetExternalSize
+
+#if MEASURE_DEBUG
+ LOG(INFO) << "Measuring external " << userId;
+#endif
+
+ const char* uuid_ = uuid ? uuid->c_str() : nullptr;
+
+ int64_t totalSize = 0;
+ int64_t audioSize = 0;
+ int64_t videoSize = 0;
+ int64_t imageSize = 0;
+
+ if (flags & FLAG_USE_QUOTA) {
+ struct dqblk dq;
+
+ auto device = findDeviceForUuid(uuid);
+
+ 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
+ totalSize = dq.dqb_curspace;
+ }
+
+ gid_t audioGid = multiuser_get_uid(userId, AID_MEDIA_AUDIO);
+ if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), audioGid,
+ reinterpret_cast<char*>(&dq)) == 0) {
+#if MEASURE_DEBUG
+ LOG(DEBUG) << "quotactl() for GID " << audioGid << " " << dq.dqb_curspace;
+#endif
+ audioSize = dq.dqb_curspace;
+ }
+ gid_t videoGid = multiuser_get_uid(userId, AID_MEDIA_VIDEO);
+ if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), videoGid,
+ reinterpret_cast<char*>(&dq)) == 0) {
+#if MEASURE_DEBUG
+ LOG(DEBUG) << "quotactl() for GID " << videoGid << " " << dq.dqb_curspace;
+#endif
+ videoSize = dq.dqb_curspace;
+ }
+ gid_t imageGid = multiuser_get_uid(userId, AID_MEDIA_IMAGE);
+ if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), imageGid,
+ reinterpret_cast<char*>(&dq)) == 0) {
+#if MEASURE_DEBUG
+ LOG(DEBUG) << "quotactl() for GID " << imageGid << " " << dq.dqb_curspace;
+#endif
+ imageSize = dq.dqb_curspace;
+ }
+ } else {
+ FTS *fts;
+ FTSENT *p;
+ auto path = create_data_media_path(uuid_, userId);
+ char *argv[] = { (char*) path.c_str(), nullptr };
+ if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_XDEV, NULL))) {
+ return error("Failed to fts_open " + path);
+ }
+ while ((p = fts_read(fts)) != NULL) {
+ char* ext;
+ int64_t size = (p->fts_statp->st_blocks * 512);
+ switch (p->fts_info) {
+ case FTS_F:
+ // Only categorize files not belonging to apps
+ if (p->fts_statp->st_gid < AID_APP_START) {
+ ext = strrchr(p->fts_name, '.');
+ if (ext != nullptr) {
+ switch (MatchExtension(++ext)) {
+ case AID_MEDIA_AUDIO: audioSize += size; break;
+ case AID_MEDIA_VIDEO: videoSize += size; break;
+ case AID_MEDIA_IMAGE: imageSize += size; break;
+ }
+ }
+ }
+ // Fall through to always count against total
+ case FTS_D:
+ case FTS_DEFAULT:
+ case FTS_SL:
+ case FTS_SLNONE:
+ totalSize += size;
+ break;
+ }
+ }
+ fts_close(fts);
+ }
+
+ std::vector<int64_t> ret;
+ ret.push_back(totalSize);
+ ret.push_back(audioSize);
+ ret.push_back(videoSize);
+ ret.push_back(imageSize);
+#if MEASURE_DEBUG
+ LOG(DEBUG) << "Final result " << toString(ret);
+#endif
*_aidl_return = ret;
return ok();
}