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

Commit bfd4f600 authored by Samiul Islam's avatar Samiul Islam Committed by Automerger Merge Worker
Browse files

Create supplemental data directories when app data is created am: b911bc6a am: 09b84f89

Original change: https://android-review.googlesource.com/c/platform/frameworks/native/+/2006950

Change-Id: I2193d8edf0aca38cf00aeb98d42245ca9a757211
parents 481d9e26 09b84f89
Loading
Loading
Loading
Loading
+73 −4
Original line number Diff line number Diff line
@@ -18,13 +18,9 @@

#define ATRACE_TAG ATRACE_TAG_PACKAGE_MANAGER

#include <algorithm>
#include <errno.h>
#include <fstream>
#include <fts.h>
#include <functional>
#include <inttypes.h>
#include <regex>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -40,6 +36,11 @@
#include <sys/wait.h>
#include <sys/xattr.h>
#include <unistd.h>
#include <algorithm>
#include <filesystem>
#include <fstream>
#include <functional>
#include <regex>

#include <android-base/file.h>
#include <android-base/logging.h>
@@ -720,6 +721,74 @@ binder::Status InstalldNativeService::createAppDataLocked(
            return error("Failed to prepare profiles for " + packageName);
        }
    }

    {
        auto status = createAppDirectoryForSupplementalData(uuid, packageName, userId, appId,
                                                            previousAppId, seInfo, flags);
        if (!status.isOk()) {
            return status;
        }
    }

    return ok();
}

/**
 * Responsible for creating /data/user/0/supplemental/<app-name> directory and other
 * app level sub directories, such as ./shared
 */
binder::Status InstalldNativeService::createAppDirectoryForSupplementalData(
        const std::optional<std::string>& uuid, const std::string& packageName, int32_t userId,
        int32_t appId, int32_t previousAppId, const std::string& seInfo, int32_t flags) {
    int32_t supplementalUid = multiuser_get_supplemental_uid(userId, appId);
    if (supplementalUid == -1) {
        // There no valid supplemental process for this app. Skip creation of data directory
        return ok();
    }

    // TODO(b/211763739): what if uuid is not nullptr or TEST?
    const char* uuid_ = uuid ? uuid->c_str() : nullptr;

    constexpr int storageFlags[2] = {FLAG_STORAGE_CE, FLAG_STORAGE_DE};
    for (int i = 0; i < 2; i++) {
        int currentFlag = storageFlags[i];
        if ((flags & currentFlag) == 0) {
            continue;
        }
        bool isCeData = (currentFlag == FLAG_STORAGE_CE);

        // /data/misc_{ce,de}/<user-id>/supplemental directory gets created by vold
        // during user creation

        // Prepare the app directory
        auto appPath = create_data_misc_supplemental_package_path(uuid_, isCeData, userId,
                                                                  packageName.c_str());
        if (prepare_app_dir(appPath, 0751, AID_SYSTEM)) {
            return error("Failed to prepare " + appPath);
        }

        // Now prepare the shared directory which will be accessible by all codes
        auto sharedPath = create_data_misc_supplemental_shared_path(uuid_, isCeData, userId,
                                                                    packageName.c_str());

        int32_t previousSupplementalUid = multiuser_get_supplemental_uid(userId, previousAppId);
        int32_t cacheGid = multiuser_get_cache_gid(userId, appId);
        if (cacheGid == -1) {
            return exception(binder::Status::EX_ILLEGAL_STATE,
                             StringPrintf("cacheGid cannot be -1 for supplemental data"));
        }
        auto status = createAppDataDirs(sharedPath, supplementalUid, &previousSupplementalUid,
                                        cacheGid, seInfo, 0700);
        if (!status.isOk()) {
            return status;
        }

        // TODO(b/211763739): We also need to handle art profile creations

        // TODO(b/211763739): And return the CE inode of the supplemental root directory and
        // app directory under it so we can clear contents while CE storage is locked
    }

    return ok();
}

