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

Commit 8a3c8b1a authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "installd: parameterize user data snapshots with snapshot_id"

parents 01f59ce0 ad5da1ee
Loading
Loading
Loading
Loading
+49 −26
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@
#include <sys/xattr.h>
#include <unistd.h>

#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/properties.h>
#include <android-base/scopeguard.h>
@@ -80,6 +81,8 @@ namespace installd {
// An uuid used in unit tests.
static constexpr const char* kTestUuid = "TEST";

static constexpr const mode_t kRollbackFolderMode = 0700;

static constexpr const char* kCpPath = "/system/bin/cp";
static constexpr const char* kXattrDefault = "user.default";

@@ -784,8 +787,8 @@ static int32_t copy_directory_recursive(const char* from, const char* to) {

binder::Status InstalldNativeService::snapshotAppData(
        const std::unique_ptr<std::string>& volumeUuid,
        const std::string& packageName, int32_t user, int32_t storageFlags,
        int64_t* _aidl_return) {
        const std::string& packageName, int32_t user, int32_t snapshotId,
        int32_t storageFlags, int64_t* _aidl_return) {
    ENFORCE_UID(AID_SYSTEM);
    CHECK_ARGUMENT_UUID_IS_TEST_OR_NULL(volumeUuid);
    CHECK_ARGUMENT_PACKAGE_NAME(packageName);
@@ -802,16 +805,19 @@ binder::Status InstalldNativeService::snapshotAppData(
    bool clear_ce_on_exit = false;
    bool clear_de_on_exit = false;

    auto deleter = [&clear_ce_on_exit, &clear_de_on_exit, &volume_uuid, &user, &package_name] {
    auto deleter = [&clear_ce_on_exit, &clear_de_on_exit, &volume_uuid, &user, &package_name,
            &snapshotId] {
        if (clear_de_on_exit) {
            auto to = create_data_misc_de_rollback_package_path(volume_uuid, user, package_name);
            auto to = create_data_misc_de_rollback_package_path(volume_uuid, user, snapshotId,
                    package_name);
            if (delete_dir_contents(to.c_str(), 1, nullptr) != 0) {
                LOG(WARNING) << "Failed to delete app data snapshot: " << to;
            }
        }

        if (clear_ce_on_exit) {
            auto to = create_data_misc_ce_rollback_package_path(volume_uuid, user, package_name);
            auto to = create_data_misc_ce_rollback_package_path(volume_uuid, user, snapshotId,
                    package_name);
            if (delete_dir_contents(to.c_str(), 1, nullptr) != 0) {
                LOG(WARNING) << "Failed to delete app data snapshot: " << to;
            }
@@ -847,15 +853,21 @@ binder::Status InstalldNativeService::snapshotAppData(

    if (storageFlags & FLAG_STORAGE_DE) {
        auto from = create_data_user_de_package_path(volume_uuid, user, package_name);
        auto to = create_data_misc_de_rollback_path(volume_uuid, user);
        auto to = create_data_misc_de_rollback_path(volume_uuid, user, snapshotId);
        auto rollback_package_path = create_data_misc_de_rollback_package_path(volume_uuid, user,
            snapshotId, package_name);

        int rd = delete_dir_contents(to, true /* ignore_if_missing */);
        if (rd != 0) {
            res = error(rd, "Failed clearing existing snapshot " + to);
            return res;
        int rc = create_dir_if_needed(to.c_str(), kRollbackFolderMode);
        if (rc != 0) {
            return error(rc, "Failed to create folder " + to);
        }

        int rc = copy_directory_recursive(from.c_str(), to.c_str());
        rc = delete_dir_contents(rollback_package_path, true /* ignore_if_missing */);
        if (rc != 0) {
            return error(rc, "Failed clearing existing snapshot " + rollback_package_path);
        }

        rc = copy_directory_recursive(from.c_str(), to.c_str());
        if (rc != 0) {
            res = error(rc, "Failed copying " + from + " to " + to);
            clear_de_on_exit = true;
@@ -865,15 +877,21 @@ binder::Status InstalldNativeService::snapshotAppData(

    if (storageFlags & FLAG_STORAGE_CE) {
        auto from = create_data_user_ce_package_path(volume_uuid, user, package_name);
        auto to = create_data_misc_ce_rollback_path(volume_uuid, user);
        auto to = create_data_misc_ce_rollback_path(volume_uuid, user, snapshotId);
        auto rollback_package_path = create_data_misc_ce_rollback_package_path(volume_uuid, user,
            snapshotId, package_name);

        int rd = delete_dir_contents(to, true /* ignore_if_missing */);
        if (rd != 0) {
            res = error(rd, "Failed clearing existing snapshot " + to);
            return res;
        int rc = create_dir_if_needed(to.c_str(), kRollbackFolderMode);
        if (rc != 0) {
            return error(rc, "Failed to create folder " + to);
        }

        int rc = copy_directory_recursive(from.c_str(), to.c_str());
        rc = delete_dir_contents(rollback_package_path, true /* ignore_if_missing */);
        if (rc != 0) {
            return error(rc, "Failed clearing existing snapshot " + rollback_package_path);
        }

        rc = copy_directory_recursive(from.c_str(), to.c_str());
        if (rc != 0) {
            res = error(rc, "Failed copying " + from + " to " + to);
            clear_ce_on_exit = true;
@@ -881,7 +899,7 @@ binder::Status InstalldNativeService::snapshotAppData(
        }
        if (_aidl_return != nullptr) {
            auto ce_snapshot_path = create_data_misc_ce_rollback_package_path(volume_uuid, user,
                    package_name);
                    snapshotId, package_name);
            rc = get_path_inode(ce_snapshot_path, reinterpret_cast<ino_t*>(_aidl_return));
            if (rc != 0) {
                res = error(rc, "Failed to get_path_inode for " + ce_snapshot_path);
@@ -896,8 +914,8 @@ binder::Status InstalldNativeService::snapshotAppData(

binder::Status InstalldNativeService::restoreAppDataSnapshot(
        const std::unique_ptr<std::string>& volumeUuid, const std::string& packageName,
        const int32_t appId, const int64_t ceDataInode, const std::string& seInfo,
        const int32_t user, int32_t storageFlags) {
        const int32_t appId, const std::string& seInfo, const int32_t user,
        const int32_t snapshotId, int32_t storageFlags) {
    ENFORCE_UID(AID_SYSTEM);
    CHECK_ARGUMENT_UUID_IS_TEST_OR_NULL(volumeUuid);
    CHECK_ARGUMENT_PACKAGE_NAME(packageName);
@@ -907,9 +925,9 @@ binder::Status InstalldNativeService::restoreAppDataSnapshot(
    const char* package_name = packageName.c_str();

    auto from_ce = create_data_misc_ce_rollback_package_path(volume_uuid,
            user, package_name);
            user, snapshotId, package_name);
    auto from_de = create_data_misc_de_rollback_package_path(volume_uuid,
            user, package_name);
            user, snapshotId, package_name);

    const bool needs_ce_rollback = (storageFlags & FLAG_STORAGE_CE) &&
        (access(from_ce.c_str(), F_OK) == 0);
@@ -926,7 +944,11 @@ binder::Status InstalldNativeService::restoreAppDataSnapshot(
    // app with no data in those cases is arguably better than leaving the app
    // with mismatched / stale data.
    LOG(INFO) << "Clearing app data for " << packageName << " to restore snapshot.";
    binder::Status res = clearAppData(volumeUuid, packageName, user, storageFlags, ceDataInode);
    // It's fine to pass 0 as ceDataInode here, because restoreAppDataSnapshot
    // can only be called when user unlocks the phone, meaning that CE user data
    // is decrypted.
    binder::Status res = clearAppData(volumeUuid, packageName, user, storageFlags,
            0 /* ceDataInode */);
    if (!res.isOk()) {
        return res;
    }
@@ -962,7 +984,8 @@ binder::Status InstalldNativeService::restoreAppDataSnapshot(

binder::Status InstalldNativeService::destroyAppDataSnapshot(
        const std::unique_ptr<std::string> &volumeUuid, const std::string& packageName,
        const int32_t user, const int64_t ceSnapshotInode, int32_t storageFlags) {
        const int32_t user, const int64_t ceSnapshotInode, const int32_t snapshotId,
        int32_t storageFlags) {
    ENFORCE_UID(AID_SYSTEM);
    CHECK_ARGUMENT_UUID_IS_TEST_OR_NULL(volumeUuid);
    CHECK_ARGUMENT_PACKAGE_NAME(packageName);
@@ -973,7 +996,7 @@ binder::Status InstalldNativeService::destroyAppDataSnapshot(

    if (storageFlags & FLAG_STORAGE_DE) {
        auto de_snapshot_path = create_data_misc_de_rollback_package_path(volume_uuid,
                user, package_name);
                user, snapshotId, package_name);

        int res = delete_dir_contents_and_dir(de_snapshot_path, true /* ignore_if_missing */);
        if (res != 0) {
@@ -983,7 +1006,7 @@ binder::Status InstalldNativeService::destroyAppDataSnapshot(

    if (storageFlags & FLAG_STORAGE_CE) {
        auto ce_snapshot_path = create_data_misc_ce_rollback_package_path(volume_uuid,
                user, package_name, ceSnapshotInode);
                user, snapshotId, package_name, ceSnapshotInode);
        int res = delete_dir_contents_and_dir(ce_snapshot_path, true /* ignore_if_missing */);
        if (res != 0) {
            return error(res, "Failed clearing snapshot " + ce_snapshot_path);
+5 −5
Original line number Diff line number Diff line
@@ -61,14 +61,14 @@ public:
    binder::Status fixupAppData(const std::unique_ptr<std::string>& uuid, int32_t flags);

    binder::Status snapshotAppData(const std::unique_ptr<std::string>& volumeUuid,
            const std::string& packageName, const int32_t user, int32_t storageFlags,
            int64_t* _aidl_return);
            const std::string& packageName, const int32_t user, const int32_t snapshotId,
            int32_t storageFlags, int64_t* _aidl_return);
    binder::Status restoreAppDataSnapshot(const std::unique_ptr<std::string>& volumeUuid,
            const std::string& packageName, const int32_t appId, const int64_t ceDataInode,
            const std::string& seInfo, const int32_t user, int32_t storageFlags);
            const std::string& packageName, const int32_t appId, const std::string& seInfo,
            const int32_t user, const int32_t snapshotId, int32_t storageFlags);
    binder::Status destroyAppDataSnapshot(const std::unique_ptr<std::string> &volumeUuid,
            const std::string& packageName, const int32_t user, const int64_t ceSnapshotInode,
            int32_t storageFlags);
            const int32_t snapshotId, int32_t storageFlags);

    binder::Status getAppSize(const std::unique_ptr<std::string>& uuid,
            const std::vector<std::string>& packageNames, int32_t userId, int32_t flags,
+3 −3
Original line number Diff line number Diff line
@@ -106,11 +106,11 @@ interface IInstalld {
        @nullable @utf8InCpp String dexMetadata);

    long snapshotAppData(@nullable @utf8InCpp String uuid, in @utf8InCpp String packageName,
            int userId, int storageFlags);
            int userId, int snapshotId, int storageFlags);
    void restoreAppDataSnapshot(@nullable @utf8InCpp String uuid, in @utf8InCpp String packageName,
            int appId, long ceDataInode, @utf8InCpp String seInfo, int user, int storageflags);
            int appId, @utf8InCpp String seInfo, int user, int snapshotId, int storageflags);
    void destroyAppDataSnapshot(@nullable @utf8InCpp String uuid, @utf8InCpp String packageName,
            int userId, long ceSnapshotInode, int storageFlags);
            int userId, long ceSnapshotInode, int snapshotId, int storageFlags);

    const int FLAG_STORAGE_DE = 0x1;
    const int FLAG_STORAGE_CE = 0x2;
+168 −225

File changed.

Preview size limit exceeded, changes collapsed.

+68 −38
Original line number Diff line number Diff line
@@ -546,56 +546,86 @@ TEST_F(UtilsTest, MatchExtension_Invalid) {
}

TEST_F(UtilsTest, TestRollbackPaths) {
    EXPECT_EQ("/data/misc_ce/0/rollback/com.foo",
            create_data_misc_ce_rollback_package_path(nullptr, 0, "com.foo"));
    EXPECT_EQ("/data/misc_ce/10/rollback/com.foo",
            create_data_misc_ce_rollback_package_path(nullptr, 10, "com.foo"));

    EXPECT_EQ("/data/misc_de/0/rollback/com.foo",
            create_data_misc_de_rollback_package_path(nullptr, 0, "com.foo"));
    EXPECT_EQ("/data/misc_de/10/rollback/com.foo",
            create_data_misc_de_rollback_package_path(nullptr, 10, "com.foo"));

    EXPECT_EQ("/data/misc_ce/0/rollback",
            create_data_misc_ce_rollback_path(nullptr, 0));
    EXPECT_EQ("/data/misc_ce/10/rollback",
            create_data_misc_ce_rollback_path(nullptr, 10));

    EXPECT_EQ("/data/misc_de/0/rollback",
            create_data_misc_de_rollback_path(nullptr, 0));
    EXPECT_EQ("/data/misc_de/10/rollback",
            create_data_misc_de_rollback_path(nullptr, 10));

    EXPECT_EQ("/data/misc_ce/0/rollback/com.foo",
            create_data_misc_ce_rollback_package_path(nullptr, 0, "com.foo", 0));
    EXPECT_EQ("/data/misc_ce/0/rollback/com.foo",
            create_data_misc_ce_rollback_package_path(nullptr, 0, "com.foo", 239));

    auto rollback_ce_package_path = create_data_misc_ce_rollback_package_path(nullptr, 0, "com.foo");
    auto deleter = [&rollback_ce_package_path]() {
        delete_dir_contents_and_dir(rollback_ce_package_path, true /* ignore_if_missing */);
    EXPECT_EQ("/data/misc_ce/0/rollback/239/com.foo",
            create_data_misc_ce_rollback_package_path(nullptr, 0, 239, "com.foo"));
    EXPECT_EQ("/data/misc_ce/10/rollback/37/com.foo",
            create_data_misc_ce_rollback_package_path(nullptr, 10, 37, "com.foo"));

    EXPECT_EQ("/data/misc_de/0/rollback/73/com.foo",
            create_data_misc_de_rollback_package_path(nullptr, 0, 73, "com.foo"));
    EXPECT_EQ("/data/misc_de/10/rollback/13/com.foo",
            create_data_misc_de_rollback_package_path(nullptr, 10, 13, "com.foo"));

    EXPECT_EQ("/data/misc_ce/0/rollback/57",
            create_data_misc_ce_rollback_path(nullptr, 0, 57));
    EXPECT_EQ("/data/misc_ce/10/rollback/1543",
            create_data_misc_ce_rollback_path(nullptr, 10, 1543));

    EXPECT_EQ("/data/misc_de/0/rollback/43",
            create_data_misc_de_rollback_path(nullptr, 0, 43));
    EXPECT_EQ("/data/misc_de/10/rollback/41",
            create_data_misc_de_rollback_path(nullptr, 10, 41));

    EXPECT_EQ("/data/misc_ce/0/rollback/17/com.foo",
            create_data_misc_ce_rollback_package_path(nullptr, 0, 17, "com.foo", 0));
    EXPECT_EQ("/data/misc_ce/0/rollback/19/com.foo",
            create_data_misc_ce_rollback_package_path(nullptr, 0, 19, "com.foo", 239));

    auto rollback_ce_path = create_data_misc_ce_rollback_path(nullptr, 0, 53);
    auto rollback_ce_package_path = create_data_misc_ce_rollback_package_path(nullptr, 0, 53,
            "com.foo");
    auto deleter = [&rollback_ce_path]() {
        delete_dir_contents_and_dir(rollback_ce_path, true /* ignore_if_missing */);
    };
    auto scope_guard = android::base::make_scope_guard(deleter);

    ASSERT_NE(-1, mkdir(rollback_ce_package_path.c_str(), 700));
    EXPECT_NE(-1, mkdir(rollback_ce_path.c_str(), 700));
    EXPECT_NE(-1, mkdir(rollback_ce_package_path.c_str(), 700));

    ino_t ce_data_inode;
    ASSERT_EQ(0, get_path_inode(rollback_ce_package_path, &ce_data_inode));
    EXPECT_EQ(0, get_path_inode(rollback_ce_package_path, &ce_data_inode));

    EXPECT_EQ("/data/misc_ce/0/rollback/com.foo",
            create_data_misc_ce_rollback_package_path(nullptr, 0, "com.foo", ce_data_inode));
    EXPECT_EQ("/data/misc_ce/0/rollback/53/com.foo",
            create_data_misc_ce_rollback_package_path(nullptr, 0, 53, "com.foo", ce_data_inode));
    // Check that path defined by inode is picked even if it's not the same as
    // the fallback one.
    EXPECT_EQ("/data/misc_ce/0/rollback/com.foo",
            create_data_misc_ce_rollback_package_path(nullptr, 0, "com.bar", ce_data_inode));
    EXPECT_EQ("/data/misc_ce/0/rollback/53/com.foo",
            create_data_misc_ce_rollback_package_path(nullptr, 0, 53, "com.bar", ce_data_inode));

    // These last couple of cases are never exercised in production because we
    // only snapshot apps in the primary data partition. Exercise them here for
    // the sake of completeness.
    EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b/misc_ce/0/rollback/com.example",
            create_data_misc_ce_rollback_package_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", 0, "com.example"));
    EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b/misc_de/0/rollback/com.example",
            create_data_misc_de_rollback_package_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", 0, "com.example"));
    EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b/misc_ce/0/rollback/7/com.example",
            create_data_misc_ce_rollback_package_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", 0, 7,
                    "com.example"));
    EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b/misc_de/0/rollback/11/com.example",
            create_data_misc_de_rollback_package_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", 0, 11,
                    "com.example"));
}

TEST_F(UtilsTest, TestCreateDirIfNeeded) {
    system("mkdir -p /data/local/tmp/user/0");

    auto deleter = [&]() {
        delete_dir_contents_and_dir("/data/local/tmp/user/0", true /* ignore_if_missing */);
    };
    auto scope_guard = android::base::make_scope_guard(deleter);

    // Create folder and check it's permissions.
    ASSERT_EQ(0, create_dir_if_needed("/data/local/tmp/user/0/foo", 0700));
    struct stat st;
    ASSERT_EQ(0, stat("/data/local/tmp/user/0/foo", &st));
    ASSERT_EQ(0700, st.st_mode & ALLPERMS);

    // Check that create_dir_if_needed is no-op if folder already exists with
    // correct permissions.
    ASSERT_EQ(0, create_dir_if_needed("/data/local/tmp/user/0/foo", 0700));

    // Check -1 is returned if folder exists but with different permissions.
    ASSERT_EQ(-1, create_dir_if_needed("/data/local/tmp/user/0/foo", 0750));

    // Check that call fails if parent doesn't exist.
    ASSERT_NE(0, create_dir_if_needed("/data/local/tmp/user/0/bar/baz", 0700));
}

}  // namespace installd
Loading