OSDN Git Service

Handle devices without quota, speed up lookup.
authorJeff Sharkey <jsharkey@android.com>
Tue, 17 Jan 2017 03:57:45 +0000 (20:57 -0700)
committerJeff Sharkey <jsharkey@android.com>
Tue, 17 Jan 2017 03:59:01 +0000 (20:59 -0700)
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
cmds/installd/InstalldNativeService.h
cmds/installd/binder/android/os/IInstalld.aidl

index 102359d..0339086 100644 (file)
@@ -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<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);
+
+    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<int64_t> values) {
 }
 #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 @@ static void collectQuotaStats(const std::string& device, int32_t userId,
 #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 @@ binder::Status InstalldNativeService::getAppSize(const std::unique_ptr<std::stri
 
     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 @@ binder::Status InstalldNativeService::getAppSize(const std::unique_ptr<std::stri
                     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 @@ binder::Status InstalldNativeService::getUserSize(const std::unique_ptr<std::str
     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 @@ binder::Status InstalldNativeService::getUserSize(const std::unique_ptr<std::str
         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 @@ binder::Status InstalldNativeService::getExternalSize(const std::unique_ptr<std:
     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 @@ binder::Status InstalldNativeService::deleteOdex(const std::string& apkPath,
     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
index ec81462..0208fb1 100644 (file)
@@ -22,6 +22,7 @@
 #include <unistd.h>
 
 #include <vector>
+#include <unordered_map>
 
 #include <binder/BinderService.h>
 #include <cutils/multiuser.h>
@@ -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<std::string, std::string> mQuotaDevices;
+
+    std::string findQuotaDeviceForUuid(const std::unique_ptr<std::string>& uuid);
 };
 
 }  // namespace installd
index 6e4d7fa..2f12ea9 100644 (file)
@@ -68,4 +68,6 @@ interface IInstalld {
             @utf8InCpp String outputPath);
     void deleteOdex(@utf8InCpp String apkPath, @utf8InCpp String instructionSet,
             @utf8InCpp String outputPath);
+
+    void invalidateMounts();
 }