+15 −8
Original line number Diff line number Diff line
@@ -47,14 +47,9 @@ public:
            int32_t flags);

    binder::Status createAppData(const std::optional<std::string>& uuid,
            const std::string& packageName, int32_t userId, int32_t flags, int32_t appId,
            int32_t previousAppId, const std::string& seInfo, int32_t targetSdkVersion,
            int64_t* _aidl_return);
    binder::Status createAppDataLocked(const std::optional<std::string>& uuid,
                                       const std::string& packageName, int32_t userId,
                                       int32_t flags, int32_t appId, int32_t previousAppId,
                                       const std::string& seInfo, int32_t targetSdkVersion,
                                       int64_t* _aidl_return);
                                 const std::string& packageName, int32_t userId, int32_t flags,
                                 int32_t appId, int32_t previousAppId, const std::string& seInfo,
                                 int32_t targetSdkVersion, int64_t* _aidl_return);

    binder::Status createAppData(
            const android::os::CreateAppDataArgs& args,
@@ -202,6 +197,18 @@ private:
    std::unordered_map<uid_t, int64_t> mCacheQuotas;

    std::string findDataMediaPath(const std::optional<std::string>& uuid, userid_t userid);

    binder::Status createAppDataLocked(const std::optional<std::string>& uuid,
                                       const std::string& packageName, int32_t userId,
                                       int32_t flags, int32_t appId, int32_t previousAppId,
                                       const std::string& seInfo, int32_t targetSdkVersion,
                                       int64_t* _aidl_return);

    binder::Status createAppDirectoryForSupplementalData(const std::optional<std::string>& uuid,
                                                         const std::string& packageName,
                                                         int32_t userId, int32_t appId,
                                                         int32_t previousAppId,
                                                         const std::string& seInfo, int32_t flags);
};

}  // namespace installd
+123 −2
Original line number Diff line number Diff line
@@ -74,8 +74,14 @@ std::string get_package_name(uid_t uid) {
}
namespace installd {

constexpr const char* kTestUuid = "TEST";
constexpr const char* kTestPath = "/data/local/tmp/user/0";
static constexpr const char* kTestUuid = "TEST";
static constexpr const char* kTestPath = "/data/local/tmp/user/0";
static constexpr const uid_t kSystemUid = 1000;
static constexpr const int32_t kTestUserId = 0;
static constexpr const uid_t kTestAppId = 19999;

const gid_t kTestAppUid = multiuser_get_uid(kTestUserId, kTestAppId);
const uid_t kTestAppSupplementalUid = multiuser_get_supplemental_uid(kTestUserId, kTestAppId);

#define FLAG_FORCE InstalldNativeService::FLAG_FORCE

@@ -943,5 +949,120 @@ TEST_F(AppDataSnapshotTest, RestoreAppDataSnapshot_WrongVolumeUuid) {
          "com.foo", 10000, "", 0, 41, FLAG_STORAGE_DE));
}

class AppSupplementalDataTest : public testing::Test {
public:
    void CheckFileAccess(const std::string& path, uid_t uid, mode_t mode) {
        const auto fullPath = "/data/local/tmp/" + path;
        ASSERT_TRUE(exists(fullPath.c_str())) << "For path: " << fullPath;
        struct stat st;
        ASSERT_EQ(0, stat(fullPath.c_str(), &st));
        ASSERT_EQ(uid, st.st_uid) << "For path: " << fullPath;
        ASSERT_EQ(uid, st.st_gid) << "For path: " << fullPath;
        ASSERT_EQ(mode, st.st_mode) << "For path: " << fullPath;
    }

    bool exists(const char* path) { return ::access(path, F_OK) == 0; }

    // Creates a default CreateAppDataArgs object
    android::os::CreateAppDataArgs createAppDataArgs() {
        android::os::CreateAppDataArgs args;
        args.uuid = kTestUuid;
        args.packageName = "com.foo";
        args.userId = kTestUserId;
        args.appId = kTestAppId;
        args.seInfo = "default";
        args.flags = FLAG_STORAGE_CE | FLAG_STORAGE_DE;
        return args;
    }

protected:
    InstalldNativeService* service;

