diff options
author | 2018-10-26 12:06:58 -0600 | |
---|---|---|
committer | 2018-11-02 14:31:19 +0000 | |
commit | 5f30826cd6817972547bdfe20b10294ea9ba7a38 (patch) | |
tree | 7605a064d1e2b639bfed40b01591754081c080bf | |
parent | 1eb32e2ffd899e0e70d4cea1c5f5817fd52def1f (diff) |
Refactor quota ops to a separate utils
Bug: 110380029
Test: - android.appsecurity.cts.StorageHostTest - all passes either when
running in bulk or when running alone (some tests somehow fails when
running in bulk - but passes when running alone. This also happens
before this CL, so the failure is not caused by this CL).
- Also tested with quota disabled.
Change-Id: I7a950115153378c9aeda86dd46bfa10f67c4e464
-rw-r--r-- | cmds/installd/Android.bp | 1 | ||||
-rw-r--r-- | cmds/installd/CacheTracker.cpp | 36 | ||||
-rw-r--r-- | cmds/installd/CacheTracker.h | 4 | ||||
-rw-r--r-- | cmds/installd/InstalldNativeService.cpp | 200 | ||||
-rw-r--r-- | cmds/installd/InstalldNativeService.h | 3 | ||||
-rw-r--r-- | cmds/installd/QuotaUtils.cpp | 122 | ||||
-rw-r--r-- | cmds/installd/QuotaUtils.h | 41 |
7 files changed, 232 insertions, 175 deletions
diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp index 9d0d8ba8b7..3c42ede116 100644 --- a/cmds/installd/Android.bp +++ b/cmds/installd/Android.bp @@ -14,6 +14,7 @@ cc_defaults { "CacheItem.cpp", "CacheTracker.cpp", "InstalldNativeService.cpp", + "QuotaUtils.cpp", "dexopt.cpp", "globals.cpp", "utils.cpp", diff --git a/cmds/installd/CacheTracker.cpp b/cmds/installd/CacheTracker.cpp index a7242c35cf..8b868fb584 100644 --- a/cmds/installd/CacheTracker.cpp +++ b/cmds/installd/CacheTracker.cpp @@ -19,13 +19,13 @@ #include "CacheTracker.h" #include <fts.h> -#include <sys/quota.h> #include <sys/xattr.h> #include <utils/Trace.h> #include <android-base/logging.h> #include <android-base/stringprintf.h> +#include "QuotaUtils.h" #include "utils.h" using android::base::StringPrintf; @@ -33,9 +33,13 @@ using android::base::StringPrintf; namespace android { namespace installd { -CacheTracker::CacheTracker(userid_t userId, appid_t appId, const std::string& quotaDevice) : - cacheUsed(0), cacheQuota(0), mUserId(userId), mAppId(appId), mQuotaDevice(quotaDevice), - mItemsLoaded(false) { +CacheTracker::CacheTracker(userid_t userId, appid_t appId, const std::string& uuid) + : cacheUsed(0), + cacheQuota(0), + mUserId(userId), + mAppId(appId), + mItemsLoaded(false), + mUuid(uuid) { } CacheTracker::~CacheTracker() { @@ -72,26 +76,18 @@ void CacheTracker::loadStats() { bool CacheTracker::loadQuotaStats() { int cacheGid = multiuser_get_cache_gid(mUserId, mAppId); int extCacheGid = multiuser_get_ext_cache_gid(mUserId, mAppId); - if (!mQuotaDevice.empty() && cacheGid != -1 && extCacheGid != -1) { - struct dqblk dq; - if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), mQuotaDevice.c_str(), cacheGid, - reinterpret_cast<char*>(&dq)) != 0) { - if (errno != ESRCH) { - PLOG(ERROR) << "Failed to quotactl " << mQuotaDevice << " for GID " << cacheGid; - } - return false; + if (IsQuotaSupported(mUuid) && cacheGid != -1 && extCacheGid != -1) { + int64_t space; + if ((space = GetOccupiedSpaceForGid(mUuid, cacheGid)) != -1) { + cacheUsed += space; } else { - cacheUsed += dq.dqb_curspace; + return false; } - if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), mQuotaDevice.c_str(), extCacheGid, - reinterpret_cast<char*>(&dq)) != 0) { - if (errno != ESRCH) { - PLOG(ERROR) << "Failed to quotactl " << mQuotaDevice << " for GID " << cacheGid; - } - return false; + if ((space = GetOccupiedSpaceForGid(mUuid, extCacheGid)) != -1) { + cacheUsed += space; } else { - cacheUsed += dq.dqb_curspace; + return false; } return true; } else { diff --git a/cmds/installd/CacheTracker.h b/cmds/installd/CacheTracker.h index 44359b4970..b0527e7b3f 100644 --- a/cmds/installd/CacheTracker.h +++ b/cmds/installd/CacheTracker.h @@ -39,7 +39,7 @@ namespace installd { */ class CacheTracker { public: - CacheTracker(userid_t userId, appid_t appId, const std::string& quotaDevice); + CacheTracker(userid_t userId, appid_t appId, const std::string& uuid); ~CacheTracker(); std::string toString(); @@ -61,8 +61,8 @@ public: private: userid_t mUserId; appid_t mAppId; - std::string mQuotaDevice; bool mItemsLoaded; + const std::string& mUuid; std::vector<std::string> mDataPaths; diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp index 28ffdf1e31..2439dff54e 100644 --- a/cmds/installd/InstalldNativeService.cpp +++ b/cmds/installd/InstalldNativeService.cpp @@ -31,7 +31,6 @@ #include <sys/file.h> #include <sys/ioctl.h> #include <sys/mman.h> -#include <sys/quota.h> #include <sys/resource.h> #include <sys/stat.h> #include <sys/statvfs.h> @@ -64,6 +63,7 @@ #include "CacheTracker.h" #include "MatchExtensionGen.h" +#include "QuotaUtils.h" #ifndef LOG_TAG #define LOG_TAG "installd" @@ -266,11 +266,6 @@ status_t InstalldNativeService::dump(int fd, const Vector<String16> & /* args */ for (const auto& n : mStorageMounts) { out << " " << n.first << " = " << n.second << endl; } - - out << endl << "Quota reverse mounts:" << endl; - for (const auto& n : mQuotaReverseMounts) { - out << " " << n.first << " = " << n.second << endl; - } } { @@ -950,9 +945,9 @@ binder::Status InstalldNativeService::freeCache(const std::unique_ptr<std::strin CHECK_ARGUMENT_UUID(uuid); std::lock_guard<std::recursive_mutex> lock(mLock); + auto uuidString = uuid ? *uuid : ""; const char* uuid_ = uuid ? uuid->c_str() : nullptr; auto data_path = create_data_path(uuid_); - auto device = findQuotaDeviceForUuid(uuid); auto noop = (flags & FLAG_FREE_CACHE_NOOP); int64_t free = data_disk_free(data_path); @@ -999,7 +994,7 @@ binder::Status InstalldNativeService::freeCache(const std::unique_ptr<std::strin search->second->addDataPath(p->fts_path); } else { auto tracker = std::shared_ptr<CacheTracker>(new CacheTracker( - multiuser_get_user_id(uid), multiuser_get_app_id(uid), device)); + multiuser_get_user_id(uid), multiuser_get_app_id(uid), uuidString)); tracker->addDataPath(p->fts_path); { std::lock_guard<std::recursive_mutex> lock(mQuotasLock); @@ -1164,53 +1159,26 @@ static std::string toString(std::vector<int64_t> values) { } #endif -static void collectQuotaStats(const std::string& device, int32_t userId, +static void collectQuotaStats(const std::string& uuid, int32_t userId, int32_t appId, struct stats* stats, struct stats* extStats) { - if (device.empty()) return; - - struct dqblk dq; - + int64_t space; if (stats != nullptr) { uid_t uid = multiuser_get_uid(userId, appId); - 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 - stats->dataSize += dq.dqb_curspace; + if ((space = GetOccupiedSpaceForUid(uuid, uid)) != -1) { + stats->dataSize += space; } int cacheGid = multiuser_get_cache_gid(userId, appId); if (cacheGid != -1) { - if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), cacheGid, - reinterpret_cast<char*>(&dq)) != 0) { - if (errno != ESRCH) { - 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; + if ((space = GetOccupiedSpaceForGid(uuid, cacheGid)) != -1) { + stats->cacheSize += space; } } int sharedGid = multiuser_get_shared_gid(0, appId); if (sharedGid != -1) { - if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), sharedGid, - reinterpret_cast<char*>(&dq)) != 0) { - if (errno != ESRCH) { - 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 ((space = GetOccupiedSpaceForGid(uuid, sharedGid)) != -1) { + stats->codeSize += space; } } } @@ -1218,32 +1186,16 @@ static void collectQuotaStats(const std::string& device, int32_t userId, if (extStats != nullptr) { 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; + if ((space = GetOccupiedSpaceForGid(uuid, extGid)) != -1) { + extStats->dataSize += space; } } int extCacheGid = multiuser_get_ext_cache_gid(userId, appId); if (extCacheGid != -1) { - if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), extCacheGid, - reinterpret_cast<char*>(&dq)) != 0) { - if (errno != ESRCH) { - PLOG(ERROR) << "Failed to quotactl " << device << " for GID " << extCacheGid; - } - } else { -#if MEASURE_DEBUG - LOG(DEBUG) << "quotactl() for GID " << extCacheGid << " " << dq.dqb_curspace; -#endif - extStats->dataSize += dq.dqb_curspace; - extStats->cacheSize += dq.dqb_curspace; + if ((space = GetOccupiedSpaceForGid(uuid, extCacheGid)) != -1) { + extStats->dataSize += space; + extStats->cacheSize += space; } } } @@ -1407,10 +1359,10 @@ binder::Status InstalldNativeService::getAppSize(const std::unique_ptr<std::stri memset(&stats, 0, sizeof(stats)); memset(&extStats, 0, sizeof(extStats)); + auto uuidString = uuid ? *uuid : ""; const char* uuid_ = uuid ? uuid->c_str() : nullptr; - auto device = findQuotaDeviceForUuid(uuid); - if (device.empty()) { + if (!IsQuotaSupported(uuidString)) { flags &= ~FLAG_USE_QUOTA; } @@ -1430,7 +1382,7 @@ binder::Status InstalldNativeService::getAppSize(const std::unique_ptr<std::stri ATRACE_END(); ATRACE_BEGIN("quota"); - collectQuotaStats(device, userId, appId, &stats, &extStats); + collectQuotaStats(uuidString, userId, appId, &stats, &extStats); ATRACE_END(); } else { ATRACE_BEGIN("code"); @@ -1513,27 +1465,19 @@ binder::Status InstalldNativeService::getUserSize(const std::unique_ptr<std::str memset(&stats, 0, sizeof(stats)); memset(&extStats, 0, sizeof(extStats)); + auto uuidString = uuid ? *uuid : ""; const char* uuid_ = uuid ? uuid->c_str() : nullptr; - auto device = findQuotaDeviceForUuid(uuid); - if (device.empty()) { + if (!IsQuotaSupported(uuidString)) { flags &= ~FLAG_USE_QUOTA; } if (flags & FLAG_USE_QUOTA) { - struct dqblk dq; + int64_t space; 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; + if ((space = GetOccupiedSpaceForGid(uuidString, AID_MEDIA_OBB)) != -1) { + extStats.codeSize += space; } ATRACE_END(); @@ -1559,16 +1503,8 @@ binder::Status InstalldNativeService::getUserSize(const std::unique_ptr<std::str ATRACE_BEGIN("external"); 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; + if ((space = GetOccupiedSpaceForUid(uuidString, uid)) != -1) { + extStats.dataSize += space; } ATRACE_END(); @@ -1585,7 +1521,7 @@ binder::Status InstalldNativeService::getUserSize(const std::unique_ptr<std::str int64_t dataSize = extStats.dataSize; for (auto appId : appIds) { if (appId >= AID_APP_START) { - collectQuotaStats(device, userId, appId, &stats, &extStats); + collectQuotaStats(uuidString, userId, appId, &stats, &extStats); #if MEASURE_DEBUG // Sleep to make sure we don't lose logs @@ -1667,6 +1603,7 @@ binder::Status InstalldNativeService::getExternalSize(const std::unique_ptr<std: LOG(INFO) << "Measuring external " << userId; #endif + auto uuidString = uuid ? *uuid : ""; const char* uuid_ = uuid ? uuid->c_str() : nullptr; int64_t totalSize = 0; @@ -1676,58 +1613,33 @@ binder::Status InstalldNativeService::getExternalSize(const std::unique_ptr<std: int64_t appSize = 0; int64_t obbSize = 0; - auto device = findQuotaDeviceForUuid(uuid); - if (device.empty()) { + if (!IsQuotaSupported(uuidString)) { flags &= ~FLAG_USE_QUOTA; } if (flags & FLAG_USE_QUOTA) { - struct dqblk dq; + int64_t space; ATRACE_BEGIN("quota"); 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; + if ((space = GetOccupiedSpaceForUid(uuidString, uid)) != -1) { + totalSize = space; } 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; + if ((space = GetOccupiedSpaceForGid(uuidString, audioGid)) != -1) { + audioSize = space; } 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; + if ((space = GetOccupiedSpaceForGid(uuidString, videoGid)) != -1) { + videoSize = space; } 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; + if ((space = GetOccupiedSpaceForGid(uuidString, imageGid)) != -1) { + imageSize = space; } - if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), AID_MEDIA_OBB, - reinterpret_cast<char*>(&dq)) == 0) { -#if MEASURE_DEBUG - LOG(DEBUG) << "quotactl() for GID " << AID_MEDIA_OBB << " " << dq.dqb_curspace; -#endif - obbSize = dq.dqb_curspace; + if ((space = GetOccupiedSpaceForGid(uuidString, AID_MEDIA_OBB)) != -1) { + obbSize = space; } ATRACE_END(); @@ -1736,7 +1648,7 @@ binder::Status InstalldNativeService::getExternalSize(const std::unique_ptr<std: memset(&extStats, 0, sizeof(extStats)); for (auto appId : appIds) { if (appId >= AID_APP_START) { - collectQuotaStats(device, userId, appId, nullptr, &extStats); + collectQuotaStats(uuidString, userId, appId, nullptr, &extStats); } } appSize = extStats.dataSize; @@ -2524,7 +2436,12 @@ binder::Status InstalldNativeService::invalidateMounts() { std::lock_guard<std::recursive_mutex> lock(mMountsLock); mStorageMounts.clear(); - mQuotaReverseMounts.clear(); + +#if !BYPASS_QUOTA + if (!InvalidateQuotaMounts()) { + return error("Failed to read mounts"); + } +#endif std::ifstream in("/proc/mounts"); if (!in.is_open()) { @@ -2545,17 +2462,6 @@ binder::Status InstalldNativeService::invalidateMounts() { mStorageMounts[source] = target; } #endif - -#if !BYPASS_QUOTA - if (source.compare(0, 11, "/dev/block/") == 0) { - struct dqblk dq; - if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), source.c_str(), 0, - reinterpret_cast<char*>(&dq)) == 0) { - LOG(DEBUG) << "Found quota mount " << source << " at " << target; - mQuotaReverseMounts[target] = source; - } - } -#endif } return ok(); } @@ -2573,16 +2479,10 @@ std::string InstalldNativeService::findDataMediaPath( return StringPrintf("%s/%u", resolved.c_str(), userid); } -std::string InstalldNativeService::findQuotaDeviceForUuid( - const std::unique_ptr<std::string>& uuid) { - std::lock_guard<std::recursive_mutex> lock(mMountsLock); - auto path = create_data_path(uuid ? uuid->c_str() : nullptr); - return mQuotaReverseMounts[path]; -} - binder::Status InstalldNativeService::isQuotaSupported( - const std::unique_ptr<std::string>& volumeUuid, bool* _aidl_return) { - *_aidl_return = !findQuotaDeviceForUuid(volumeUuid).empty(); + const std::unique_ptr<std::string>& uuid, bool* _aidl_return) { + auto uuidString = uuid ? *uuid : ""; + *_aidl_return = IsQuotaSupported(uuidString); return ok(); } diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h index cebd3f90d3..367f2c1547 100644 --- a/cmds/installd/InstalldNativeService.h +++ b/cmds/installd/InstalldNativeService.h @@ -150,14 +150,11 @@ private: /* Map of all storage mounts from source to target */ std::unordered_map<std::string, std::string> mStorageMounts; - /* Map of all quota mounts from target to source */ - std::unordered_map<std::string, std::string> mQuotaReverseMounts; /* Map from UID to cache quota size */ std::unordered_map<uid_t, int64_t> mCacheQuotas; std::string findDataMediaPath(const std::unique_ptr<std::string>& uuid, userid_t userid); - std::string findQuotaDeviceForUuid(const std::unique_ptr<std::string>& uuid); }; } // namespace installd diff --git a/cmds/installd/QuotaUtils.cpp b/cmds/installd/QuotaUtils.cpp new file mode 100644 index 0000000000..b238dd36e3 --- /dev/null +++ b/cmds/installd/QuotaUtils.cpp @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "QuotaUtils.h" + +#include <fstream> +#include <unordered_map> + +#include <sys/quota.h> + +#include <android-base/logging.h> + +#include "utils.h" + +namespace android { +namespace installd { + +namespace { + +std::recursive_mutex mMountsLock; + +/* Map of all quota mounts from target to source */ +std::unordered_map<std::string, std::string> mQuotaReverseMounts; + +std::string& FindQuotaDeviceForUuid(const std::string& uuid) { + std::lock_guard<std::recursive_mutex> lock(mMountsLock); + auto path = create_data_path(uuid.empty() ? nullptr : uuid.c_str()); + return mQuotaReverseMounts[path]; +} + +} // namespace + +bool InvalidateQuotaMounts() { + std::lock_guard<std::recursive_mutex> lock(mMountsLock); + + mQuotaReverseMounts.clear(); + + std::ifstream in("/proc/mounts"); + if (!in.is_open()) { + return false; + } + + std::string source; + std::string target; + std::string ignored; + while (!in.eof()) { + std::getline(in, source, ' '); + std::getline(in, target, ' '); + std::getline(in, ignored); + + if (source.compare(0, 11, "/dev/block/") == 0) { + struct dqblk dq; + if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), source.c_str(), 0, + reinterpret_cast<char*>(&dq)) == 0) { + LOG(DEBUG) << "Found quota mount " << source << " at " << target; + mQuotaReverseMounts[target] = source; + } + } + } + return true; +} + +bool IsQuotaSupported(const std::string& uuid) { + return !FindQuotaDeviceForUuid(uuid).empty(); +} + +int64_t GetOccupiedSpaceForUid(const std::string& uuid, uid_t uid) { + const std::string device = FindQuotaDeviceForUuid(uuid); + if (device == "") { + return -1; + } + struct dqblk dq; + 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; + } + return -1; + } else { +#if MEASURE_DEBUG + LOG(DEBUG) << "quotactl() for UID " << uid << " " << dq.dqb_curspace; +#endif + return dq.dqb_curspace; + } +} + +int64_t GetOccupiedSpaceForGid(const std::string& uuid, gid_t gid) { + const std::string device = FindQuotaDeviceForUuid(uuid); + if (device == "") { + return -1; + } + struct dqblk dq; + if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), gid, + reinterpret_cast<char*>(&dq)) != 0) { + if (errno != ESRCH) { + PLOG(ERROR) << "Failed to quotactl " << device << " for GID " << gid; + } + return -1; + } else { +#if MEASURE_DEBUG + LOG(DEBUG) << "quotactl() for GID " << gid << " " << dq.dqb_curspace; +#endif + return dq.dqb_curspace; + } + +} + +} // namespace installd +} // namespace android diff --git a/cmds/installd/QuotaUtils.h b/cmds/installd/QuotaUtils.h new file mode 100644 index 0000000000..9ad170fcbb --- /dev/null +++ b/cmds/installd/QuotaUtils.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_INSTALLD_QUOTA_UTILS_H_ +#define ANDROID_INSTALLD_QUOTA_UTILS_H_ + +#include <memory> +#include <string> + +namespace android { +namespace installd { + +/* Clear and recompute the reverse mounts map */ +bool InvalidateQuotaMounts(); + +/* Whether quota is supported in the device with the given uuid */ +bool IsQuotaSupported(const std::string& uuid); + +/* Get the current occupied space in bytes for a uid or -1 if fails */ +int64_t GetOccupiedSpaceForUid(const std::string& uuid, uid_t uid); + +/* Get the current occupied space in bytes for a gid or -1 if fails */ +int64_t GetOccupiedSpaceForGid(const std::string& uuid, gid_t gid); + +} // namespace installd +} // namespace android + +#endif // ANDROID_INSTALLD_QUOTA_UTILS_H_ |