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
This commit is contained in:
parent
55c0da3208
commit
771cc344c6
4 changed files with 198 additions and 49 deletions
|
@ -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;
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in a new issue