    virtual void SetUp() {
        setenv("ANDROID_LOG_TAGS", "*:v", 1);
        android::base::InitLogging(nullptr);

        service = new InstalldNativeService();
        clearAppData();
        ASSERT_TRUE(mkdirs("/data/local/tmp/user/0", 0700));
        ASSERT_TRUE(mkdirs("/data/local/tmp/user_de/0", 0700));
        ASSERT_TRUE(mkdirs("/data/local/tmp/misc_ce/0/supplemental", 0700));
        ASSERT_TRUE(mkdirs("/data/local/tmp/misc_de/0/supplemental", 0700));

        init_globals_from_data_and_root();
    }

    virtual void TearDown() {
        delete service;
        clearAppData();
    }

private:
    void clearAppData() {
        ASSERT_EQ(0, delete_dir_contents_and_dir("/data/local/tmp/user_de", true));
        ASSERT_EQ(0, delete_dir_contents_and_dir("/data/local/tmp/misc_ce", true));
        ASSERT_EQ(0, delete_dir_contents_and_dir("/data/local/tmp/misc_de", true));
        ASSERT_EQ(0, delete_dir_contents_and_dir("/data/local/tmp/user_de", true));
    }
};

TEST_F(AppSupplementalDataTest, CreateAppData_CreatesSupplementalAppData) {
    android::os::CreateAppDataResult result;
    android::os::CreateAppDataArgs args = createAppDataArgs();
    args.packageName = "com.foo";
    args.flags = FLAG_STORAGE_CE | FLAG_STORAGE_DE;

    // Create the app user data.
    ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));

    CheckFileAccess("misc_ce/0/supplemental/com.foo", kSystemUid, S_IFDIR | 0751);
    CheckFileAccess("misc_ce/0/supplemental/com.foo/shared", kTestAppSupplementalUid,
                    S_IFDIR | 0700);
    CheckFileAccess("misc_ce/0/supplemental/com.foo/shared/cache", kTestAppSupplementalUid,
                    S_IFDIR | S_ISGID | 0771);
    CheckFileAccess("misc_ce/0/supplemental/com.foo/shared/code_cache", kTestAppSupplementalUid,
                    S_IFDIR | S_ISGID | 0771);

    CheckFileAccess("misc_de/0/supplemental/com.foo", kSystemUid, S_IFDIR | 0751);
    CheckFileAccess("misc_de/0/supplemental/com.foo/shared", kTestAppSupplementalUid,
                    S_IFDIR | 0700);
    CheckFileAccess("misc_de/0/supplemental/com.foo/shared/cache", kTestAppSupplementalUid,
                    S_IFDIR | S_ISGID | 0771);
    CheckFileAccess("misc_de/0/supplemental/com.foo/shared/code_cache", kTestAppSupplementalUid,
                    S_IFDIR | S_ISGID | 0771);
}

TEST_F(AppSupplementalDataTest, CreateAppData_CreatesSupplementalAppData_WithoutDeFlag) {
    android::os::CreateAppDataResult result;
    android::os::CreateAppDataArgs args = createAppDataArgs();
    args.packageName = "com.foo";
    args.flags = FLAG_STORAGE_CE;

    // Create the app user data.
    ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));

    // Only CE paths should exist
    CheckFileAccess("misc_ce/0/supplemental/com.foo", kSystemUid, S_IFDIR | 0751);

    // DE paths should not exist
    ASSERT_FALSE(exists("/data/local/tmp/misc_de/0/supplemental/com.foo"));
}

TEST_F(AppSupplementalDataTest, CreateAppData_CreatesSupplementalAppData_WithoutCeFlag) {
    android::os::CreateAppDataResult result;
    android::os::CreateAppDataArgs args = createAppDataArgs();
    args.packageName = "com.foo";
    args.flags = FLAG_STORAGE_DE;

    // Create the app user data.
    ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));

    // CE paths should not exist
    ASSERT_FALSE(exists("/data/local/tmp/misc_ce/0/supplemental/com.foo"));

    // Only DE paths should exist
    CheckFileAccess("misc_de/0/supplemental/com.foo", kSystemUid, S_IFDIR | 0751);
}

}  // namespace installd
}  // namespace android
+34 −0
Original line number Diff line number Diff line
@@ -658,6 +658,40 @@ TEST_F(UtilsTest, TestCreateDirIfNeeded) {
    ASSERT_NE(0, create_dir_if_needed("/data/local/tmp/user/0/bar/baz", 0700));
}

