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
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 102359d..0339086 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::dump(int fd, const Vector<String16> & /* 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<std::recursive_mutex> lock(mLock);
- std::string msg = "installd is happy\n";
- write(fd, msg.c_str(), strlen(msg.c_str()));
+ 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();
+
return NO_ERROR;
}
@@ -888,28 +896,6 @@
}
#endif
-static std::string findDeviceForUuid(const std::unique_ptr<std::string>& 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 @@
#endif
}
-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;
@@ -1090,6 +1071,11 @@
const char* uuid_ = uuid ? uuid->c_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 @@
multiuser_get_shared_gid(userId, appId));
}
- collectQuotaStats(uuid, userId, appId, &stats, &extStats);
+ collectQuotaStats(device, userId, appId, &stats, &extStats);
} else {
for (auto codePath : codePaths) {
@@ -1180,6 +1166,11 @@
auto obbPath = create_data_path(uuid_) + "/media/obb";
calculate_tree_size(obbPath, &extStats.codeSize);
+ auto device = findQuotaDeviceForUuid(uuid);
+ if (device.empty()) {
+ flags &= ~FLAG_USE_QUOTA;
+ }
+
if (flags & FLAG_USE_QUOTA) {
calculate_tree_size(create_data_app_path(uuid_), &stats.codeSize, -1, -1, true);
@@ -1205,7 +1196,6 @@
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);
@@ -1273,11 +1263,14 @@
int64_t videoSize = 0;
int64_t imageSize = 0;
+ auto device = findQuotaDeviceForUuid(uuid);
+ if (device.empty()) {
+ flags &= ~FLAG_USE_QUOTA;
+ }
+
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) {
@@ -1776,5 +1769,42 @@
return res ? ok() : error();
}
+binder::Status InstalldNativeService::invalidateMounts() {
+ ENFORCE_UID(AID_SYSTEM);
+ std::lock_guard<std::recursive_mutex> 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<char*>(&dq)) == 0) {
+ LOG(DEBUG) << "Found " << source << " with quota";
+ mQuotaDevices[target] = source;
+ }
+ }
+ }
+ return ok();
+}
+
+std::string InstalldNativeService::findQuotaDeviceForUuid(
+ const std::unique_ptr<std::string>& 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 ec81462..0208fb1 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -22,6 +22,7 @@
#include <unistd.h>
#include <vector>
+#include <unordered_map>
#include <binder/BinderService.h>
#include <cutils/multiuser.h>
@@ -100,8 +101,15 @@
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<std::string, std::string> mQuotaDevices;
+
+ std::string findQuotaDeviceForUuid(const std::unique_ptr<std::string>& uuid);
};
} // namespace installd
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index 6e4d7fa..2f12ea9 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -68,4 +68,6 @@
@utf8InCpp String outputPath);
void deleteOdex(@utf8InCpp String apkPath, @utf8InCpp String instructionSet,
@utf8InCpp String outputPath);
+
+ void invalidateMounts();
}