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
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index dc0583e..6fee11b 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 @@
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,