TEST_F(UtilsTest, TestSupplementalDataPaths) {
    // Ce data paths
    EXPECT_EQ("/data/misc_ce/0/supplemental",
              create_data_misc_supplemental_path(nullptr, /*isCeData=*/true, 0));
    EXPECT_EQ("/data/misc_ce/10/supplemental",
              create_data_misc_supplemental_path(nullptr, true, 10));

    EXPECT_EQ("/data/misc_ce/0/supplemental/com.foo",
              create_data_misc_supplemental_package_path(nullptr, true, 0, "com.foo"));
    EXPECT_EQ("/data/misc_ce/10/supplemental/com.foo",
              create_data_misc_supplemental_package_path(nullptr, true, 10, "com.foo"));

    EXPECT_EQ("/data/misc_ce/0/supplemental/com.foo/shared",
              create_data_misc_supplemental_shared_path(nullptr, true, 0, "com.foo"));
    EXPECT_EQ("/data/misc_ce/10/supplemental/com.foo/shared",
              create_data_misc_supplemental_shared_path(nullptr, true, 10, "com.foo"));

    // De data paths
    EXPECT_EQ("/data/misc_de/0/supplemental",
              create_data_misc_supplemental_path(nullptr, /*isCeData=*/false, 0));
    EXPECT_EQ("/data/misc_de/10/supplemental",
              create_data_misc_supplemental_path(nullptr, false, 10));

    EXPECT_EQ("/data/misc_de/0/supplemental/com.foo",
              create_data_misc_supplemental_package_path(nullptr, false, 0, "com.foo"));
    EXPECT_EQ("/data/misc_de/10/supplemental/com.foo",
              create_data_misc_supplemental_package_path(nullptr, false, 10, "com.foo"));

    EXPECT_EQ("/data/misc_de/0/supplemental/com.foo/shared",
              create_data_misc_supplemental_shared_path(nullptr, false, 0, "com.foo"));
    EXPECT_EQ("/data/misc_de/10/supplemental/com.foo/shared",
              create_data_misc_supplemental_shared_path(nullptr, false, 10, "com.foo"));
}

TEST_F(UtilsTest, WaitChild) {
    pid_t pid = fork();
    if (pid == 0) {
+37 −0
Original line number Diff line number Diff line
@@ -197,6 +197,43 @@ std::string create_data_user_de_path(const char* volume_uuid, userid_t userid) {
    return StringPrintf("%s/user_de/%u", data.c_str(), userid);
}

/**
 * Create the path name where supplemental data for all apps will be stored.
 * E.g. /data/misc_ce/0/supplemental
 */
std::string create_data_misc_supplemental_path(const char* uuid, bool isCeData, userid_t user) {
    std::string data(create_data_path(uuid));
    if (isCeData) {
        return StringPrintf("%s/misc_ce/%d/supplemental", data.c_str(), user);
    } else {
        return StringPrintf("%s/misc_de/%d/supplemental", data.c_str(), user);
    }
}

/**
 * Create the path name where code data for all codes in a particular app will be stored.
 * E.g. /data/misc_ce/0/supplemental/<app-name>
 */
std::string create_data_misc_supplemental_package_path(const char* volume_uuid, bool isCeData,
                                                       userid_t user, const char* package_name) {
    check_package_name(package_name);
    return StringPrintf("%s/%s",
                        create_data_misc_supplemental_path(volume_uuid, isCeData, user).c_str(),
                        package_name);
}

/**
 * Create the path name where shared code data for a particular app will be stored.
 * E.g. /data/misc_ce/0/supplemental/<app-name>/shared
 */
std::string create_data_misc_supplemental_shared_path(const char* volume_uuid, bool isCeData,
                                                      userid_t user, const char* package_name) {
    return StringPrintf("%s/shared",
                        create_data_misc_supplemental_package_path(volume_uuid, isCeData, user,
                                                                   package_name)
                                .c_str());
}

std::string create_data_misc_ce_rollback_base_path(const char* volume_uuid, userid_t user) {
    return StringPrintf("%s/misc_ce/%u/rollback", create_data_path(volume_uuid).c_str(), user);
}
Loading