diff options
author | 2020-02-19 23:26:56 +0100 | |
---|---|---|
committer | 2020-02-20 15:41:02 +0100 | |
commit | 771cc344c65894405b05da1a22ffd57ae915d819 (patch) | |
tree | f2b80b50820f26b0efe1119cb795340952e79120 | |
parent | 55c0da3208354ea2a8243c0c6f91aa4e957b8703 (diff) |
Implement quota calculation for project ID based quota.
Devices launching with R will no longer have the sdcardfs filesystem;
instead, quota tracking on external storage is implemented by project
IDs. Switch over the existing quota calculation to use project IDs when
sdcardfs is not available.
Bug: 146419093
Test: atest StorageHostTest (on devices with and without sdcardfs)
Change-Id: I17925c811b08c7c85fff02ee6e279e4d7586e3ff
-rw-r--r-- | cmds/installd/CacheTracker.cpp | 5 | ||||
-rw-r--r-- | cmds/installd/InstalldNativeService.cpp | 190 | ||||
-rw-r--r-- | cmds/installd/utils.cpp | 48 | ||||
-rw-r--r-- | cmds/installd/utils.h | 4 |
4 files changed, 198 insertions, 49 deletions
diff --git a/cmds/installd/CacheTracker.cpp b/cmds/installd/CacheTracker.cpp index 8b868fb584..a61f6bf87b 100644 --- a/cmds/installd/CacheTracker.cpp +++ b/cmds/installd/CacheTracker.cpp @@ -75,8 +75,7 @@ void CacheTracker::loadStats() { bool CacheTracker::loadQuotaStats() { int cacheGid = multiuser_get_cache_gid(mUserId, mAppId); - int extCacheGid = multiuser_get_ext_cache_gid(mUserId, mAppId); - if (IsQuotaSupported(mUuid) && cacheGid != -1 && extCacheGid != -1) { + if (IsQuotaSupported(mUuid) && cacheGid != -1) { int64_t space; if ((space = GetOccupiedSpaceForGid(mUuid, cacheGid)) != -1) { cacheUsed += space; @@ -84,7 +83,7 @@ bool CacheTracker::loadQuotaStats() { return false; } - if ((space = GetOccupiedSpaceForGid(mUuid, extCacheGid)) != -1) { + if ((space = get_occupied_app_cache_space_external(mUuid, mUserId, mAppId)) != -1) { cacheUsed += space; } else { return false; diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp index 737c6c9582..d8d324aa58 100644 --- a/cmds/installd/InstalldNativeService.cpp +++ b/cmds/installd/InstalldNativeService.cpp @@ -53,6 +53,7 @@ #include <log/log.h> // TODO: Move everything to base/logging. #include <logwrap/logwrap.h> #include <private/android_filesystem_config.h> +#include <private/android_projectid_config.h> #include <selinux/android.h> #include <system/thread_defs.h> #include <utils/Trace.h> @@ -1474,8 +1475,8 @@ static std::string toString(std::vector<int64_t> values) { static void collectQuotaStats(const std::string& uuid, int32_t userId, int32_t appId, struct stats* stats, struct stats* extStats) { int64_t space; + uid_t uid = multiuser_get_uid(userId, appId); if (stats != nullptr) { - uid_t uid = multiuser_get_uid(userId, appId); if ((space = GetOccupiedSpaceForUid(uuid, uid)) != -1) { stats->dataSize += space; } @@ -1496,20 +1497,44 @@ static void collectQuotaStats(const std::string& uuid, int32_t userId, } if (extStats != nullptr) { - int extGid = multiuser_get_ext_gid(userId, appId); - if (extGid != -1) { - if ((space = GetOccupiedSpaceForGid(uuid, extGid)) != -1) { - extStats->dataSize += space; + static const bool supportsSdCardFs = supports_sdcardfs(); + space = get_occupied_app_space_external(uuid, userId, appId); + + if (space != -1) { + extStats->dataSize += space; + if (!supportsSdCardFs && stats != nullptr) { + // On devices without sdcardfs, if internal and external are on + // the same volume, a uid such as u0_a123 is used for + // application dirs on both internal and external storage; + // therefore, substract that amount from internal to make sure + // we don't count it double. + stats->dataSize -= space; } } - int extCacheGid = multiuser_get_ext_cache_gid(userId, appId); - if (extCacheGid != -1) { - if ((space = GetOccupiedSpaceForGid(uuid, extCacheGid)) != -1) { - extStats->dataSize += space; - extStats->cacheSize += space; + space = get_occupied_app_cache_space_external(uuid, userId, appId); + if (space != -1) { + extStats->dataSize += space; // cache counts for "data" + extStats->cacheSize += space; + if (!supportsSdCardFs && stats != nullptr) { + // On devices without sdcardfs, if internal and external are on + // the same volume, a uid such as u0_a123 is used for both + // internal and external storage; therefore, substract that + // amount from internal to make sure we don't count it double. + stats->dataSize -= space; } } + + if (!supportsSdCardFs && stats != nullptr) { + // On devices without sdcardfs, the UID of OBBs on external storage + // matches the regular app UID (eg u0_a123); therefore, to avoid + // OBBs being include in stats->dataSize, compute the OBB size for + // this app, and substract it from the size reported on internal + // storage + long obbProjectId = uid - AID_APP_START + PROJECT_ID_EXT_OBB_START; + int64_t appObbSize = GetOccupiedSpaceForProjectId(uuid, obbProjectId); + stats->dataSize -= appObbSize; + } } } @@ -1758,6 +1783,106 @@ binder::Status InstalldNativeService::getAppSize(const std::unique_ptr<std::stri return ok(); } +struct external_sizes { + int64_t audioSize; + int64_t videoSize; + int64_t imageSize; + int64_t totalSize; // excludes OBBs (Android/obb), but includes app data + cache + int64_t obbSize; +}; + +#define PER_USER_RANGE 100000 + +static long getProjectIdForUser(int userId, long projectId) { + return userId * PER_USER_RANGE + projectId; +} + +static external_sizes getExternalSizesForUserWithQuota(const std::string& uuid, int32_t userId, const std::vector<int32_t>& appIds) { + struct external_sizes sizes = {}; + int64_t space; + + if (supports_sdcardfs()) { + uid_t uid = multiuser_get_uid(userId, AID_MEDIA_RW); + if ((space = GetOccupiedSpaceForUid(uuid, uid)) != -1) { + sizes.totalSize = space; + } + + gid_t audioGid = multiuser_get_uid(userId, AID_MEDIA_AUDIO); + if ((space = GetOccupiedSpaceForGid(uuid, audioGid)) != -1) { + sizes.audioSize = space; + } + + gid_t videoGid = multiuser_get_uid(userId, AID_MEDIA_VIDEO); + if ((space = GetOccupiedSpaceForGid(uuid, videoGid)) != -1) { + sizes.videoSize = space; + } + + gid_t imageGid = multiuser_get_uid(userId, AID_MEDIA_IMAGE); + if ((space = GetOccupiedSpaceForGid(uuid, imageGid)) != -1) { + sizes.imageSize = space; + } + + if ((space = GetOccupiedSpaceForGid(uuid, AID_MEDIA_OBB)) != -1) { + sizes.obbSize = space; + } + } else { + int64_t totalSize = 0; + long defaultProjectId = getProjectIdForUser(userId, PROJECT_ID_EXT_DEFAULT); + if ((space = GetOccupiedSpaceForProjectId(uuid, defaultProjectId)) != -1) { + // This is all files that are not audio/video/images, excluding + // OBBs and app-private data + totalSize += space; + } + + long audioProjectId = getProjectIdForUser(userId, PROJECT_ID_EXT_MEDIA_AUDIO); + if ((space = GetOccupiedSpaceForProjectId(uuid, audioProjectId)) != -1) { + sizes.audioSize = space; + totalSize += space; + } + + long videoProjectId = getProjectIdForUser(userId, PROJECT_ID_EXT_MEDIA_VIDEO); + if ((space = GetOccupiedSpaceForProjectId(uuid, videoProjectId)) != -1) { + sizes.videoSize = space; + totalSize += space; + } + + long imageProjectId = getProjectIdForUser(userId, PROJECT_ID_EXT_MEDIA_IMAGE); + if ((space = GetOccupiedSpaceForProjectId(uuid, imageProjectId)) != -1) { + sizes.imageSize = space; + totalSize += space; + } + + int64_t totalAppDataSize = 0; + int64_t totalAppCacheSize = 0; + int64_t totalAppObbSize = 0; + for (auto appId : appIds) { + if (appId >= AID_APP_START) { + // App data + uid_t uid = multiuser_get_uid(userId, appId); + long projectId = uid - AID_APP_START + PROJECT_ID_EXT_DATA_START; + totalAppDataSize += GetOccupiedSpaceForProjectId(uuid, projectId); + + // App cache + long cacheProjectId = uid - AID_APP_START + PROJECT_ID_EXT_CACHE_START; + totalAppCacheSize += GetOccupiedSpaceForProjectId(uuid, cacheProjectId); + + // App OBBs + long obbProjectId = uid - AID_APP_START + PROJECT_ID_EXT_OBB_START; + totalAppObbSize += GetOccupiedSpaceForProjectId(uuid, obbProjectId); + } + } + // Total size should include app data + cache + totalSize += totalAppDataSize; + totalSize += totalAppCacheSize; + sizes.totalSize = totalSize; + + // Only OBB is separate + sizes.obbSize = totalAppObbSize; + } + + return sizes; +} + 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) { @@ -1786,14 +1911,6 @@ binder::Status InstalldNativeService::getUserSize(const std::unique_ptr<std::str } if (flags & FLAG_USE_QUOTA) { - int64_t space; - - ATRACE_BEGIN("obb"); - if ((space = GetOccupiedSpaceForGid(uuidString, AID_MEDIA_OBB)) != -1) { - extStats.codeSize += space; - } - ATRACE_END(); - ATRACE_BEGIN("code"); calculate_tree_size(create_data_app_path(uuid_), &stats.codeSize, -1, -1, true); ATRACE_END(); @@ -1815,10 +1932,9 @@ binder::Status InstalldNativeService::getUserSize(const std::unique_ptr<std::str } ATRACE_BEGIN("external"); - uid_t uid = multiuser_get_uid(userId, AID_MEDIA_RW); - if ((space = GetOccupiedSpaceForUid(uuidString, uid)) != -1) { - extStats.dataSize += space; - } + auto sizes = getExternalSizesForUserWithQuota(uuidString, userId, appIds); + extStats.dataSize += sizes.totalSize; + extStats.codeSize += sizes.obbSize; ATRACE_END(); if (!uuid) { @@ -1829,13 +1945,11 @@ binder::Status InstalldNativeService::getUserSize(const std::unique_ptr<std::str -1, -1, true); ATRACE_END(); } - ATRACE_BEGIN("quota"); int64_t dataSize = extStats.dataSize; for (auto appId : appIds) { if (appId >= AID_APP_START) { collectQuotaStats(uuidString, userId, appId, &stats, &extStats); - #if MEASURE_DEBUG // Sleep to make sure we don't lose logs usleep(1); @@ -1931,29 +2045,13 @@ binder::Status InstalldNativeService::getExternalSize(const std::unique_ptr<std: } if (flags & FLAG_USE_QUOTA) { - int64_t space; - ATRACE_BEGIN("quota"); - uid_t uid = multiuser_get_uid(userId, AID_MEDIA_RW); - if ((space = GetOccupiedSpaceForUid(uuidString, uid)) != -1) { - totalSize = space; - } - - gid_t audioGid = multiuser_get_uid(userId, AID_MEDIA_AUDIO); - if ((space = GetOccupiedSpaceForGid(uuidString, audioGid)) != -1) { - audioSize = space; - } - gid_t videoGid = multiuser_get_uid(userId, AID_MEDIA_VIDEO); - if ((space = GetOccupiedSpaceForGid(uuidString, videoGid)) != -1) { - videoSize = space; - } - gid_t imageGid = multiuser_get_uid(userId, AID_MEDIA_IMAGE); - if ((space = GetOccupiedSpaceForGid(uuidString, imageGid)) != -1) { - imageSize = space; - } - if ((space = GetOccupiedSpaceForGid(uuidString, AID_MEDIA_OBB)) != -1) { - obbSize = space; - } + auto sizes = getExternalSizesForUserWithQuota(uuidString, userId, appIds); + totalSize = sizes.totalSize; + audioSize = sizes.audioSize; + videoSize = sizes.videoSize; + imageSize = sizes.imageSize; + obbSize = sizes.obbSize; ATRACE_END(); ATRACE_BEGIN("apps"); diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp index 4eb1df0b2e..64eefe6f74 100644 --- a/cmds/installd/utils.cpp +++ b/cmds/installd/utils.cpp @@ -26,6 +26,7 @@ #include <sys/xattr.h> #include <sys/statvfs.h> +#include <android-base/file.h> #include <android-base/logging.h> #include <android-base/strings.h> #include <android-base/stringprintf.h> @@ -34,9 +35,11 @@ #include <cutils/properties.h> #include <log/log.h> #include <private/android_filesystem_config.h> +#include <private/android_projectid_config.h> #include "dexopt_return_codes.h" #include "globals.h" // extern variables. +#include "QuotaUtils.h" #ifndef LOG_TAG #define LOG_TAG "installd" @@ -1060,6 +1063,51 @@ int prepare_app_cache_dir(const std::string& parent, const char* name, mode_t ta return 0; } +static const char* kProcFilesystems = "/proc/filesystems"; +bool supports_sdcardfs() { + std::string supported; + if (!android::base::ReadFileToString(kProcFilesystems, &supported)) { + PLOG(ERROR) << "Failed to read supported filesystems"; + return false; + } + return supported.find("sdcardfs\n") != std::string::npos; +} + +int64_t get_occupied_app_space_external(const std::string& uuid, int32_t userId, int32_t appId) { + static const bool supportsSdcardFs = supports_sdcardfs(); + + if (supportsSdcardFs) { + int extGid = multiuser_get_ext_gid(userId, appId); + + if (extGid == -1) { + return -1; + } + + return GetOccupiedSpaceForGid(uuid, extGid); + } else { + uid_t uid = multiuser_get_uid(userId, appId); + long projectId = uid - AID_APP_START + PROJECT_ID_EXT_DATA_START; + return GetOccupiedSpaceForProjectId(uuid, projectId); + } +} +int64_t get_occupied_app_cache_space_external(const std::string& uuid, int32_t userId, int32_t appId) { + static const bool supportsSdcardFs = supports_sdcardfs(); + + if (supportsSdcardFs) { + int extCacheGid = multiuser_get_ext_cache_gid(userId, appId); + + if (extCacheGid == -1) { + return -1; + } + + return GetOccupiedSpaceForGid(uuid, extCacheGid); + } else { + uid_t uid = multiuser_get_uid(userId, appId); + long projectId = uid - AID_APP_START + PROJECT_ID_EXT_CACHE_START; + return GetOccupiedSpaceForProjectId(uuid, projectId); + } +} + // Collect all non empty profiles from the given directory and puts then into profile_paths. // The profiles are identified based on PROFILE_EXT extension. // If a subdirectory or profile file cannot be opened the method logs a warning and moves on. diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h index 6a420261a1..2503168f1e 100644 --- a/cmds/installd/utils.h +++ b/cmds/installd/utils.h @@ -150,6 +150,10 @@ int wait_child(pid_t pid); int prepare_app_cache_dir(const std::string& parent, const char* name, mode_t target_mode, uid_t uid, gid_t gid); +bool supports_sdcardfs(); +int64_t get_occupied_app_space_external(const std::string& uuid, int32_t userId, int32_t appId); +int64_t get_occupied_app_cache_space_external(const std::string& uuid, int32_t userId, int32_t appId); + // Collect all non empty profiles from the global profile directory and // put then into profile_paths. The profiles are identified based on PROFILE_EXT extension. // If a subdirectory or profile file cannot be opened the method logs a warning and moves on. |