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

Commit 7fa4f884 authored by Shikha Malhotra's avatar Shikha Malhotra
Browse files

Added support to calculate storage using project ids on devices whose

user data is wiped and their add directories are created using project
id
Bug: b/215154615
Test: atest StorageHostTest
Test: atest tests/installd_service_test.cpp
Change-Id: Ib29af7c4c0e80d5b8902899b38de41a807e1cd72
Merged-In: Idfe262d5606a4f577587e75e4a29fdb55c021a37
parent 0b272119
Loading
Loading
Loading
Loading
+111 −50
Original line number Original line Diff line number Diff line
@@ -55,6 +55,7 @@
#include <cutils/fs.h>
#include <cutils/fs.h>
#include <cutils/properties.h>
#include <cutils/properties.h>
#include <cutils/sched_policy.h>
#include <cutils/sched_policy.h>
#include <linux/quota.h>
#include <log/log.h> // TODO: Move everything to base/logging.
#include <log/log.h> // TODO: Move everything to base/logging.
#include <logwrap/logwrap.h>
#include <logwrap/logwrap.h>
#include <private/android_filesystem_config.h>
#include <private/android_filesystem_config.h>
@@ -458,14 +459,37 @@ done:
    return res;
    return res;
}
}


static int prepare_app_dir(const std::string& path, mode_t target_mode, uid_t uid, gid_t gid) {
static bool internal_storage_has_project_id() {
    // The following path is populated in setFirstBoot, so if this file is present
    // then project ids can be used.

    auto using_project_ids =
            StringPrintf("%smisc/installd/using_project_ids", android_data_dir.c_str());
    return access(using_project_ids.c_str(), F_OK) == 0;
}

static int prepare_app_dir(const std::string& path, mode_t target_mode, uid_t uid, gid_t gid,
                           long project_id) {
    if (fs_prepare_dir_strict(path.c_str(), target_mode, uid, gid) != 0) {
    if (fs_prepare_dir_strict(path.c_str(), target_mode, uid, gid) != 0) {
        PLOG(ERROR) << "Failed to prepare " << path;
        PLOG(ERROR) << "Failed to prepare " << path;
        return -1;
        return -1;
    }
    }
    if (internal_storage_has_project_id()) {
        return set_quota_project_id(path, project_id, true);
    }
    return 0;
    return 0;
}
}


static int prepare_app_cache_dir(const std::string& parent, const char* name, mode_t target_mode,
                                 uid_t uid, gid_t gid, long project_id) {
    auto path = StringPrintf("%s/%s", parent.c_str(), name);
    int ret = prepare_app_cache_dir(parent, name, target_mode, uid, gid);
    if (ret == 0 && internal_storage_has_project_id()) {
        return set_quota_project_id(path, project_id, true);
    }
    return ret;
}

