Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit aae9644c authored by Shikha Malhotra's avatar Shikha Malhotra
Browse files

Manually calculate stats for app owning external storage

The stats are calculated using quota APIs for all the apps.
This is going wrong for the app owning external storage, as it includes
the external storage files also. The reason for that is the uid for the
external storage files and the app owning the external storage is the
same. Calculating the size manually avoids the problem.

Bug: http://b/195804288
Test: atest StorageHostTest
Test: atest installd_service_test.cpp
Change-Id: I183c6997375b94dc02562bede03e3a15036efb6e
parent 38a12996
Loading
Loading
Loading
Loading
+16 −3
Original line number Diff line number Diff line
@@ -1940,7 +1940,18 @@ static void collectManualExternalStatsForUser(const std::string& path, struct st
    }
    fts_close(fts);
}

static bool ownsExternalStorage(int32_t appId) {
    //  Fetch external storage owner appid  and check if it is the same as the
    //  current appId whose size is calculated
    struct stat s;
    auto _picDir = StringPrintf("%s/Pictures", create_data_media_path(nullptr, 0).c_str());
    // check if the stat are present
    if (stat(_picDir.c_str(), &s) == 0) {
        // fetch the appId from the uid of the media app
        return ((int32_t)multiuser_get_app_id(s.st_uid) == appId);
    }
    return false;
}
binder::Status InstalldNativeService::getAppSize(const std::optional<std::string>& uuid,
        const std::vector<std::string>& packageNames, int32_t userId, int32_t flags,
        int32_t appId, const std::vector<int64_t>& ceDataInodes,
@@ -1995,8 +2006,10 @@ binder::Status InstalldNativeService::getAppSize(const std::optional<std::string
        calculate_tree_size(obbCodePath, &extStats.codeSize);
    }
    ATRACE_END();

    if (flags & FLAG_USE_QUOTA && appId >= AID_APP_START) {
    // Calculating the app size of the external storage owning app in a manual way, since
    // calculating it through quota apis also includes external media storage in the app storage
    // numbers
    if (flags & FLAG_USE_QUOTA && appId >= AID_APP_START && !ownsExternalStorage(appId)) {
        ATRACE_BEGIN("code");
        for (const auto& codePath : codePaths) {
            calculate_tree_size(codePath, &stats.codeSize, -1,
+22 −6
Original line number Diff line number Diff line
@@ -13,7 +13,10 @@ cc_test {
    test_suites: ["device-tests"],
    clang: true,
    srcs: ["installd_utils_test.cpp"],
    cflags: ["-Wall", "-Werror"],
    cflags: [
        "-Wall",
        "-Werror",
    ],
    shared_libs: [
        "libbase",
        "libutils",
@@ -33,7 +36,10 @@ cc_test {
    test_suites: ["device-tests"],
    clang: true,
    srcs: ["installd_cache_test.cpp"],
    cflags: ["-Wall", "-Werror"],
    cflags: [
        "-Wall",
        "-Werror",
    ],
    shared_libs: [
        "libbase",
        "libbinder",
@@ -75,7 +81,10 @@ cc_test {
    test_suites: ["device-tests"],
    clang: true,
    srcs: ["installd_service_test.cpp"],
    cflags: ["-Wall", "-Werror"],
    cflags: [
        "-Wall",
        "-Werror",
    ],
    shared_libs: [
        "libbase",
        "libbinder",
@@ -84,6 +93,7 @@ cc_test {
        "libprocessgroup",
        "libselinux",
        "libutils",
        "packagemanager_aidl-cpp",
        "server_configurable_flags",
    ],
    static_libs: [
@@ -117,7 +127,10 @@ cc_test {
    test_suites: ["device-tests"],
    clang: true,
    srcs: ["installd_dexopt_test.cpp"],
    cflags: ["-Wall", "-Werror"],
    cflags: [
        "-Wall",
        "-Werror",
    ],
    shared_libs: [
        "libbase",
        "libbinder",
@@ -160,7 +173,10 @@ cc_test {
    test_suites: ["device-tests"],
    clang: true,
    srcs: ["installd_otapreopt_test.cpp"],
    cflags: ["-Wall", "-Werror"],
    cflags: [
        "-Wall",
        "-Werror",
    ],
    shared_libs: [
        "libbase",
        "libcutils",
@@ -169,6 +185,6 @@ cc_test {
    ],
    static_libs: [
        "liblog",
        "libotapreoptparameters"
        "libotapreoptparameters",
    ],
}
+77 −3
Original line number Diff line number Diff line
@@ -18,10 +18,11 @@
#include <string>

#include <fcntl.h>
#include <pwd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/statvfs.h>
#include <sys/stat.h>
#include <sys/statvfs.h>
#include <sys/xattr.h>

#include <android-base/file.h>
@@ -32,8 +33,10 @@
#include <cutils/properties.h>
#include <gtest/gtest.h>

#include "binder_test_utils.h"
#include <android/content/pm/IPackageManagerNative.h>
#include <binder/IServiceManager.h>
#include "InstalldNativeService.h"
#include "binder_test_utils.h"
#include "dexopt.h"
#include "globals.h"
#include "utils.h"
@@ -41,6 +44,34 @@
using android::base::StringPrintf;

namespace android {
std::string get_package_name(uid_t uid) {
    sp<IServiceManager> sm = defaultServiceManager();
    sp<content::pm::IPackageManagerNative> package_mgr;
    if (sm.get() == nullptr) {
        LOG(INFO) << "Cannot find service manager";
    } else {
        sp<IBinder> binder = sm->getService(String16("package_native"));
        if (binder.get() == nullptr) {
            LOG(INFO) << "Cannot find package_native";
        } else {
            package_mgr = interface_cast<content::pm::IPackageManagerNative>(binder);
        }
    }
    // find package name
    std::string pkg;
    if (package_mgr != nullptr) {
        std::vector<std::string> names;
        binder::Status status = package_mgr->getNamesForUids({(int)uid}, &names);
        if (!status.isOk()) {
            LOG(INFO) << "getNamesForUids failed: %s", status.exceptionMessage().c_str();
        } else {
            if (!names[0].empty()) {
                pkg = names[0].c_str();
            }
        }
    }
    return pkg;
}
namespace installd {

constexpr const char* kTestUuid = "TEST";
@@ -247,7 +278,50 @@ TEST_F(ServiceTest, CalculateCache) {
    EXPECT_TRUE(create_cache_path(buf, "/path/to/file.apk", "isa"));
    EXPECT_EQ("/data/dalvik-cache/isa/path@to@file.apk@classes.dex", std::string(buf));
}

TEST_F(ServiceTest, GetAppSize) {
    struct stat s;

    std::string externalPicDir =
            StringPrintf("%s/Pictures", create_data_media_path(nullptr, 0).c_str());
    if (stat(externalPicDir.c_str(), &s) == 0) {
        // fetch the appId from the uid of the external storage owning app
        int32_t externalStorageAppId = multiuser_get_app_id(s.st_uid);
        // Fetch Package Name for the external storage owning app uid
        std::string pkg = get_package_name(s.st_uid);

        std::vector<int64_t> externalStorageSize, externalStorageSizeAfterAddingExternalFile;
        std::vector<int64_t> ceDataInodes;

        std::vector<std::string> codePaths;
        std::vector<std::string> packageNames;
        // set up parameters
        packageNames.push_back(pkg);
        ceDataInodes.push_back(0);
        // initialise the mounts
        service->invalidateMounts();
        // call the getAppSize to get the current size of the external storage owning app
        service->getAppSize(std::nullopt, packageNames, 0, InstalldNativeService::FLAG_USE_QUOTA,
                            externalStorageAppId, ceDataInodes, codePaths, &externalStorageSize);
        // add a file with 20MB size to the external storage
        std::string externalFileLocation =
                StringPrintf("%s/Pictures/%s", getenv("EXTERNAL_STORAGE"), "External.jpg");
        std::string externalFileContentCommand =
                StringPrintf("dd if=/dev/zero of=%s bs=1M count=20", externalFileLocation.c_str());
        system(externalFileContentCommand.c_str());
        // call the getAppSize again to get the new size of the external storage owning app
        service->getAppSize(std::nullopt, packageNames, 0, InstalldNativeService::FLAG_USE_QUOTA,
                            externalStorageAppId, ceDataInodes, codePaths,
                            &externalStorageSizeAfterAddingExternalFile);
        // check that the size before adding the file and after should be the same, as the app size
        // is not changed.
        for (size_t i = 0; i < externalStorageSize.size(); i++) {
            ASSERT_TRUE(externalStorageSize[i] == externalStorageSizeAfterAddingExternalFile[i]);
        }
        // remove the external file
        std::string removeCommand = StringPrintf("rm -f %s", externalFileLocation.c_str());
        system(removeCommand.c_str());
    }
}
static bool mkdirs(const std::string& path, mode_t mode) {
    struct stat sb;
    if (stat(path.c_str(), &sb) != -1 && S_ISDIR(sb.st_mode)) {