Merge pull request #422 from t-m-w/do-not-restore-storage-provider

Exclude storage provider from restore
This commit is contained in:
Torsten Grote 2022-08-15 17:29:01 -03:00 committed by GitHub
commit 3aa1b9f03d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 39 additions and 1 deletions

View file

@ -41,7 +41,12 @@ internal class ApkRestore(
@Suppress("BlockingMethodInNonBlockingContext") @Suppress("BlockingMethodInNonBlockingContext")
fun restore(backup: RestorableBackup) = flow { fun restore(backup: RestorableBackup) = flow {
// filter out packages without APK and get total // 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 val total = packages.size
var progress = 0 var progress = 0

View file

@ -118,6 +118,7 @@ internal class ApkBackupRestoreTest : TransportTest() {
every { metadataManager.salt } returns salt every { metadataManager.salt } returns salt
every { crypto.getNameForApk(salt, packageName) } returns name every { crypto.getNameForApk(salt, packageName) } returns name
every { crypto.getNameForApk(salt, packageName, splitName) } returns suffixName every { crypto.getNameForApk(salt, packageName, splitName) } returns suffixName
every { storagePlugin.providerPackageName } returns storageProviderPackageName
apkBackup.backupApkIfNecessary(packageInfo, PackageState.APK_AND_DATA, outputStreamGetter) apkBackup.backupApkIfNecessary(packageInfo, PackageState.APK_AND_DATA, outputStreamGetter)

View file

@ -97,6 +97,7 @@ internal class ApkRestoreTest : TransportTest() {
every { strictContext.cacheDir } returns File(tmpDir.toString()) every { strictContext.cacheDir } returns File(tmpDir.toString())
every { crypto.getNameForApk(salt, packageName, "") } returns name every { crypto.getNameForApk(salt, packageName, "") } returns name
coEvery { storagePlugin.getInputStream(token, name) } returns apkInputStream coEvery { storagePlugin.getInputStream(token, name) } returns apkInputStream
every { storagePlugin.providerPackageName } returns storageProviderPackageName
apkRestore.restore(backup).collectIndexed { i, value -> apkRestore.restore(backup).collectIndexed { i, value ->
assertQueuedFailFinished(i, value) assertQueuedFailFinished(i, value)
@ -112,6 +113,7 @@ internal class ApkRestoreTest : TransportTest() {
every { crypto.getNameForApk(salt, packageName, "") } returns name every { crypto.getNameForApk(salt, packageName, "") } returns name
coEvery { storagePlugin.getInputStream(token, name) } returns apkInputStream coEvery { storagePlugin.getInputStream(token, name) } returns apkInputStream
every { pm.getPackageArchiveInfo(any(), any()) } returns packageInfo every { pm.getPackageArchiveInfo(any(), any()) } returns packageInfo
every { storagePlugin.providerPackageName } returns storageProviderPackageName
apkRestore.restore(backup).collectIndexed { i, value -> apkRestore.restore(backup).collectIndexed { i, value ->
assertQueuedFailFinished(i, value) assertQueuedFailFinished(i, value)
@ -124,6 +126,7 @@ internal class ApkRestoreTest : TransportTest() {
coEvery { coEvery {
apkInstaller.install(match { it.size == 1 }, packageName, installerName, any()) apkInstaller.install(match { it.size == 1 }, packageName, installerName, any())
} throws SecurityException() } throws SecurityException()
every { storagePlugin.providerPackageName } returns storageProviderPackageName
apkRestore.restore(backup).collectIndexed { i, value -> apkRestore.restore(backup).collectIndexed { i, value ->
assertQueuedProgressFailFinished(i, value) assertQueuedProgressFailFinished(i, value)
@ -146,6 +149,7 @@ internal class ApkRestoreTest : TransportTest() {
coEvery { coEvery {
apkInstaller.install(match { it.size == 1 }, packageName, installerName, any()) apkInstaller.install(match { it.size == 1 }, packageName, installerName, any())
} returns installResult } returns installResult
every { storagePlugin.providerPackageName } returns storageProviderPackageName
apkRestore.restore(backup).collectIndexed { i, value -> apkRestore.restore(backup).collectIndexed { i, value ->
assertQueuedProgressSuccessFinished(i, value) assertQueuedProgressSuccessFinished(i, value)
@ -184,6 +188,7 @@ internal class ApkRestoreTest : TransportTest() {
coEvery { coEvery {
apkInstaller.install(match { it.size == 1 }, packageName, installerName, any()) apkInstaller.install(match { it.size == 1 }, packageName, installerName, any())
} returns installResult } returns installResult
every { storagePlugin.providerPackageName } returns storageProviderPackageName
apkRestore.restore(backup).collectIndexed { i, value -> apkRestore.restore(backup).collectIndexed { i, value ->
assertQueuedProgressSuccessFinished(i, value) assertQueuedProgressSuccessFinished(i, value)
@ -202,6 +207,7 @@ internal class ApkRestoreTest : TransportTest() {
cacheBaseApkAndGetInfo(tmpDir) cacheBaseApkAndGetInfo(tmpDir)
every { packageInfo.applicationInfo.loadIcon(pm) } returns icon every { packageInfo.applicationInfo.loadIcon(pm) } returns icon
every { storagePlugin.providerPackageName } returns storageProviderPackageName
if (willFail) { if (willFail) {
every { every {
@ -281,6 +287,7 @@ internal class ApkRestoreTest : TransportTest() {
every { every {
splitCompatChecker.isCompatible(deviceName, listOf(split1Name, split2Name)) splitCompatChecker.isCompatible(deviceName, listOf(split1Name, split2Name))
} returns false } returns false
every { storagePlugin.providerPackageName } returns storageProviderPackageName
apkRestore.restore(backup).collectIndexed { i, value -> apkRestore.restore(backup).collectIndexed { i, value ->
assertQueuedProgressFailFinished(i, value) assertQueuedProgressFailFinished(i, value)
@ -303,6 +310,7 @@ internal class ApkRestoreTest : TransportTest() {
coEvery { coEvery {
storagePlugin.getInputStream(token, suffixName) storagePlugin.getInputStream(token, suffixName)
} returns ByteArrayInputStream(getRandomByteArray()) } returns ByteArrayInputStream(getRandomByteArray())
every { storagePlugin.providerPackageName } returns storageProviderPackageName
apkRestore.restore(backup).collectIndexed { i, value -> apkRestore.restore(backup).collectIndexed { i, value ->
assertQueuedProgressFailFinished(i, value) assertQueuedProgressFailFinished(i, value)
@ -325,6 +333,7 @@ internal class ApkRestoreTest : TransportTest() {
every { splitCompatChecker.isCompatible(deviceName, listOf(splitName)) } returns true every { splitCompatChecker.isCompatible(deviceName, listOf(splitName)) } returns true
every { crypto.getNameForApk(salt, packageName, splitName) } returns suffixName every { crypto.getNameForApk(salt, packageName, splitName) } returns suffixName
coEvery { storagePlugin.getInputStream(token, suffixName) } throws IOException() coEvery { storagePlugin.getInputStream(token, suffixName) } throws IOException()
every { storagePlugin.providerPackageName } returns storageProviderPackageName
apkRestore.restore(backup).collectIndexed { i, value -> apkRestore.restore(backup).collectIndexed { i, value ->
assertQueuedProgressFailFinished(i, value) assertQueuedProgressFailFinished(i, value)
@ -363,6 +372,7 @@ internal class ApkRestoreTest : TransportTest() {
coEvery { storagePlugin.getInputStream(token, suffixName1) } returns split1InputStream coEvery { storagePlugin.getInputStream(token, suffixName1) } returns split1InputStream
every { crypto.getNameForApk(salt, packageName, split2Name) } returns suffixName2 every { crypto.getNameForApk(salt, packageName, split2Name) } returns suffixName2
coEvery { storagePlugin.getInputStream(token, suffixName2) } returns split2InputStream coEvery { storagePlugin.getInputStream(token, suffixName2) } returns split2InputStream
every { storagePlugin.providerPackageName } returns storageProviderPackageName
coEvery { coEvery {
apkInstaller.install(match { it.size == 3 }, packageName, installerName, any()) 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 { private fun swapPackages(packageMetadataMap: PackageMetadataMap): RestorableBackup {
val metadata = metadata.copy(packageMetadataMap = packageMetadataMap) val metadata = metadata.copy(packageMetadataMap = packageMetadataMap)
return backup.copy(backupMetadata = metadata) return backup.copy(backupMetadata = metadata)

View file

@ -61,6 +61,7 @@ internal abstract class TransportTest {
protected val salt = metadata.salt protected val salt = metadata.salt
protected val name = getRandomString(12) protected val name = getRandomString(12)
protected val name2 = getRandomString(23) protected val name2 = getRandomString(23)
protected val storageProviderPackageName = getRandomString(23)
init { init {
mockkStatic(Log::class) mockkStatic(Log::class)