From 66b1a12e7a120f85042669bb58f1db864616b506 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Mon, 16 Jan 2017 20:57:45 -0700 Subject: [PATCH] Handle devices without quota, speed up lookup. Start tracking which block devices have quota support, and gracefully clear FLAG_USE_QUOTA when no support is present. Also build a cached map of mounted volumes that support quota, which halves the average quota calculation speed from 0.70ms to 0.35ms, since we're no longer parsing procfs every time. Test: builds, boots, common operations work Bug: 34249218 Change-Id: Ie791df7801b67495331f3eea256c018860c9b4f6 --- cmds/installd/InstalldNativeService.cpp | 100 ++++++++++++++++--------- cmds/installd/InstalldNativeService.h | 8 ++ cmds/installd/binder/android/os/IInstalld.aidl | 2 + 3 files changed, 75 insertions(+), 35 deletions(-) diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp index 102359d442..0339086cf0 100644 --- a/cmds/installd/InstalldNativeService.cpp +++ b/cmds/installd/InstalldNativeService.cpp @@ -60,6 +60,7 @@ #endif using android::base::StringPrintf; +using std::endl; namespace android { namespace installd { @@ -188,15 +189,22 @@ status_t InstalldNativeService::start() { } status_t InstalldNativeService::dump(int fd, const Vector & /* args */) { + auto out = std::fstream(StringPrintf("/proc/self/fd/%d", fd)); const binder::Status dump_permission = checkPermission(kDump); if (!dump_permission.isOk()) { - const String8 msg(dump_permission.toString8()); - write(fd, msg.string(), msg.size()); + out << dump_permission.toString8() << endl; return PERMISSION_DENIED; } + std::lock_guard lock(mLock); + + out << "installd is happy!" << endl << endl; + out << "Devices with quota support:" << endl; + for (const auto& n : mQuotaDevices) { + out << " " << n.first << " = " << n.second << endl; + } + out << endl; + out.flush(); - std::string msg = "installd is happy\n"; - write(fd, msg.c_str(), strlen(msg.c_str())); return NO_ERROR; } @@ -888,28 +896,6 @@ static std::string toString(std::vector values) { } #endif -static std::string findDeviceForUuid(const std::unique_ptr& uuid) { - auto path = create_data_path(uuid ? uuid->c_str() : nullptr); - 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); - } - 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; @@ -964,11 +950,6 @@ static void collectQuotaStats(const std::string& device, int32_t userId, #endif } -static void collectQuotaStats(const std::unique_ptr& 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; @@ -1090,6 +1071,11 @@ binder::Status InstalldNativeService::getAppSize(const std::unique_ptrc_str() : nullptr; + auto device = findQuotaDeviceForUuid(uuid); + if (device.empty()) { + flags &= ~FLAG_USE_QUOTA; + } + for (auto packageName : packageNames) { auto obbCodePath = create_data_media_obb_path(uuid_, packageName.c_str()); calculate_tree_size(obbCodePath, &extStats.codeSize); @@ -1101,7 +1087,7 @@ binder::Status InstalldNativeService::getAppSize(const std::unique_ptr= AID_APP_START) { collectQuotaStats(device, userId, appId, &stats, &extStats); @@ -1273,11 +1263,14 @@ binder::Status InstalldNativeService::getExternalSize(const std::unique_ptr(&dq)) != 0) { @@ -1776,5 +1769,42 @@ binder::Status InstalldNativeService::deleteOdex(const std::string& apkPath, return res ? ok() : error(); } +binder::Status InstalldNativeService::invalidateMounts() { + ENFORCE_UID(AID_SYSTEM); + std::lock_guard lock(mLock); + + mQuotaDevices.clear(); + + std::ifstream in("/proc/mounts"); + if (!in.is_open()) { + return error("Failed to read mounts"); + } + + std::string source; + std::string target; + std::string ignored; + struct dqblk dq; + while (!in.eof()) { + std::getline(in, source, ' '); + std::getline(in, target, ' '); + std::getline(in, ignored); + + if (source.compare(0, 11, "/dev/block/") == 0) { + if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), source.c_str(), 0, + reinterpret_cast(&dq)) == 0) { + LOG(DEBUG) << "Found " << source << " with quota"; + mQuotaDevices[target] = source; + } + } + } + return ok(); +} + +std::string InstalldNativeService::findQuotaDeviceForUuid( + const std::unique_ptr& uuid) { + auto path = create_data_path(uuid ? uuid->c_str() : nullptr); + return mQuotaDevices[path]; +} + } // namespace installd } // namespace android diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h index ec814629c0..0208fb147c 100644 --- a/cmds/installd/InstalldNativeService.h +++ b/cmds/installd/InstalldNativeService.h @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -100,8 +101,15 @@ public: binder::Status deleteOdex(const std::string& apkPath, const std::string& instructionSet, const std::string& outputPath); + binder::Status invalidateMounts(); + private: std::recursive_mutex mLock; + + /* Map from mount point to underlying device node */ + std::unordered_map mQuotaDevices; + + std::string findQuotaDeviceForUuid(const std::unique_ptr& uuid); }; } // namespace installd diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl index 6e4d7fa7ab..2f12ea9f37 100644 --- a/cmds/installd/binder/android/os/IInstalld.aidl +++ b/cmds/installd/binder/android/os/IInstalld.aidl @@ -68,4 +68,6 @@ interface IInstalld { @utf8InCpp String outputPath); void deleteOdex(@utf8InCpp String apkPath, @utf8InCpp String instructionSet, @utf8InCpp String outputPath); + + void invalidateMounts(); } -- 2.11.0