installd: Add destroyAppDataSnapshot and corresponding binder API
- destroyAppDataSnapshot: deletes both ce and de snapshots (controlled
via storageFlags), for ce snapshot fallbacks to deleting it by it's
inode in case snapshot is not accessible (user hasn't unlocked the
phone yet).
- snapshotAppData: in case ce snapshot was requested, it will now return
inode if a folder with the snapshot. Otherwise it will return 0.
Passing ceSnapshotInode to destroyAppDataSnapshot should make logic
inside RollbackManagerService a bit easier. Since it will be able to
delete ce snapshot regardless of user unlocking their phone.
Bug: 112431924
Test: installd_service_test installd_utils_test
Change-Id: I015de12593b87f3000f004cc0a901a9208d0b693
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 9169aea..f3c0471 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -158,6 +158,15 @@
}
}
+binder::Status checkArgumentUuidTestOrNull(const std::unique_ptr<std::string>& uuid) {
+ if (!uuid || strcmp(uuid->c_str(), kTestUuid) == 0) {
+ return ok();
+ } else {
+ return exception(binder::Status::EX_ILLEGAL_ARGUMENT,
+ StringPrintf("UUID must be null or \"%s\", got: %s", kTestUuid, uuid->c_str()));
+ }
+}
+
binder::Status checkArgumentPackageName(const std::string& packageName) {
if (is_valid_package_name(packageName.c_str())) {
return ok();
@@ -210,6 +219,13 @@
} \
}
+#define CHECK_ARGUMENT_UUID_IS_TEST_OR_NULL(uuid) { \
+ auto status = checkArgumentUuidTestOrNull(uuid); \
+ if (!status.isOk()) { \
+ return status; \
+ } \
+} \
+
#define CHECK_ARGUMENT_PACKAGE_NAME(packageName) { \
binder::Status status = \
checkArgumentPackageName((packageName)); \
@@ -806,20 +822,21 @@
binder::Status InstalldNativeService::snapshotAppData(
const std::unique_ptr<std::string>& volumeUuid,
- const std::string& packageName, int32_t user, int32_t storageFlags) {
+ const std::string& packageName, int32_t user, int32_t storageFlags,
+ int64_t* _aidl_return) {
ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_UUID_IS_TEST_OR_NULL(volumeUuid);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
std::lock_guard<std::recursive_mutex> lock(mLock);
const char* volume_uuid = volumeUuid ? volumeUuid->c_str() : nullptr;
const char* package_name = packageName.c_str();
- if (volume_uuid && strcmp(volume_uuid, kTestUuid)) {
- return exception(binder::Status::EX_ILLEGAL_ARGUMENT,
- StringPrintf("volumeUuid must be null or \"%s\", got: %s", kTestUuid, volume_uuid));
- }
-
binder::Status res = ok();
+ // Default result to 0, it will be populated with inode of ce data snapshot
+ // if FLAG_STORAGE_CE has been passed.
+ if (_aidl_return != nullptr) *_aidl_return = 0;
+
bool clear_ce_on_exit = false;
bool clear_de_on_exit = false;
@@ -900,6 +917,16 @@
clear_ce_on_exit = true;
return res;
}
+ if (_aidl_return != nullptr) {
+ auto ce_snapshot_path = create_data_misc_ce_rollback_package_path(volume_uuid, user,
+ 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);
+ clear_ce_on_exit = true;
+ return res;
+ }
+ }
}
return res;
@@ -910,17 +937,13 @@
const int32_t appId, const int64_t ceDataInode, const std::string& seInfo,
const int32_t user, int32_t storageFlags) {
ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_UUID_IS_TEST_OR_NULL(volumeUuid);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
std::lock_guard<std::recursive_mutex> lock(mLock);
const char* volume_uuid = volumeUuid ? volumeUuid->c_str() : nullptr;
const char* package_name = packageName.c_str();
- if (volume_uuid && strcmp(volume_uuid, kTestUuid)) {
- return exception(binder::Status::EX_ILLEGAL_ARGUMENT,
- StringPrintf("volumeUuid must be null or \"%s\", got: %s", kTestUuid, volume_uuid));
- }
-
auto from_ce = create_data_misc_ce_rollback_package_path(volume_uuid,
user, package_name);
auto from_de = create_data_misc_de_rollback_package_path(volume_uuid,
@@ -971,6 +994,39 @@
return restoreconAppData(volumeUuid, packageName, user, storageFlags, appId, seInfo);
}
+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) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_UUID_IS_TEST_OR_NULL(volumeUuid);
+ CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
+
+ const char* volume_uuid = volumeUuid ? volumeUuid->c_str() : nullptr;
+ const char* package_name = packageName.c_str();
+
+ if (storageFlags & FLAG_STORAGE_DE) {
+ auto de_snapshot_path = create_data_misc_de_rollback_package_path(volume_uuid,
+ user, package_name);
+
+ int res = delete_dir_contents_and_dir(de_snapshot_path, true /* ignore_if_missing */);
+ if (res != 0) {
+ return error(res, "Failed clearing snapshot " + de_snapshot_path);
+ }
+ }
+
+ if (storageFlags & FLAG_STORAGE_CE) {
+ auto ce_snapshot_path = create_data_misc_ce_rollback_package_path(volume_uuid,
+ user, 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);
+ }
+ }
+ return ok();
+}
+
+
binder::Status InstalldNativeService::moveCompleteApp(const std::unique_ptr<std::string>& fromUuid,
const std::unique_ptr<std::string>& toUuid, const std::string& packageName,
const std::string& dataAppName, int32_t appId, const std::string& seInfo,