static bool prepare_app_profile_dir(const std::string& packageName, int32_t appId, int32_t userId) {
static bool prepare_app_profile_dir(const std::string& packageName, int32_t appId, int32_t userId) {
    if (!property_get_bool("dalvik.vm.usejitprofiles", false)) {
    if (!property_get_bool("dalvik.vm.usejitprofiles", false)) {
        return true;
        return true;
@@ -625,9 +649,11 @@ static binder::Status createAppDataDirs(const std::string& path, int32_t uid, in
    }
    }


    // Prepare only the parent app directory
    // Prepare only the parent app directory
    if (prepare_app_dir(path, targetMode, uid, gid) ||
    long project_id_app = get_project_id(uid, PROJECT_ID_APP_START);
        prepare_app_cache_dir(path, "cache", 02771, uid, cacheGid) ||
    long project_id_cache_app = get_project_id(uid, PROJECT_ID_APP_CACHE_START);
        prepare_app_cache_dir(path, "code_cache", 02771, uid, cacheGid)) {
    if (prepare_app_dir(path, targetMode, uid, gid, project_id_app) ||
        prepare_app_cache_dir(path, "cache", 02771, uid, cacheGid, project_id_cache_app) ||
        prepare_app_cache_dir(path, "code_cache", 02771, uid, cacheGid, project_id_cache_app)) {
        return error("Failed to prepare " + path);
        return error("Failed to prepare " + path);
    }
    }


@@ -773,7 +799,7 @@ binder::Status InstalldNativeService::createSdkSandboxDataPackageDirectory(
        LOG(DEBUG) << "Creating app-level sdk data directory: " << packagePath;
        LOG(DEBUG) << "Creating app-level sdk data directory: " << packagePath;
#endif
#endif


        if (prepare_app_dir(packagePath, 0751, AID_SYSTEM, AID_SYSTEM)) {
        if (prepare_app_dir(packagePath, 0751, AID_SYSTEM, AID_SYSTEM, 0)) {
            return error("Failed to prepare " + packagePath);
            return error("Failed to prepare " + packagePath);
        }
        }


@@ -2088,22 +2114,66 @@ static std::string toString(std::vector<int64_t> values) {
    return res.str();
    return res.str();
}
}
#endif
#endif
// On devices without sdcardfs, if internal and external are on
// the same volume, a uid such as u0_a123 is used for both
// internal and external storage; therefore, subtract that
// amount from internal to make sure we don't count it double.
// This needs to happen for data, cache and OBB
static void deductDoubleSpaceIfNeeded(stats* stats, int64_t doubleSpaceToBeDeleted, uid_t uid,
                                      const std::string& uuid) {
    if (!supports_sdcardfs()) {
        stats->dataSize -= doubleSpaceToBeDeleted;
        long obbProjectId = get_project_id(uid, PROJECT_ID_EXT_OBB_START);
        int64_t appObbSize = GetOccupiedSpaceForProjectId(uuid, obbProjectId);
        stats->dataSize -= appObbSize;
    }
}


static void collectQuotaStats(const std::string& uuid, int32_t userId,
static void collectQuotaStats(const std::string& uuid, int32_t userId,
        int32_t appId, struct stats* stats, struct stats* extStats) {
        int32_t appId, struct stats* stats, struct stats* extStats) {
    int64_t space;
    int64_t space, doubleSpaceToBeDeleted = 0;
    uid_t uid = multiuser_get_uid(userId, appId);
    uid_t uid = multiuser_get_uid(userId, appId);
    static const bool supportsProjectId = internal_storage_has_project_id();

    if (extStats != nullptr) {
        space = get_occupied_app_space_external(uuid, userId, appId);

        if (space != -1) {
            extStats->dataSize += space;
            doubleSpaceToBeDeleted += space;
        }

        space = get_occupied_app_cache_space_external(uuid, userId, appId);
        if (space != -1) {
            extStats->dataSize += space; // cache counts for "data"
            extStats->cacheSize += space;
            doubleSpaceToBeDeleted += space;
        }
    }

    if (stats != nullptr) {
    if (stats != nullptr) {
        if (!supportsProjectId) {
            if ((space = GetOccupiedSpaceForUid(uuid, uid)) != -1) {
            if ((space = GetOccupiedSpaceForUid(uuid, uid)) != -1) {
                stats->dataSize += space;
                stats->dataSize += space;
            }
            }

            deductDoubleSpaceIfNeeded(stats, doubleSpaceToBeDeleted, uid, uuid);
            int cacheGid = multiuser_get_cache_gid(userId, appId);
            int cacheGid = multiuser_get_cache_gid(userId, appId);
            if (cacheGid != -1) {
            if (cacheGid != -1) {
                if ((space = GetOccupiedSpaceForGid(uuid, cacheGid)) != -1) {
                if ((space = GetOccupiedSpaceForGid(uuid, cacheGid)) != -1) {
                    stats->cacheSize += space;
                    stats->cacheSize += space;
                }
                }
            }
            }
        } else {
            long projectId = get_project_id(uid, PROJECT_ID_APP_START);
            if ((space = GetOccupiedSpaceForProjectId(uuid, projectId)) != -1) {
                stats->dataSize += space;
            }
            projectId = get_project_id(uid, PROJECT_ID_APP_CACHE_START);
            if ((space = GetOccupiedSpaceForProjectId(uuid, projectId)) != -1) {
                stats->cacheSize += space;
                stats->dataSize += space;
            }
        }


        int sharedGid = multiuser_get_shared_gid(0, appId);
        int sharedGid = multiuser_get_shared_gid(0, appId);
        if (sharedGid != -1) {
        if (sharedGid != -1) {
@@ -2112,47 +2182,6 @@ static void collectQuotaStats(const std::string& uuid, int32_t userId,
            }
            }
        }
        }
    }
    }

    if (extStats != nullptr) {
        static const bool supportsSdCardFs = supports_sdcardfs();
        space = get_occupied_app_space_external(uuid, userId, appId);

        if (space != -1) {
            extStats->dataSize += space;
            if (!supportsSdCardFs && stats != nullptr) {
                // On devices without sdcardfs, if internal and external are on
                // the same volume, a uid such as u0_a123 is used for
                // application dirs on both internal and external storage;
                // therefore, substract that amount from internal to make sure
                // we don't count it double.
                stats->dataSize -= space;
            }
        }

        space = get_occupied_app_cache_space_external(uuid, userId, appId);
        if (space != -1) {
            extStats->dataSize += space; // cache counts for "data"
            extStats->cacheSize += space;
            if (!supportsSdCardFs && stats != nullptr) {
                // On devices without sdcardfs, if internal and external are on
                // the same volume, a uid such as u0_a123 is used for both
                // internal and external storage; therefore, substract that
                // amount from internal to make sure we don't count it double.
                stats->dataSize -= space;
            }
        }

        if (!supportsSdCardFs && stats != nullptr) {
            // On devices without sdcardfs, the UID of OBBs on external storage
            // matches the regular app UID (eg u0_a123); therefore, to avoid
            // OBBs being include in stats->dataSize, compute the OBB size for
            // this app, and substract it from the size reported on internal
            // storage
            long obbProjectId = uid - AID_APP_START + PROJECT_ID_EXT_OBB_START;
            int64_t appObbSize = GetOccupiedSpaceForProjectId(uuid, obbProjectId);
            stats->dataSize -= appObbSize;
        }
    }
}
}


static void collectManualStats(const std::string& path, struct stats* stats) {
static void collectManualStats(const std::string& path, struct stats* stats) {
@@ -2273,6 +2302,11 @@ static void collectManualExternalStatsForUser(const std::string& path, struct st
    fts_close(fts);
    fts_close(fts);
}
}
static bool ownsExternalStorage(int32_t appId) {
static bool ownsExternalStorage(int32_t appId) {
    // if project id calculation is supported then, there is no need to
    // calculate in a different way and project_id based calculation can work
    if (internal_storage_has_project_id()) {
        return false;
    }
    //  Fetch external storage owner appid  and check if it is the same as the
    //  Fetch external storage owner appid  and check if it is the same as the
    //  current appId whose size is calculated
    //  current appId whose size is calculated
    struct stat s;
    struct stat s;
@@ -3264,6 +3298,33 @@ binder::Status InstalldNativeService::hashSecondaryDexFile(
    return result ? ok() : error();
    return result ? ok() : error();
}
}


bool check_if_ioctl_feature_is_supported() {
    bool result = false;
    auto temp_path = StringPrintf("%smisc/installd/ioctl_check", android_data_dir.c_str());
    if (access(temp_path.c_str(), F_OK) != 0) {
        open(temp_path.c_str(), O_CREAT | O_TRUNC | O_RDWR | O_CLOEXEC, 0644);
        result = set_quota_project_id(temp_path, 0, true) == 0;
        // delete the temp file
        // remove the external file
        remove(temp_path.c_str());
    }
    return result;
}

binder::Status InstalldNativeService::setFirstBoot() {
    ENFORCE_UID(AID_SYSTEM);
    std::lock_guard<std::recursive_mutex> lock(mMountsLock);
    std::string uuid;
    if (GetOccupiedSpaceForProjectId(uuid, 0) != -1 && check_if_ioctl_feature_is_supported()) {
        auto first_boot_path =
                StringPrintf("%smisc/installd/using_project_ids", android_data_dir.c_str());
        if (access(first_boot_path.c_str(), F_OK) != 0) {
            open(first_boot_path.c_str(), O_CREAT | O_TRUNC | O_RDWR | O_CLOEXEC, 0644);
        }
    }
    return ok();
}

binder::Status InstalldNativeService::invalidateMounts() {
binder::Status InstalldNativeService::invalidateMounts() {
    ENFORCE_UID(AID_SYSTEM);
    ENFORCE_UID(AID_SYSTEM);
    std::lock_guard<std::recursive_mutex> lock(mMountsLock);
    std::lock_guard<std::recursive_mutex> lock(mMountsLock);
+1 −0
Original line number Original line Diff line number Diff line
@@ -169,6 +169,7 @@ public:
        int32_t storageFlag, std::vector<uint8_t>* _aidl_return);
        int32_t storageFlag, std::vector<uint8_t>* _aidl_return);


    binder::Status invalidateMounts();
    binder::Status invalidateMounts();
    binder::Status setFirstBoot();
    binder::Status isQuotaSupported(const std::optional<std::string>& volumeUuid,
    binder::Status isQuotaSupported(const std::optional<std::string>& volumeUuid,
            bool* _aidl_return);
            bool* _aidl_return);
    binder::Status tryMountDataMirror(const std::optional<std::string>& volumeUuid);
    binder::Status tryMountDataMirror(const std::optional<std::string>& volumeUuid);
+1 −1
Original line number Original line Diff line number Diff line
@@ -20,7 +20,7 @@ package android.os;
interface IInstalld {
interface IInstalld {
    void createUserData(@nullable @utf8InCpp String uuid, int userId, int userSerial, int flags);
    void createUserData(@nullable @utf8InCpp String uuid, int userId, int userSerial, int flags);
    void destroyUserData(@nullable @utf8InCpp String uuid, int userId, int flags);
    void destroyUserData(@nullable @utf8InCpp String uuid, int userId, int flags);

    void setFirstBoot();
    android.os.CreateAppDataResult createAppData(in android.os.CreateAppDataArgs args);
    android.os.CreateAppDataResult createAppData(in android.os.CreateAppDataArgs args);
    android.os.CreateAppDataResult[] createAppDataBatched(in android.os.CreateAppDataArgs[] args);
    android.os.CreateAppDataResult[] createAppDataBatched(in android.os.CreateAppDataArgs[] args);


+76 −1
Original line number Original line Diff line number Diff line
@@ -463,7 +463,7 @@ TEST_F(ServiceTest, CalculateCache) {
    EXPECT_TRUE(create_cache_path(buf, "/path/to/file.apk", "isa"));
    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));
    EXPECT_EQ("/data/dalvik-cache/isa/path@to@file.apk@classes.dex", std::string(buf));
}
}
TEST_F(ServiceTest, GetAppSize) {
TEST_F(ServiceTest, GetAppSizeManualForMedia) {
    struct stat s;
    struct stat s;


    std::string externalPicDir =
    std::string externalPicDir =
@@ -507,6 +507,81 @@ TEST_F(ServiceTest, GetAppSize) {
        system(removeCommand.c_str());
        system(removeCommand.c_str());
    }
    }
}
}
TEST_F(ServiceTest, GetAppSizeProjectID_UID) {
    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, externalStorageSizeAfterAddingCacheFile;
        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();
        auto using_project_ids =
                StringPrintf("%smisc/installd/using_project_ids", android_data_dir.c_str());
        bool usingProjectIds = access(using_project_ids.c_str(), F_OK) == 0;
        if (!usingProjectIds) {
            service->setFirstBoot();
        }
        // 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 externalStorageCacheDir =
                StringPrintf("%s/%s/cache", create_data_user_ce_path(nullptr, 0).c_str(),
                             pkg.c_str());
        std::string cacheFileLocation =
                StringPrintf("%s/%s", externalStorageCacheDir.c_str(), "External.jpg");
        std::string externalFileContentCommand =
                StringPrintf("dd if=/dev/zero of=%s bs=1M count=20", cacheFileLocation.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,
                            &externalStorageSizeAfterAddingCacheFile);
        // check that the size of cache and data increases when cache file is added
        int64_t sizeDiffData = externalStorageSizeAfterAddingCacheFile[1] - externalStorageSize[1];
        int64_t sizeDiffCache = externalStorageSizeAfterAddingCacheFile[2] - externalStorageSize[2];
        ASSERT_TRUE(sizeDiffData == sizeDiffCache);
        // remove the external file
        std::string removeCommand = StringPrintf("rm -f %s", cacheFileLocation.c_str());
        system(removeCommand.c_str());
        // remove the setFirstBoot setting
        std::string removeCommand2 = "rm -f /data/misc/installd/using_project_ids";
        system(removeCommand2.c_str());
        // Do now without project id
        std::vector<int64_t> sizeWithUID, sizeWithUIDAfterAddingCacheFile;
        // 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, &sizeWithUID);
        // add a file with 20MB size to the external storage
        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,
                            &sizeWithUIDAfterAddingCacheFile);
        // check that the size of cache and data increases when cache file is added
        sizeDiffData = sizeWithUIDAfterAddingCacheFile[1] - sizeWithUID[1];
        sizeDiffCache = sizeWithUIDAfterAddingCacheFile[2] - sizeWithUID[2];
        ASSERT_TRUE(sizeDiffData == sizeDiffCache);
        // remove the external file
        system(removeCommand.c_str());
        // reset the using_project_id if it was initially set
        if (usingProjectIds) {
            service->setFirstBoot();
        }
    }
}
TEST_F(ServiceTest, GetAppSizeWrongSizes) {
TEST_F(ServiceTest, GetAppSizeWrongSizes) {
    int32_t externalStorageAppId = -1;
    int32_t externalStorageAppId = -1;
    std::vector<int64_t> externalStorageSize;
    std::vector<int64_t> externalStorageSize;
+38 −0
Original line number Original line Diff line number Diff line
@@ -37,6 +37,7 @@
#include <android-base/unique_fd.h>
#include <android-base/unique_fd.h>
#include <cutils/fs.h>
#include <cutils/fs.h>
#include <cutils/properties.h>
#include <cutils/properties.h>
#include <linux/fs.h>
#include <log/log.h>
#include <log/log.h>
#include <private/android_filesystem_config.h>
#include <private/android_filesystem_config.h>
#include <private/android_projectid_config.h>
#include <private/android_projectid_config.h>
@@ -434,7 +435,44 @@ std::vector<userid_t> get_known_users(const char* volume_uuid) {


    return users;
    return users;
}
}
long get_project_id(uid_t uid, long start_project_id_range) {
    return uid - AID_APP_START + start_project_id_range;
}

int set_quota_project_id(const std::string& path, long project_id, bool set_inherit) {
    struct fsxattr fsx;
    android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_CLOEXEC)));
    if (fd == -1) {
        PLOG(ERROR) << "Failed to open " << path << " to set project id.";
        return -1;
    }

    if (ioctl(fd, FS_IOC_FSGETXATTR, &fsx) == -1) {
        PLOG(ERROR) << "Failed to get extended attributes for " << path << " to get project id.";
        return -1;
    }

    fsx.fsx_projid = project_id;
    if (ioctl(fd, FS_IOC_FSSETXATTR, &fsx) == -1) {
        PLOG(ERROR) << "Failed to set project id on " << path;
        return -1;
    }
    if (set_inherit) {
        unsigned int flags;
        if (ioctl(fd, FS_IOC_GETFLAGS, &flags) == -1) {
            PLOG(ERROR) << "Failed to get flags for " << path << " to set project id inheritance.";
            return -1;
        }


        flags |= FS_PROJINHERIT_FL;

        if (ioctl(fd, FS_IOC_SETFLAGS, &flags) == -1) {
            PLOG(ERROR) << "Failed to set flags for " << path << " to set project id inheritance.";
            return -1;
        }
    }
    return 0;
}
int calculate_tree_size(const std::string& path, int64_t* size,
int calculate_tree_size(const std::string& path, int64_t* size,
        int32_t include_gid, int32_t exclude_gid, bool exclude_apps) {
        int32_t include_gid, int32_t exclude_gid, bool exclude_apps) {
    FTS *fts;
    FTS *fts;
Loading