summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Oli Lan <olilan@google.com> 2020-03-16 18:18:41 +0000
committer Oli Lan <olilan@google.com> 2020-03-26 16:17:38 +0000
commit035abbb1180b6f8a1e1ac2e4931a541e5044beff (patch)
tree2c7d926815bcf48a0b70bd0aa4805a89a64f6801
parent08768df3075638d108991e379a2887e182dbcd10 (diff)
Add installd method to delete CE snapshots.
This adds a new installd service method to allow CE snapshots to be deleted. The existing method for deleting snapshots - destroyAppDataSnapshot - does not work if the user is not unlocked. Although it takes the inode of the snapshot directory, it still cannot access the parent directory and so the delete fails. The new method is destroyCeSnapshotsNotSpecified, as it deletes all CE snapshots for the specified user, except for those with snapshot ids in a provided list. RollbackManager will call this method when the user unlocks, passing a list of all current rollbacks. This will ensure that all expired snapshots are deleted. It will also allow any "orphaned" snapshots (e.g. from tests or previous snapshots that have not been deleted) to be cleaned up. The new method is expected to be called when the user has unlocked - it will fail if the user is not unlocked. Bug: 147806409 Test: atest AppDataSnapshotTest#DestroyCeSnapshotsNotSpecified (new test) Change-Id: Iab048733ac794261f906ffb9e3b19f331dc67a76 Merged-In: Iab048733ac794261f906ffb9e3b19f331dc67a76
-rw-r--r--cmds/installd/InstalldNativeService.cpp39
-rw-r--r--cmds/installd/InstalldNativeService.h2
-rw-r--r--cmds/installd/binder/android/os/IInstalld.aidl2
-rw-r--r--cmds/installd/tests/installd_service_test.cpp40
4 files changed, 83 insertions, 0 deletions
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index dc0583e3db..6fee11b566 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -42,6 +42,7 @@
#include <android-base/file.h>
#include <android-base/logging.h>
+#include <android-base/parseint.h>
#include <android-base/properties.h>
#include <android-base/scopeguard.h>
#include <android-base/stringprintf.h>
@@ -74,6 +75,7 @@
#define LOG_TAG "installd"
#endif
+using android::base::ParseUint;
using android::base::StringPrintf;
using std::endl;
@@ -1090,6 +1092,43 @@ binder::Status InstalldNativeService::destroyAppDataSnapshot(
return ok();
}
+binder::Status InstalldNativeService::destroyCeSnapshotsNotSpecified(
+ const std::optional<std::string> &volumeUuid, const int32_t user,
+ const std::vector<int32_t>& retainSnapshotIds) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_UUID_IS_TEST_OR_NULL(volumeUuid);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
+
+ const char* volume_uuid = volumeUuid ? volumeUuid->c_str() : nullptr;
+
+ auto base_path = create_data_misc_ce_rollback_base_path(volume_uuid, user);
+
+ std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(base_path.c_str()), closedir);
+ if (!dir) {
+ return error(-1, "Failed to open rollback base dir " + base_path);
+ }
+
+ struct dirent* ent;
+ while ((ent = readdir(dir.get()))) {
+ if (ent->d_type != DT_DIR) {
+ continue;
+ }
+
+ uint snapshot_id;
+ bool parse_ok = ParseUint(ent->d_name, &snapshot_id);
+ if (parse_ok &&
+ std::find(retainSnapshotIds.begin(), retainSnapshotIds.end(),
+ snapshot_id) == retainSnapshotIds.end()) {
+ auto rollback_path = create_data_misc_ce_rollback_path(
+ volume_uuid, user, snapshot_id);
+ int res = delete_dir_contents_and_dir(rollback_path, true /* ignore_if_missing */);
+ if (res != 0) {
+ return error(res, "Failed clearing snapshot " + rollback_path);
+ }
+ }
+ }
+ return ok();
+}
binder::Status InstalldNativeService::moveCompleteApp(const std::optional<std::string>& fromUuid,
const std::optional<std::string>& toUuid, const std::string& packageName,
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index 80a88b4c27..1a8da5f865 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -69,6 +69,8 @@ public:
binder::Status destroyAppDataSnapshot(const std::optional<std::string> &volumeUuid,
const std::string& packageName, const int32_t user, const int64_t ceSnapshotInode,
const int32_t snapshotId, int32_t storageFlags);
+ binder::Status destroyCeSnapshotsNotSpecified(const std::optional<std::string> &volumeUuid,
+ const int32_t user, const std::vector<int32_t>& retainSnapshotIds);
binder::Status getAppSize(const std::optional<std::string>& uuid,
const std::vector<std::string>& 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 d99bcc8d13..0b9a444c58 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -109,6 +109,8 @@ interface IInstalld {
int userId, int snapshotId, int storageFlags);
void restoreAppDataSnapshot(@nullable @utf8InCpp String uuid, in @utf8InCpp String packageName,
int appId, @utf8InCpp String seInfo, int user, int snapshotId, int storageflags);
+ void destroyCeSnapshotsNotSpecified(@nullable @utf8InCpp String uuid, int userId,
+ in int[] retainSnapshotIds);
void destroyAppDataSnapshot(@nullable @utf8InCpp String uuid, @utf8InCpp String packageName,
int userId, long ceSnapshotInode, int snapshotId, int storageFlags);
diff --git a/cmds/installd/tests/installd_service_test.cpp b/cmds/installd/tests/installd_service_test.cpp
index 727867720d..1e7559d174 100644
--- a/cmds/installd/tests/installd_service_test.cpp
+++ b/cmds/installd/tests/installd_service_test.cpp
@@ -640,6 +640,46 @@ TEST_F(AppDataSnapshotTest, DestroyAppDataSnapshot_WrongVolumeUuid) {
"com.foo", 0, 0, 43, FLAG_STORAGE_DE).isOk());
}
+TEST_F(AppDataSnapshotTest, DestroyCeSnapshotsNotSpecified) {
+ auto rollback_ce_dir_in_1 = create_data_misc_ce_rollback_path("TEST", 0, 1543);
+ auto rollback_ce_dir_in_2 = create_data_misc_ce_rollback_path("TEST", 0, 77);
+ auto rollback_ce_dir_out_1 = create_data_misc_ce_rollback_path("TEST", 0, 1500);
+ auto rollback_ce_dir_out_2 = create_data_misc_ce_rollback_path("TEST", 0, 2);
+
+ // Create snapshots
+ ASSERT_TRUE(mkdirs(rollback_ce_dir_in_1 + "/com.foo/", 0700));
+ ASSERT_TRUE(android::base::WriteStringToFile(
+ "CE_RESTORE_CONTENT", rollback_ce_dir_in_1 + "/com.foo/file1",
+ 0700, 10000, 20000, false /* follow_symlinks */));
+
+ ASSERT_TRUE(mkdirs(rollback_ce_dir_in_2 + "/com.foo/", 0700));
+ ASSERT_TRUE(android::base::WriteStringToFile(
+ "CE_RESTORE_CONTENT", rollback_ce_dir_in_2 + "/com.foo/file1",
+ 0700, 10000, 20000, false /* follow_symlinks */));
+
+ ASSERT_TRUE(mkdirs(rollback_ce_dir_out_1 + "/com.foo/", 0700));
+ ASSERT_TRUE(android::base::WriteStringToFile(
+ "CE_RESTORE_CONTENT", rollback_ce_dir_out_1 + "/com.foo/file1",
+ 0700, 10000, 20000, false /* follow_symlinks */));
+
+ ASSERT_TRUE(mkdirs(rollback_ce_dir_out_2 + "/com.foo/", 0700));
+ ASSERT_TRUE(android::base::WriteStringToFile(
+ "CE_RESTORE_CONTENT", rollback_ce_dir_out_2 + "/com.foo/file1",
+ 0700, 10000, 20000, false /* follow_symlinks */));
+
+ ASSERT_TRUE(service->destroyCeSnapshotsNotSpecified(
+ std::make_optional<std::string>("TEST"), 0, { 1543, 77 }).isOk());
+
+ // Check only snapshots not specified are deleted.
+ struct stat sb;
+ ASSERT_EQ(0, stat((rollback_ce_dir_in_1 + "/com.foo").c_str(), &sb));
+ ASSERT_EQ(0, stat((rollback_ce_dir_in_2 + "/com.foo").c_str(), &sb));
+ ASSERT_EQ(-1, stat((rollback_ce_dir_out_1 + "/com.foo").c_str(), &sb));
+ ASSERT_EQ(ENOENT, errno);
+ ASSERT_EQ(-1, stat((rollback_ce_dir_out_2 + "/com.foo").c_str(), &sb));
+ ASSERT_EQ(ENOENT, errno);
+}
+
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.