From 7901aec408b742c0a741fd2080fd8d3f444d7f3a Mon Sep 17 00:00:00 2001 From: t-m-w Date: Thu, 30 Jun 2022 22:48:14 +0000 Subject: [PATCH] Exclude storage provider from restore and update affected unit tests, additionally adding a test to ensure the storage provider is excluded. Otherwise, when the storage provider (i.e. DAVx5 or Nextcloud) is installed, it will be terminated, and the restoration process will be interrupted. Change-Id: Ic1be201b673d718b416009ff61f5d975c89b6a62 --- .../seedvault/restore/install/ApkRestore.kt | 7 ++++- .../restore/install/ApkBackupRestoreTest.kt | 1 + .../restore/install/ApkRestoreTest.kt | 31 +++++++++++++++++++ .../seedvault/transport/TransportTest.kt | 1 + 4 files changed, 39 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/stevesoltys/seedvault/restore/install/ApkRestore.kt b/app/src/main/java/com/stevesoltys/seedvault/restore/install/ApkRestore.kt index 4c7a9a1a..59600b3d 100644 --- a/app/src/main/java/com/stevesoltys/seedvault/restore/install/ApkRestore.kt +++ b/app/src/main/java/com/stevesoltys/seedvault/restore/install/ApkRestore.kt @@ -41,7 +41,12 @@ internal class ApkRestore( @Suppress("BlockingMethodInNonBlockingContext") fun restore(backup: RestorableBackup) = flow { // filter out packages without APK and get total - val packages = backup.packageMetadataMap.filter { it.value.hasApk() } + val packages = backup.packageMetadataMap.filter { + // We also need to exclude the DocumentsProvider used to retrieve backup data. + // Otherwise, it gets killed when we install it, terminating our restoration. + val isStorageProvider = it.key == storagePlugin.providerPackageName + it.value.hasApk() && !isStorageProvider + } val total = packages.size var progress = 0 diff --git a/app/src/test/java/com/stevesoltys/seedvault/restore/install/ApkBackupRestoreTest.kt b/app/src/test/java/com/stevesoltys/seedvault/restore/install/ApkBackupRestoreTest.kt index d384e6ac..97012e3d 100644 --- a/app/src/test/java/com/stevesoltys/seedvault/restore/install/ApkBackupRestoreTest.kt +++ b/app/src/test/java/com/stevesoltys/seedvault/restore/install/ApkBackupRestoreTest.kt @@ -118,6 +118,7 @@ internal class ApkBackupRestoreTest : TransportTest() { every { metadataManager.salt } returns salt every { crypto.getNameForApk(salt, packageName) } returns name every { crypto.getNameForApk(salt, packageName, splitName) } returns suffixName + every { storagePlugin.providerPackageName } returns storageProviderPackageName apkBackup.backupApkIfNecessary(packageInfo, PackageState.APK_AND_DATA, outputStreamGetter) diff --git a/app/src/test/java/com/stevesoltys/seedvault/restore/install/ApkRestoreTest.kt b/app/src/test/java/com/stevesoltys/seedvault/restore/install/ApkRestoreTest.kt index 86be9580..ad730402 100644 --- a/app/src/test/java/com/stevesoltys/seedvault/restore/install/ApkRestoreTest.kt +++ b/app/src/test/java/com/stevesoltys/seedvault/restore/install/ApkRestoreTest.kt @@ -97,6 +97,7 @@ internal class ApkRestoreTest : TransportTest() { every { strictContext.cacheDir } returns File(tmpDir.toString()) every { crypto.getNameForApk(salt, packageName, "") } returns name coEvery { storagePlugin.getInputStream(token, name) } returns apkInputStream + every { storagePlugin.providerPackageName } returns storageProviderPackageName apkRestore.restore(backup).collectIndexed { i, value -> assertQueuedFailFinished(i, value) @@ -112,6 +113,7 @@ internal class ApkRestoreTest : TransportTest() { every { crypto.getNameForApk(salt, packageName, "") } returns name coEvery { storagePlugin.getInputStream(token, name) } returns apkInputStream every { pm.getPackageArchiveInfo(any(), any()) } returns packageInfo + every { storagePlugin.providerPackageName } returns storageProviderPackageName apkRestore.restore(backup).collectIndexed { i, value -> assertQueuedFailFinished(i, value) @@ -124,6 +126,7 @@ internal class ApkRestoreTest : TransportTest() { coEvery { apkInstaller.install(match { it.size == 1 }, packageName, installerName, any()) } throws SecurityException() + every { storagePlugin.providerPackageName } returns storageProviderPackageName apkRestore.restore(backup).collectIndexed { i, value -> assertQueuedProgressFailFinished(i, value) @@ -146,6 +149,7 @@ internal class ApkRestoreTest : TransportTest() { coEvery { apkInstaller.install(match { it.size == 1 }, packageName, installerName, any()) } returns installResult + every { storagePlugin.providerPackageName } returns storageProviderPackageName apkRestore.restore(backup).collectIndexed { i, value -> assertQueuedProgressSuccessFinished(i, value) @@ -184,6 +188,7 @@ internal class ApkRestoreTest : TransportTest() { coEvery { apkInstaller.install(match { it.size == 1 }, packageName, installerName, any()) } returns installResult + every { storagePlugin.providerPackageName } returns storageProviderPackageName apkRestore.restore(backup).collectIndexed { i, value -> assertQueuedProgressSuccessFinished(i, value) @@ -202,6 +207,7 @@ internal class ApkRestoreTest : TransportTest() { cacheBaseApkAndGetInfo(tmpDir) every { packageInfo.applicationInfo.loadIcon(pm) } returns icon + every { storagePlugin.providerPackageName } returns storageProviderPackageName if (willFail) { every { @@ -281,6 +287,7 @@ internal class ApkRestoreTest : TransportTest() { every { splitCompatChecker.isCompatible(deviceName, listOf(split1Name, split2Name)) } returns false + every { storagePlugin.providerPackageName } returns storageProviderPackageName apkRestore.restore(backup).collectIndexed { i, value -> assertQueuedProgressFailFinished(i, value) @@ -303,6 +310,7 @@ internal class ApkRestoreTest : TransportTest() { coEvery { storagePlugin.getInputStream(token, suffixName) } returns ByteArrayInputStream(getRandomByteArray()) + every { storagePlugin.providerPackageName } returns storageProviderPackageName apkRestore.restore(backup).collectIndexed { i, value -> assertQueuedProgressFailFinished(i, value) @@ -325,6 +333,7 @@ internal class ApkRestoreTest : TransportTest() { every { splitCompatChecker.isCompatible(deviceName, listOf(splitName)) } returns true every { crypto.getNameForApk(salt, packageName, splitName) } returns suffixName coEvery { storagePlugin.getInputStream(token, suffixName) } throws IOException() + every { storagePlugin.providerPackageName } returns storageProviderPackageName apkRestore.restore(backup).collectIndexed { i, value -> assertQueuedProgressFailFinished(i, value) @@ -363,6 +372,7 @@ internal class ApkRestoreTest : TransportTest() { coEvery { storagePlugin.getInputStream(token, suffixName1) } returns split1InputStream every { crypto.getNameForApk(salt, packageName, split2Name) } returns suffixName2 coEvery { storagePlugin.getInputStream(token, suffixName2) } returns split2InputStream + every { storagePlugin.providerPackageName } returns storageProviderPackageName coEvery { apkInstaller.install(match { it.size == 3 }, packageName, installerName, any()) @@ -381,6 +391,27 @@ internal class ApkRestoreTest : TransportTest() { } } + @Test + fun `storage provider app does not get reinstalled`(@TempDir tmpDir: Path) = runBlocking { + // set the storage provider package name to match our current package name, + // and ensure that the current package is therefore skipped. + every { storagePlugin.providerPackageName } returns packageName + + apkRestore.restore(backup).collectIndexed { i, value -> + when (i) { + 0 -> { + assertFalse(value.isFinished) + } + 1 -> { + // the only package provided should have been filtered, leaving 0 packages. + assertEquals(0, value.total) + assertTrue(value.isFinished) + } + else -> fail("more values emitted") + } + } + } + private fun swapPackages(packageMetadataMap: PackageMetadataMap): RestorableBackup { val metadata = metadata.copy(packageMetadataMap = packageMetadataMap) return backup.copy(backupMetadata = metadata) diff --git a/app/src/test/java/com/stevesoltys/seedvault/transport/TransportTest.kt b/app/src/test/java/com/stevesoltys/seedvault/transport/TransportTest.kt index 9d441528..2f4e0cd2 100644 --- a/app/src/test/java/com/stevesoltys/seedvault/transport/TransportTest.kt +++ b/app/src/test/java/com/stevesoltys/seedvault/transport/TransportTest.kt @@ -61,6 +61,7 @@ internal abstract class TransportTest { protected val salt = metadata.salt protected val name = getRandomString(12) protected val name2 = getRandomString(23) + protected val storageProviderPackageName = getRandomString(23) init { mockkStatic(Log::class)