From b68f0d14931905472b93ad08a753a01a33bd315b Mon Sep 17 00:00:00 2001 From: Nikita Ioffe Date: Mon, 4 Feb 2019 11:06:37 +0000 Subject: [PATCH] installd: parameterize user data snapshots with snapshot_id - snapshot_id will be provided by RollbackManagerService and for a given rollback will be equal to its rollback_id. - snapshotAppData now creates a folder to snapshot data to, in case it does not exist. - removed ceDataInode from restoreAppDataSnapshot API, since it's only called if users phone is unlocked, meaning that CE data is available and doesn't require inode to be accessed. - refactored installd_service_test to reduce test set up boilerplate. - added a test to cover case when snapshots for different packages have the same snapshot_id. Bug: 124029909 Test: installd_utils_test installd_service_test, RollbackTest Change-Id: I4177a44a60cdfdc5429a28c613ce661b24482b8b --- cmds/installd/InstalldNativeService.cpp | 75 +++-- cmds/installd/InstalldNativeService.h | 10 +- cmds/installd/binder/android/os/IInstalld.aidl | 6 +- cmds/installd/tests/installd_service_test.cpp | 393 +++++++++++-------------- cmds/installd/tests/installd_utils_test.cpp | 106 ++++--- cmds/installd/utils.cpp | 56 +++- cmds/installd/utils.h | 16 +- 7 files changed, 350 insertions(+), 312 deletions(-) diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp index 49383e5112..2efcf11ef9 100644 --- a/cmds/installd/InstalldNativeService.cpp +++ b/cmds/installd/InstalldNativeService.cpp @@ -39,6 +39,7 @@ #include #include +#include #include #include #include @@ -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"; @@ -822,8 +825,8 @@ static int32_t copy_directory_recursive(const char* from, const char* to) { binder::Status InstalldNativeService::snapshotAppData( const std::unique_ptr& 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); @@ -840,16 +843,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; } @@ -885,15 +891,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); + } + + rc = delete_dir_contents(rollback_package_path, true /* ignore_if_missing */); + if (rc != 0) { + return error(rc, "Failed clearing existing snapshot " + rollback_package_path); } - int rc = copy_directory_recursive(from.c_str(), to.c_str()); + 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; @@ -903,15 +915,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; @@ -919,7 +937,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(_aidl_return)); if (rc != 0) { res = error(rc, "Failed to get_path_inode for " + ce_snapshot_path); @@ -934,8 +952,8 @@ binder::Status InstalldNativeService::snapshotAppData( binder::Status InstalldNativeService::restoreAppDataSnapshot( const std::unique_ptr& 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); @@ -945,9 +963,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); @@ -964,7 +982,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; } @@ -1000,7 +1022,8 @@ binder::Status InstalldNativeService::restoreAppDataSnapshot( binder::Status InstalldNativeService::destroyAppDataSnapshot( const std::unique_ptr &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); @@ -1011,7 +1034,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) { @@ -1021,7 +1044,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); diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h index 578132da5b..0e91cb27ba 100644 --- a/cmds/installd/InstalldNativeService.h +++ b/cmds/installd/InstalldNativeService.h @@ -61,14 +61,14 @@ public: binder::Status fixupAppData(const std::unique_ptr& uuid, int32_t flags); binder::Status snapshotAppData(const std::unique_ptr& 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& 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 &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& uuid, const std::vector& packageNames, int32_t userId, int32_t flags, diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl index b3452100c8..63c9765a39 100644 --- a/cmds/installd/binder/android/os/IInstalld.aidl +++ b/cmds/installd/binder/android/os/IInstalld.aidl @@ -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; diff --git a/cmds/installd/tests/installd_service_test.cpp b/cmds/installd/tests/installd_service_test.cpp index 48b07c417c..a31d510565 100644 --- a/cmds/installd/tests/installd_service_test.cpp +++ b/cmds/installd/tests/installd_service_test.cpp @@ -259,32 +259,59 @@ static bool mkdirs(const std::string& path, mode_t mode) { return false; } - return (::mkdir(path.c_str(), mode) != -1); + if (::mkdir(path.c_str(), mode) != 0) { + PLOG(DEBUG) << "Failed to create folder " << path; + return false; + } + return true; } -TEST_F(ServiceTest, CreateAppDataSnapshot) { - auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0); - auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0); +class AppDataSnapshotTest : public testing::Test { +private: + std::string rollback_ce_base_dir; + std::string rollback_de_base_dir; - ASSERT_TRUE(mkdirs(rollback_ce_dir, 700)); - ASSERT_TRUE(mkdirs(rollback_de_dir, 700)); +protected: + InstalldNativeService* service; - auto fake_package_ce_path = create_data_user_ce_package_path("TEST", 0, "com.foo"); - auto fake_package_de_path = create_data_user_de_package_path("TEST", 0, "com.foo"); + std::string fake_package_ce_path; + std::string fake_package_de_path; - ASSERT_TRUE(mkdirs(fake_package_ce_path, 700)); - ASSERT_TRUE(mkdirs(fake_package_de_path, 700)); + virtual void SetUp() { + setenv("ANDROID_LOG_TAGS", "*:v", 1); + android::base::InitLogging(nullptr); - auto deleter = [&rollback_ce_dir, &rollback_de_dir, - &fake_package_ce_path, &fake_package_de_path]() { - delete_dir_contents(rollback_ce_dir, true); - delete_dir_contents(rollback_de_dir, true); - delete_dir_contents(fake_package_ce_path, true); - delete_dir_contents(fake_package_de_path, true); - rmdir(rollback_ce_dir.c_str()); - rmdir(rollback_de_dir.c_str()); - }; - auto scope_guard = android::base::make_scope_guard(deleter); + service = new InstalldNativeService(); + ASSERT_TRUE(mkdirs("/data/local/tmp/user/0", 0700)); + + init_globals_from_data_and_root(); + + rollback_ce_base_dir = create_data_misc_ce_rollback_base_path("TEST", 0); + rollback_de_base_dir = create_data_misc_de_rollback_base_path("TEST", 0); + + fake_package_ce_path = create_data_user_ce_package_path("TEST", 0, "com.foo"); + fake_package_de_path = create_data_user_de_package_path("TEST", 0, "com.foo"); + + ASSERT_TRUE(mkdirs(rollback_ce_base_dir, 0700)); + ASSERT_TRUE(mkdirs(rollback_de_base_dir, 0700)); + ASSERT_TRUE(mkdirs(fake_package_ce_path, 0700)); + ASSERT_TRUE(mkdirs(fake_package_de_path, 0700)); + } + + virtual void TearDown() { + ASSERT_EQ(0, delete_dir_contents_and_dir(rollback_ce_base_dir, true)); + ASSERT_EQ(0, delete_dir_contents_and_dir(rollback_de_base_dir, true)); + ASSERT_EQ(0, delete_dir_contents(fake_package_ce_path, true)); + ASSERT_EQ(0, delete_dir_contents(fake_package_de_path, true)); + + delete service; + ASSERT_EQ(0, delete_dir_contents_and_dir("/data/local/tmp/user/0", true)); + } +}; + +TEST_F(AppDataSnapshotTest, CreateAppDataSnapshot) { + auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0, 37); + auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0, 37); ASSERT_TRUE(android::base::WriteStringToFile( "TEST_CONTENT_CE", fake_package_ce_path + "/file1", @@ -296,7 +323,7 @@ TEST_F(ServiceTest, CreateAppDataSnapshot) { // Request a snapshot of the CE content but not the DE content. int64_t ce_snapshot_inode; ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique("TEST"), - "com.foo", 0, FLAG_STORAGE_CE, &ce_snapshot_inode)); + "com.foo", 0, 37, FLAG_STORAGE_CE, &ce_snapshot_inode)); struct stat buf; memset(&buf, 0, sizeof(buf)); ASSERT_EQ(0, stat((rollback_ce_dir + "/com.foo").c_str(), &buf)); @@ -318,7 +345,7 @@ TEST_F(ServiceTest, CreateAppDataSnapshot) { // Request a snapshot of the DE content but not the CE content. ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique("TEST"), - "com.foo", 0, FLAG_STORAGE_DE, &ce_snapshot_inode)); + "com.foo", 0, 37, FLAG_STORAGE_DE, &ce_snapshot_inode)); // Only DE content snapshot was requested. ASSERT_EQ(ce_snapshot_inode, 0); @@ -339,7 +366,7 @@ TEST_F(ServiceTest, CreateAppDataSnapshot) { // Request a snapshot of both the CE as well as the DE content. ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique("TEST"), - "com.foo", 0, FLAG_STORAGE_DE | FLAG_STORAGE_CE, nullptr)); + "com.foo", 0, 37, FLAG_STORAGE_DE | FLAG_STORAGE_CE, nullptr)); ASSERT_TRUE(android::base::ReadFileToString( rollback_ce_dir + "/com.foo/file1", &ce_content, false /* follow_symlinks */)); @@ -349,27 +376,73 @@ TEST_F(ServiceTest, CreateAppDataSnapshot) { ASSERT_EQ("TEST_CONTENT_DE_MODIFIED", de_content); } -TEST_F(ServiceTest, CreateAppDataSnapshot_AppDataAbsent) { - auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0); - auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0); +TEST_F(AppDataSnapshotTest, CreateAppDataSnapshot_TwoSnapshotsWithTheSameId) { + auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0, 67); + auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0, 67); - ASSERT_TRUE(mkdirs(rollback_ce_dir, 700)); - ASSERT_TRUE(mkdirs(rollback_de_dir, 700)); + auto another_fake_package_ce_path = create_data_user_ce_package_path("TEST", 0, "com.bar"); + auto another_fake_package_de_path = create_data_user_de_package_path("TEST", 0, "com.bar"); - auto deleter = [&rollback_ce_dir, &rollback_de_dir]() { - delete_dir_contents(rollback_ce_dir, true); - delete_dir_contents(rollback_de_dir, true); - rmdir(rollback_ce_dir.c_str()); - rmdir(rollback_de_dir.c_str()); + // Since this test sets up data for another package, some bookkeeping is required. + auto deleter = [&]() { + ASSERT_EQ(0, delete_dir_contents_and_dir(another_fake_package_ce_path, true)); + ASSERT_EQ(0, delete_dir_contents_and_dir(another_fake_package_de_path, true)); }; - auto scope_guard = android::base::make_scope_guard(deleter); + ASSERT_TRUE(mkdirs(another_fake_package_ce_path, 0700)); + ASSERT_TRUE(mkdirs(another_fake_package_de_path, 0700)); + + ASSERT_TRUE(android::base::WriteStringToFile( + "TEST_CONTENT_CE", fake_package_ce_path + "/file1", + 0700, 10000, 20000, false /* follow_symlinks */)); + ASSERT_TRUE(android::base::WriteStringToFile( + "TEST_CONTENT_DE", fake_package_de_path + "/file1", + 0700, 10000, 20000, false /* follow_symlinks */)); + ASSERT_TRUE(android::base::WriteStringToFile( + "ANOTHER_TEST_CONTENT_CE", another_fake_package_ce_path + "/file1", + 0700, 10000, 20000, false /* follow_symlinks */)); + ASSERT_TRUE(android::base::WriteStringToFile( + "ANOTHER_TEST_CONTENT_DE", another_fake_package_de_path + "/file1", + 0700, 10000, 20000, false /* follow_symlinks */)); + + // Request snapshot for the package com.foo. + ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique("TEST"), + "com.foo", 0, 67, FLAG_STORAGE_DE | FLAG_STORAGE_CE, nullptr)); + // Now request snapshot with the same id for the package com.bar + ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique("TEST"), + "com.bar", 0, 67, FLAG_STORAGE_DE | FLAG_STORAGE_CE, nullptr)); + + // Check that both snapshots have correct data in them. + std::string com_foo_ce_content, com_foo_de_content; + std::string com_bar_ce_content, com_bar_de_content; + ASSERT_TRUE(android::base::ReadFileToString( + rollback_ce_dir + "/com.foo/file1", &com_foo_ce_content, false /* follow_symlinks */)); + ASSERT_TRUE(android::base::ReadFileToString( + rollback_de_dir + "/com.foo/file1", &com_foo_de_content, false /* follow_symlinks */)); + ASSERT_TRUE(android::base::ReadFileToString( + rollback_ce_dir + "/com.bar/file1", &com_bar_ce_content, false /* follow_symlinks */)); + ASSERT_TRUE(android::base::ReadFileToString( + rollback_de_dir + "/com.bar/file1", &com_bar_de_content, false /* follow_symlinks */)); + ASSERT_EQ("TEST_CONTENT_CE", com_foo_ce_content); + ASSERT_EQ("TEST_CONTENT_DE", com_foo_de_content); + ASSERT_EQ("ANOTHER_TEST_CONTENT_CE", com_bar_ce_content); + ASSERT_EQ("ANOTHER_TEST_CONTENT_DE", com_bar_de_content); +} + +TEST_F(AppDataSnapshotTest, CreateAppDataSnapshot_AppDataAbsent) { + auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0, 73); + auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0, 73); + + // Similuating app data absence. + ASSERT_EQ(0, delete_dir_contents_and_dir(fake_package_ce_path, true)); + ASSERT_EQ(0, delete_dir_contents_and_dir(fake_package_de_path, true)); + int64_t ce_snapshot_inode; ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique("TEST"), - "com.foo", 0, FLAG_STORAGE_CE, &ce_snapshot_inode)); + "com.foo", 0, 73, FLAG_STORAGE_CE, &ce_snapshot_inode)); ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique("TEST"), - "com.foo", 0, FLAG_STORAGE_DE, nullptr)); + "com.foo", 0, 73, FLAG_STORAGE_DE, nullptr)); // No CE content snapshot was performed. ASSERT_EQ(ce_snapshot_inode, 0); @@ -380,29 +453,12 @@ TEST_F(ServiceTest, CreateAppDataSnapshot_AppDataAbsent) { ASSERT_EQ(-1, stat((rollback_de_dir + "/com.foo").c_str(), &sb)); } -TEST_F(ServiceTest, CreateAppDataSnapshot_ClearsExistingSnapshot) { - auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0); - auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0); - - ASSERT_TRUE(mkdirs(rollback_ce_dir, 700)); - ASSERT_TRUE(mkdirs(rollback_de_dir, 700)); - - auto fake_package_ce_path = create_data_user_ce_package_path("TEST", 0, "com.foo"); - auto fake_package_de_path = create_data_user_de_package_path("TEST", 0, "com.foo"); +TEST_F(AppDataSnapshotTest, CreateAppDataSnapshot_ClearsExistingSnapshot) { + auto rollback_ce_dir = create_data_misc_ce_rollback_package_path("TEST", 0, 13, "com.foo"); + auto rollback_de_dir = create_data_misc_de_rollback_package_path("TEST", 0, 13, "com.foo"); - ASSERT_TRUE(mkdirs(fake_package_ce_path, 700)); - ASSERT_TRUE(mkdirs(fake_package_de_path, 700)); - - auto deleter = [&rollback_ce_dir, &rollback_de_dir, - &fake_package_ce_path, &fake_package_de_path]() { - delete_dir_contents(rollback_ce_dir, true); - delete_dir_contents(rollback_de_dir, true); - delete_dir_contents(fake_package_ce_path, true); - delete_dir_contents(fake_package_de_path, true); - rmdir(rollback_ce_dir.c_str()); - rmdir(rollback_de_dir.c_str()); - }; - auto scope_guard = android::base::make_scope_guard(deleter); + ASSERT_TRUE(mkdirs(rollback_ce_dir, 0700)); + ASSERT_TRUE(mkdirs(rollback_de_dir, 0700)); // Simulate presence of an existing snapshot ASSERT_TRUE(android::base::WriteStringToFile( @@ -421,62 +477,40 @@ TEST_F(ServiceTest, CreateAppDataSnapshot_ClearsExistingSnapshot) { 0700, 10000, 20000, false /* follow_symlinks */)); ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique("TEST"), - "com.foo", 0, FLAG_STORAGE_DE | FLAG_STORAGE_CE, nullptr)); + "com.foo", 0, 13, FLAG_STORAGE_DE | FLAG_STORAGE_CE, nullptr)); // Previous snapshot (with data for file1) must be cleared. struct stat sb; - ASSERT_EQ(-1, stat((rollback_ce_dir + "/com.foo/file1").c_str(), &sb)); - ASSERT_EQ(-1, stat((rollback_de_dir + "/com.foo/file1").c_str(), &sb)); + ASSERT_EQ(-1, stat((rollback_ce_dir + "/file1").c_str(), &sb)); + ASSERT_EQ(-1, stat((rollback_de_dir + "/file1").c_str(), &sb)); + // New snapshot (with data for file2) must be present. + ASSERT_NE(-1, stat((rollback_ce_dir + "/file2").c_str(), &sb)); + ASSERT_NE(-1, stat((rollback_de_dir + "/file2").c_str(), &sb)); } -TEST_F(ServiceTest, SnapshotAppData_WrongVolumeUuid) { - // Setup app data to make sure that fails due to wrong volumeUuid being +TEST_F(AppDataSnapshotTest, SnapshotAppData_WrongVolumeUuid) { + // Setup rollback folders to make sure that fails due to wrong volumeUuid being // passed, not because of some other reason. - auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0); - auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0); + auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0, 17); + auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0, 17); - ASSERT_TRUE(mkdirs(rollback_ce_dir, 700)); - ASSERT_TRUE(mkdirs(rollback_de_dir, 700)); - - auto deleter = [&rollback_ce_dir, &rollback_de_dir]() { - delete_dir_contents(rollback_ce_dir, true); - delete_dir_contents(rollback_de_dir, true); - rmdir(rollback_ce_dir.c_str()); - rmdir(rollback_de_dir.c_str()); - }; - auto scope_guard = android::base::make_scope_guard(deleter); + ASSERT_TRUE(mkdirs(rollback_ce_dir, 0700)); + ASSERT_TRUE(mkdirs(rollback_de_dir, 0700)); EXPECT_BINDER_FAIL(service->snapshotAppData(std::make_unique("FOO"), - "com.foo", 0, FLAG_STORAGE_DE, nullptr)); + "com.foo", 0, 17, FLAG_STORAGE_DE, nullptr)); } -TEST_F(ServiceTest, CreateAppDataSnapshot_ClearsCache) { - auto fake_package_ce_path = create_data_user_ce_package_path("TEST", 0, "com.foo"); - auto fake_package_de_path = create_data_user_de_package_path("TEST", 0, "com.foo"); +TEST_F(AppDataSnapshotTest, CreateAppDataSnapshot_ClearsCache) { auto fake_package_ce_cache_path = fake_package_ce_path + "/cache"; auto fake_package_ce_code_cache_path = fake_package_ce_path + "/code_cache"; auto fake_package_de_cache_path = fake_package_de_path + "/cache"; auto fake_package_de_code_cache_path = fake_package_de_path + "/code_cache"; - auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0); - auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0); - - ASSERT_TRUE(mkdirs(fake_package_ce_path, 700)); - ASSERT_TRUE(mkdirs(fake_package_de_path, 700)); - ASSERT_TRUE(mkdirs(fake_package_ce_cache_path, 700)); - ASSERT_TRUE(mkdirs(fake_package_ce_code_cache_path, 700)); - ASSERT_TRUE(mkdirs(fake_package_de_cache_path, 700)); - ASSERT_TRUE(mkdirs(fake_package_de_code_cache_path, 700)); - ASSERT_TRUE(mkdirs(rollback_ce_dir, 700)); - ASSERT_TRUE(mkdirs(rollback_de_dir, 700)); - - auto deleter = [&fake_package_ce_path, &fake_package_de_path, - &rollback_ce_dir, &rollback_de_dir]() { - delete_dir_contents(fake_package_ce_path, true); - delete_dir_contents(fake_package_de_path, true); - delete_dir_contents_and_dir(rollback_ce_dir, true); - delete_dir_contents_and_dir(rollback_de_dir, true); - }; - auto scope_guard = android::base::make_scope_guard(deleter); + + ASSERT_TRUE(mkdirs(fake_package_ce_cache_path, 0700)); + ASSERT_TRUE(mkdirs(fake_package_ce_code_cache_path, 0700)); + ASSERT_TRUE(mkdirs(fake_package_de_cache_path, 0700)); + ASSERT_TRUE(mkdirs(fake_package_de_code_cache_path, 0700)); ASSERT_TRUE(android::base::WriteStringToFile( "TEST_CONTENT_CE", fake_package_ce_cache_path + "/file1", @@ -491,7 +525,7 @@ TEST_F(ServiceTest, CreateAppDataSnapshot_ClearsCache) { "TEST_CONTENT_DE", fake_package_de_code_cache_path + "/file1", 0700, 10000, 20000, false /* follow_symlinks */)); ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique("TEST"), - "com.foo", 0, FLAG_STORAGE_CE | FLAG_STORAGE_DE, nullptr)); + "com.foo", 0, 23, FLAG_STORAGE_CE | FLAG_STORAGE_DE, nullptr)); // The snapshot call must clear cache. struct stat sb; ASSERT_EQ(-1, stat((fake_package_ce_cache_path + "/file1").c_str(), &sb)); @@ -500,34 +534,17 @@ TEST_F(ServiceTest, CreateAppDataSnapshot_ClearsCache) { ASSERT_EQ(-1, stat((fake_package_de_code_cache_path + "/file1").c_str(), &sb)); } -TEST_F(ServiceTest, RestoreAppDataSnapshot) { - auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0); - auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0); - - ASSERT_TRUE(mkdirs(rollback_ce_dir, 700)); - ASSERT_TRUE(mkdirs(rollback_de_dir, 700)); - - auto fake_package_ce_path = create_data_user_ce_package_path("TEST", 0, "com.foo"); - auto fake_package_de_path = create_data_user_de_package_path("TEST", 0, "com.foo"); - - ASSERT_TRUE(mkdirs(fake_package_ce_path, 700)); - ASSERT_TRUE(mkdirs(fake_package_de_path, 700)); +TEST_F(AppDataSnapshotTest, RestoreAppDataSnapshot) { + auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0, 239); + auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0, 239); - auto deleter = [&rollback_ce_dir, &rollback_de_dir, - &fake_package_ce_path, &fake_package_de_path]() { - delete_dir_contents(rollback_ce_dir, true); - delete_dir_contents(rollback_de_dir, true); - delete_dir_contents(fake_package_ce_path, true); - delete_dir_contents(fake_package_de_path, true); - rmdir(rollback_ce_dir.c_str()); - rmdir(rollback_de_dir.c_str()); - }; - auto scope_guard = android::base::make_scope_guard(deleter); + ASSERT_TRUE(mkdirs(rollback_ce_dir, 0700)); + ASSERT_TRUE(mkdirs(rollback_de_dir, 0700)); // Write contents to the rollback location. We'll write the same files to the // app data location and make sure the restore has overwritten them. - ASSERT_TRUE(mkdirs(rollback_ce_dir + "/com.foo/", 700)); - ASSERT_TRUE(mkdirs(rollback_de_dir + "/com.foo/", 700)); + ASSERT_TRUE(mkdirs(rollback_ce_dir + "/com.foo/", 0700)); + ASSERT_TRUE(mkdirs(rollback_de_dir + "/com.foo/", 0700)); ASSERT_TRUE(android::base::WriteStringToFile( "CE_RESTORE_CONTENT", rollback_ce_dir + "/com.foo/file1", 0700, 10000, 20000, false /* follow_symlinks */)); @@ -542,7 +559,7 @@ TEST_F(ServiceTest, RestoreAppDataSnapshot) { 0700, 10000, 20000, false /* follow_symlinks */)); ASSERT_BINDER_SUCCESS(service->restoreAppDataSnapshot(std::make_unique("TEST"), - "com.foo", 10000, -1, "", 0, FLAG_STORAGE_DE | FLAG_STORAGE_CE)); + "com.foo", 10000, "", 0, 239, FLAG_STORAGE_DE | FLAG_STORAGE_CE)); std::string ce_content, de_content; ASSERT_TRUE(android::base::ReadFileToString( @@ -553,29 +570,9 @@ TEST_F(ServiceTest, RestoreAppDataSnapshot) { ASSERT_EQ("DE_RESTORE_CONTENT", de_content); } -TEST_F(ServiceTest, CreateSnapshotThenDestroyIt) { - auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0); - auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0); - - ASSERT_TRUE(mkdirs(rollback_ce_dir, 700)); - ASSERT_TRUE(mkdirs(rollback_de_dir, 700)); - - auto fake_package_ce_path = create_data_user_ce_package_path("TEST", 0, "com.foo"); - auto fake_package_de_path = create_data_user_de_package_path("TEST", 0, "com.foo"); - - ASSERT_TRUE(mkdirs(fake_package_ce_path, 700)); - ASSERT_TRUE(mkdirs(fake_package_de_path, 700)); - - auto deleter = [&rollback_ce_dir, &rollback_de_dir, - &fake_package_ce_path, &fake_package_de_path]() { - delete_dir_contents(rollback_ce_dir, true); - delete_dir_contents(rollback_de_dir, true); - delete_dir_contents(fake_package_ce_path, true); - delete_dir_contents(fake_package_de_path, true); - rmdir(rollback_ce_dir.c_str()); - rmdir(rollback_de_dir.c_str()); - }; - auto scope_guard = android::base::make_scope_guard(deleter); +TEST_F(AppDataSnapshotTest, CreateSnapshotThenDestroyIt) { + auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0, 57); + auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0, 57); // Prepare data for snapshot. ASSERT_TRUE(android::base::WriteStringToFile( @@ -588,7 +585,7 @@ TEST_F(ServiceTest, CreateSnapshotThenDestroyIt) { int64_t ce_snapshot_inode; // Request a snapshot of both the CE as well as the DE content. ASSERT_TRUE(service->snapshotAppData(std::make_unique("TEST"), - "com.foo", 0, FLAG_STORAGE_DE | FLAG_STORAGE_CE, &ce_snapshot_inode).isOk()); + "com.foo", 0, 57, FLAG_STORAGE_DE | FLAG_STORAGE_CE, &ce_snapshot_inode).isOk()); // Because CE data snapshot was requested, ce_snapshot_inode can't be null. ASSERT_NE(0, ce_snapshot_inode); // Check snapshot is there. @@ -598,39 +595,19 @@ TEST_F(ServiceTest, CreateSnapshotThenDestroyIt) { ASSERT_TRUE(service->destroyAppDataSnapshot(std::make_unique("TEST"), - "com.foo", 0, ce_snapshot_inode, FLAG_STORAGE_DE | FLAG_STORAGE_CE).isOk()); + "com.foo", 0, ce_snapshot_inode, 57, FLAG_STORAGE_DE | FLAG_STORAGE_CE).isOk()); // Check snapshot is deleted. ASSERT_EQ(-1, stat((rollback_ce_dir + "/com.foo").c_str(), &sb)); ASSERT_EQ(-1, stat((rollback_de_dir + "/com.foo").c_str(), &sb)); } -TEST_F(ServiceTest, DestroyAppDataSnapshot_CeSnapshotInodeIsZero) { - auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0); - auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0); - - ASSERT_TRUE(mkdirs(rollback_ce_dir, 700)); - ASSERT_TRUE(mkdirs(rollback_de_dir, 700)); - - auto fake_package_ce_path = create_data_user_ce_package_path("TEST", 0, "com.foo"); - auto fake_package_de_path = create_data_user_de_package_path("TEST", 0, "com.foo"); - - ASSERT_TRUE(mkdirs(fake_package_ce_path, 700)); - ASSERT_TRUE(mkdirs(fake_package_de_path, 700)); - - auto deleter = [&rollback_ce_dir, &rollback_de_dir, - &fake_package_ce_path, &fake_package_de_path]() { - delete_dir_contents(rollback_ce_dir, true); - delete_dir_contents(rollback_de_dir, true); - delete_dir_contents(fake_package_ce_path, true); - delete_dir_contents(fake_package_de_path, true); - rmdir(rollback_ce_dir.c_str()); - rmdir(rollback_de_dir.c_str()); - }; - auto scope_guard = android::base::make_scope_guard(deleter); +TEST_F(AppDataSnapshotTest, DestroyAppDataSnapshot_CeSnapshotInodeIsZero) { + auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0, 1543); + auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0, 1543); // Create a snapshot - ASSERT_TRUE(mkdirs(rollback_ce_dir + "/com.foo/", 700)); - ASSERT_TRUE(mkdirs(rollback_de_dir + "/com.foo/", 700)); + ASSERT_TRUE(mkdirs(rollback_ce_dir + "/com.foo/", 0700)); + ASSERT_TRUE(mkdirs(rollback_de_dir + "/com.foo/", 0700)); ASSERT_TRUE(android::base::WriteStringToFile( "CE_RESTORE_CONTENT", rollback_ce_dir + "/com.foo/file1", 0700, 10000, 20000, false /* follow_symlinks */)); @@ -639,7 +616,7 @@ TEST_F(ServiceTest, DestroyAppDataSnapshot_CeSnapshotInodeIsZero) { 0700, 10000, 20000, false /* follow_symlinks */)); ASSERT_TRUE(service->destroyAppDataSnapshot(std::make_unique("TEST"), - "com.foo", 0, 0, FLAG_STORAGE_DE | FLAG_STORAGE_CE).isOk()); + "com.foo", 0, 0, 1543, FLAG_STORAGE_DE | FLAG_STORAGE_CE).isOk()); // Check snapshot is deleted. struct stat sb; @@ -648,67 +625,33 @@ TEST_F(ServiceTest, DestroyAppDataSnapshot_CeSnapshotInodeIsZero) { // Check that deleting already deleted snapshot is no-op. ASSERT_TRUE(service->destroyAppDataSnapshot(std::make_unique("TEST"), - "com.foo", 0, 0, FLAG_STORAGE_DE | FLAG_STORAGE_CE).isOk()); + "com.foo", 0, 0, 1543, FLAG_STORAGE_DE | FLAG_STORAGE_CE).isOk()); } -TEST_F(ServiceTest, DestroyAppDataSnapshot_WrongVolumeUuid) { +TEST_F(AppDataSnapshotTest, DestroyAppDataSnapshot_WrongVolumeUuid) { // Setup rollback data to make sure that test fails due to wrong volumeUuid // being passed, not because of some other reason. - auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0); - auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0); - - ASSERT_TRUE(mkdirs(rollback_ce_dir, 700)); - ASSERT_TRUE(mkdirs(rollback_de_dir, 700)); - - auto fake_package_ce_path = create_data_user_ce_package_path("TEST", 0, "com.foo"); - auto fake_package_de_path = create_data_user_de_package_path("TEST", 0, "com.foo"); - - ASSERT_TRUE(mkdirs(fake_package_ce_path, 700)); - ASSERT_TRUE(mkdirs(fake_package_de_path, 700)); - - auto deleter = [&rollback_ce_dir, &rollback_de_dir, - &fake_package_ce_path, &fake_package_de_path]() { - delete_dir_contents(rollback_ce_dir, true); - delete_dir_contents(rollback_de_dir, true); - delete_dir_contents(fake_package_ce_path, true); - delete_dir_contents(fake_package_de_path, true); - rmdir(rollback_ce_dir.c_str()); - rmdir(rollback_de_dir.c_str()); - }; - auto scope_guard = android::base::make_scope_guard(deleter); + auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0, 43); + auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0, 43); + + ASSERT_TRUE(mkdirs(rollback_ce_dir, 0700)); + ASSERT_TRUE(mkdirs(rollback_de_dir, 0700)); ASSERT_FALSE(service->destroyAppDataSnapshot(std::make_unique("BAR"), - "com.foo", 0, 0, FLAG_STORAGE_DE).isOk()); + "com.foo", 0, 0, 43, FLAG_STORAGE_DE).isOk()); } -TEST_F(ServiceTest, RestoreAppDataSnapshot_WrongVolumeUuid) { +TEST_F(AppDataSnapshotTest, RestoreAppDataSnapshot_WrongVolumeUuid) { // Setup rollback data to make sure that fails due to wrong volumeUuid being // passed, not because of some other reason. - auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0); - auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0); - - ASSERT_TRUE(mkdirs(rollback_ce_dir, 700)); - ASSERT_TRUE(mkdirs(rollback_de_dir, 700)); - - auto fake_package_ce_path = create_data_user_ce_package_path("TEST", 0, "com.foo"); - auto fake_package_de_path = create_data_user_de_package_path("TEST", 0, "com.foo"); - - ASSERT_TRUE(mkdirs(fake_package_ce_path, 700)); - ASSERT_TRUE(mkdirs(fake_package_de_path, 700)); - - auto deleter = [&rollback_ce_dir, &rollback_de_dir, - &fake_package_ce_path, &fake_package_de_path]() { - delete_dir_contents(rollback_ce_dir, true); - delete_dir_contents(rollback_de_dir, true); - delete_dir_contents(fake_package_ce_path, true); - delete_dir_contents(fake_package_de_path, true); - rmdir(rollback_ce_dir.c_str()); - rmdir(rollback_de_dir.c_str()); - }; - auto scope_guard = android::base::make_scope_guard(deleter); + auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0, 41); + auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0, 41); + + ASSERT_TRUE(mkdirs(rollback_ce_dir, 0700)); + ASSERT_TRUE(mkdirs(rollback_de_dir, 0700)); EXPECT_BINDER_FAIL(service->restoreAppDataSnapshot(std::make_unique("BAR"), - "com.foo", 10000, -1, "", 0, FLAG_STORAGE_DE)); + "com.foo", 10000, "", 0, 41, FLAG_STORAGE_DE)); } } // namespace installd diff --git a/cmds/installd/tests/installd_utils_test.cpp b/cmds/installd/tests/installd_utils_test.cpp index 1782aa2816..e61eb6e52f 100644 --- a/cmds/installd/tests/installd_utils_test.cpp +++ b/cmds/installd/tests/installd_utils_test.cpp @@ -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 diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp index 5b487bb515..52ca0df121 100644 --- a/cmds/installd/utils.cpp +++ b/cmds/installd/utils.cpp @@ -197,32 +197,44 @@ std::string create_data_user_de_path(const char* volume_uuid, userid_t userid) { return StringPrintf("%s/user_de/%u", data.c_str(), userid); } - -std::string create_data_misc_ce_rollback_path(const char* volume_uuid, userid_t user) { +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); } -std::string create_data_misc_de_rollback_path(const char* volume_uuid, userid_t user) { +std::string create_data_misc_de_rollback_base_path(const char* volume_uuid, userid_t user) { return StringPrintf("%s/misc_de/%u/rollback", create_data_path(volume_uuid).c_str(), user); } +std::string create_data_misc_ce_rollback_path(const char* volume_uuid, userid_t user, + int32_t snapshot_id) { + return StringPrintf("%s/%d", create_data_misc_ce_rollback_base_path(volume_uuid, user).c_str(), + snapshot_id); +} + +std::string create_data_misc_de_rollback_path(const char* volume_uuid, userid_t user, + int32_t snapshot_id) { + return StringPrintf("%s/%d", create_data_misc_de_rollback_base_path(volume_uuid, user).c_str(), + snapshot_id); +} + std::string create_data_misc_ce_rollback_package_path(const char* volume_uuid, - userid_t user, const char* package_name) { + userid_t user, int32_t snapshot_id, const char* package_name) { return StringPrintf("%s/%s", - create_data_misc_ce_rollback_path(volume_uuid, user).c_str(), package_name); + create_data_misc_ce_rollback_path(volume_uuid, user, snapshot_id).c_str(), package_name); } std::string create_data_misc_ce_rollback_package_path(const char* volume_uuid, - userid_t user, const char* package_name, ino_t ce_rollback_inode) { - auto fallback = create_data_misc_ce_rollback_package_path(volume_uuid, user, package_name); - auto user_path = create_data_misc_ce_rollback_path(volume_uuid, user); + userid_t user, int32_t snapshot_id, const char* package_name, ino_t ce_rollback_inode) { + auto fallback = create_data_misc_ce_rollback_package_path(volume_uuid, user, snapshot_id, + package_name); + auto user_path = create_data_misc_ce_rollback_path(volume_uuid, user, snapshot_id); return resolve_ce_path_by_inode_or_fallback(user_path, ce_rollback_inode, fallback); } std::string create_data_misc_de_rollback_package_path(const char* volume_uuid, - userid_t user, const char* package_name) { + userid_t user, int32_t snapshot_id, const char* package_name) { return StringPrintf("%s/%s", - create_data_misc_de_rollback_path(volume_uuid, user).c_str(), package_name); + create_data_misc_de_rollback_path(volume_uuid, user, snapshot_id).c_str(), package_name); } /** @@ -528,6 +540,30 @@ static int _delete_dir_contents(DIR *d, return result; } +int create_dir_if_needed(const std::string& pathname, mode_t perms) { + struct stat st; + + int rc; + if ((rc = stat(pathname.c_str(), &st)) != 0) { + if (errno == ENOENT) { + return mkdir(pathname.c_str(), perms); + } else { + return rc; + } + } else if (!S_ISDIR(st.st_mode)) { + LOG(DEBUG) << pathname << " is not a folder"; + return -1; + } + + mode_t actual_perms = st.st_mode & ALLPERMS; + if (actual_perms != perms) { + LOG(WARNING) << pathname << " permissions " << actual_perms << " expected " << perms; + return -1; + } + + return 0; +} + int delete_dir_contents(const std::string& pathname, bool ignore_if_missing) { return delete_dir_contents(pathname.c_str(), 0, nullptr, ignore_if_missing); } diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h index 0711b34b9c..955d524069 100644 --- a/cmds/installd/utils.h +++ b/cmds/installd/utils.h @@ -61,14 +61,18 @@ std::string create_data_user_de_package_path(const char* volume_uuid, std::string create_data_user_ce_package_path_as_user_link( const char* volume_uuid, userid_t userid, const char* package_name); -std::string create_data_misc_ce_rollback_path(const char* volume_uuid, userid_t user); -std::string create_data_misc_de_rollback_path(const char* volume_uuid, userid_t user); +std::string create_data_misc_ce_rollback_base_path(const char* volume_uuid, userid_t user); +std::string create_data_misc_de_rollback_base_path(const char* volume_uuid, userid_t user); +std::string create_data_misc_ce_rollback_path(const char* volume_uuid, userid_t user, + int32_t snapshot_id); +std::string create_data_misc_de_rollback_path(const char* volume_uuid, userid_t user, + int32_t snapshot_id); std::string create_data_misc_ce_rollback_package_path(const char* volume_uuid, - userid_t user, const char* package_name); + userid_t user, int32_t snapshot_id, const char* package_name); std::string create_data_misc_ce_rollback_package_path(const char* volume_uuid, - userid_t user, const char* package_name, ino_t ce_rollback_inode); + userid_t user, int32_t snapshot_id, const char* package_name, ino_t ce_rollback_inode); std::string create_data_misc_de_rollback_package_path(const char* volume_uuid, - userid_t user, const char* package_name); + userid_t user, int32_t snapshot_id, const char* package_name); std::string create_data_media_path(const char* volume_uuid, userid_t userid); std::string create_data_media_obb_path(const char* volume_uuid, const char* package_name); @@ -109,6 +113,8 @@ int create_user_config_path(char path[PKG_PATH_MAX], userid_t userid); bool is_valid_filename(const std::string& name); bool is_valid_package_name(const std::string& packageName); +int create_dir_if_needed(const std::string& pathname, mode_t mode); + int delete_dir_contents(const std::string& pathname, bool ignore_if_missing = false); int delete_dir_contents_and_dir(const std::string& pathname, bool ignore_if_missing = false); -- 2.11.0