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

Commit 27223c51 authored by Samiul Islam's avatar Samiul Islam Committed by Gerrit Code Review
Browse files

Merge changes Ida831e19,I3b74e343,I966c76b0

* changes:
  Rename SupplementalProcess to SdkSandbox
  Stop creating sdk data directories due to boot time regression
  Create supplemental data directories when app data is created
parents c0061923 9c3e8f56
Loading
Loading
Loading
Loading
+75 −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,76 @@ binder::Status InstalldNativeService::createAppDataLocked(
            return error("Failed to prepare profiles for " + packageName);
        }
    }

    // TODO(b/220095381): Due to boot time regression, we have omitted call to
    // createSdkSandboxDataDirectory from here temporarily (unless it's for testing)
    if (uuid_ != nullptr && strcmp(uuid_, "TEST") == 0) {
        auto status = createSdkSandboxDataDirectory(uuid, packageName, userId, appId, previousAppId,
                                                    seInfo, flags);
        if (!status.isOk()) {
            return status;
        }
    }

    return ok();
}

/**
 * Responsible for creating /data/misc_{ce|de}/user/0/sdksandbox/<app-name> directory and other
 * app level sub directories, such as ./shared
 */
binder::Status InstalldNativeService::createSdkSandboxDataDirectory(
        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 sdkSandboxUid = multiuser_get_sdk_sandbox_uid(userId, appId);
    if (sdkSandboxUid == -1) {
        // There no valid sdk sandbox 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>/sdksandbox directory gets created by vold
        // during user creation

        // Prepare the app directory
        auto appPath = create_data_misc_sdk_sandbox_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_sdk_sandbox_shared_path(uuid_, isCeData, userId,
                                                                   packageName.c_str());

        int32_t previousSdkSandboxUid = multiuser_get_sdk_sandbox_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 sdksandbox data"));
        }
        auto status = createAppDataDirs(sharedPath, sdkSandboxUid, &previousSdkSandboxUid, 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 sdksandbox root directory and
        // app directory under it so we can clear contents while CE storage is locked
    }

    return ok();
}

+14 −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,17 @@ 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 createSdkSandboxDataDirectory(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
+121 −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 kTestSdkSandboxUid = multiuser_get_sdk_sandbox_uid(kTestUserId, kTestAppId);

#define FLAG_FORCE InstalldNativeService::FLAG_FORCE

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

class SdkSandboxDataTest : 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/sdksandbox", 0700));
        ASSERT_TRUE(mkdirs("/data/local/tmp/misc_de/0/sdksandbox", 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(SdkSandboxDataTest, 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/sdksandbox/com.foo", kSystemUid, S_IFDIR | 0751);
    CheckFileAccess("misc_ce/0/sdksandbox/com.foo/shared", kTestSdkSandboxUid, S_IFDIR | 0700);
    CheckFileAccess("misc_ce/0/sdksandbox/com.foo/shared/cache", kTestSdkSandboxUid,
                    S_IFDIR | S_ISGID | 0771);
    CheckFileAccess("misc_ce/0/sdksandbox/com.foo/shared/code_cache", kTestSdkSandboxUid,
                    S_IFDIR | S_ISGID | 0771);

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

TEST_F(SdkSandboxDataTest, 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/sdksandbox/com.foo", kSystemUid, S_IFDIR | 0751);

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

TEST_F(SdkSandboxDataTest, 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/sdksandbox/com.foo"));

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

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

TEST_F(UtilsTest, TestSdkSandboxDataPaths) {
    // Ce data paths
    EXPECT_EQ("/data/misc_ce/0/sdksandbox",
              create_data_misc_sdk_sandbox_path(nullptr, /*isCeData=*/true, 0));
    EXPECT_EQ("/data/misc_ce/10/sdksandbox", create_data_misc_sdk_sandbox_path(nullptr, true, 10));

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

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

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

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

    EXPECT_EQ("/data/misc_de/0/sdksandbox/com.foo/shared",
              create_data_misc_sdk_sandbox_shared_path(nullptr, false, 0, "com.foo"));
    EXPECT_EQ("/data/misc_de/10/sdksandbox/com.foo/shared",
              create_data_misc_sdk_sandbox_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 sdk_sandbox data for all apps will be stored.
 * E.g. /data/misc_ce/0/sdksandbox
 */
std::string create_data_misc_sdk_sandbox_path(const char* uuid, bool isCeData, userid_t user) {
    std::string data(create_data_path(uuid));
    if (isCeData) {
        return StringPrintf("%s/misc_ce/%d/sdksandbox", data.c_str(), user);
    } else {
        return StringPrintf("%s/misc_de/%d/sdksandbox", 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/sdksandbox/<app-name>
 */
std::string create_data_misc_sdk_sandbox_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_sdk_sandbox_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/sdksandbox/<app-name>/shared
 */
std::string create_data_misc_sdk_sandbox_shared_path(const char* volume_uuid, bool isCeData,
                                                     userid_t user, const char* package_name) {
    return StringPrintf("%s/shared",
                        create_data_misc_sdk_sandbox_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