diff --git a/app/src/androidTest/java/com/stevesoltys/seedvault/PluginTest.kt b/app/src/androidTest/java/com/stevesoltys/seedvault/PluginTest.kt index 9b4bc464..2045add9 100644 --- a/app/src/androidTest/java/com/stevesoltys/seedvault/PluginTest.kt +++ b/app/src/androidTest/java/com/stevesoltys/seedvault/PluginTest.kt @@ -3,18 +3,14 @@ package com.stevesoltys.seedvault import androidx.test.core.content.pm.PackageInfoBuilder import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.platform.app.InstrumentationRegistry -import com.stevesoltys.seedvault.plugins.saf.DocumentsProviderBackupPlugin -import com.stevesoltys.seedvault.plugins.saf.DocumentsProviderFullRestorePlugin -import com.stevesoltys.seedvault.plugins.saf.DocumentsProviderKVRestorePlugin -import com.stevesoltys.seedvault.plugins.saf.DocumentsProviderRestorePlugin +import com.stevesoltys.seedvault.plugins.LegacyStoragePlugin +import com.stevesoltys.seedvault.plugins.StoragePlugin +import com.stevesoltys.seedvault.plugins.saf.DocumentsProviderStoragePlugin +import com.stevesoltys.seedvault.plugins.saf.DocumentsProviderLegacyPlugin import com.stevesoltys.seedvault.plugins.saf.DocumentsStorage import com.stevesoltys.seedvault.plugins.saf.FILE_BACKUP_METADATA import com.stevesoltys.seedvault.plugins.saf.deleteContents import com.stevesoltys.seedvault.settings.SettingsManager -import com.stevesoltys.seedvault.transport.backup.BackupPlugin -import com.stevesoltys.seedvault.transport.restore.FullRestorePlugin -import com.stevesoltys.seedvault.transport.restore.KVRestorePlugin -import com.stevesoltys.seedvault.transport.restore.RestorePlugin import io.mockk.every import io.mockk.mockk import kotlinx.coroutines.Dispatchers @@ -39,14 +35,10 @@ class PluginTest : KoinComponent { private val mockedSettingsManager: SettingsManager = mockk() private val storage = DocumentsStorage(context, mockedSettingsManager) - private val backupPlugin: BackupPlugin = DocumentsProviderBackupPlugin(context, storage) - - private val kvRestorePlugin: KVRestorePlugin = - DocumentsProviderKVRestorePlugin(context, storage) - private val fullRestorePlugin: FullRestorePlugin = - DocumentsProviderFullRestorePlugin(context, storage) - private val restorePlugin: RestorePlugin = - DocumentsProviderRestorePlugin(context, storage, kvRestorePlugin, fullRestorePlugin) + private val storagePlugin: StoragePlugin = DocumentsProviderStoragePlugin(context, storage) + @Suppress("Deprecation") + private val legacyStoragePlugin: LegacyStoragePlugin = + DocumentsProviderLegacyPlugin(context, storage) private val token = System.currentTimeMillis() - 365L * 24L * 60L * 60L * 1000L private val packageInfo = PackageInfoBuilder.newBuilder().setPackageName("org.example").build() @@ -67,7 +59,7 @@ class PluginTest : KoinComponent { @Test fun testProviderPackageName() { - assertNotNull(backupPlugin.providerPackageName) + assertNotNull(storagePlugin.providerPackageName) } /** @@ -80,38 +72,38 @@ class PluginTest : KoinComponent { @Test fun testInitializationAndRestoreSets() = runBlocking(Dispatchers.IO) { // no backups available initially - assertEquals(0, backupPlugin.getAvailableBackups()?.toList()?.size) + assertEquals(0, storagePlugin.getAvailableBackups()?.toList()?.size) val uri = settingsManager.getStorage()?.getDocumentFile(context)?.uri ?: error("no storage") - assertFalse(backupPlugin.hasBackup(uri)) + assertFalse(storagePlugin.hasBackup(uri)) // prepare returned tokens requested when initializing device every { mockedSettingsManager.getToken() } returnsMany listOf(token, token + 1, token + 1) // start new restore set and initialize device afterwards - backupPlugin.startNewRestoreSet(token) - backupPlugin.initializeDevice() + storagePlugin.startNewRestoreSet(token) + storagePlugin.initializeDevice() // write metadata (needed for backup to be recognized) - backupPlugin.getOutputStream(token, FILE_BACKUP_METADATA) + storagePlugin.getOutputStream(token, FILE_BACKUP_METADATA) .writeAndClose(getRandomByteArray()) // one backup available now - assertEquals(1, backupPlugin.getAvailableBackups()?.toList()?.size) - assertTrue(backupPlugin.hasBackup(uri)) + assertEquals(1, storagePlugin.getAvailableBackups()?.toList()?.size) + assertTrue(storagePlugin.hasBackup(uri)) // initializing again (with another restore set) does add a restore set - backupPlugin.startNewRestoreSet(token + 1) - backupPlugin.initializeDevice() - backupPlugin.getOutputStream(token + 1, FILE_BACKUP_METADATA) + storagePlugin.startNewRestoreSet(token + 1) + storagePlugin.initializeDevice() + storagePlugin.getOutputStream(token + 1, FILE_BACKUP_METADATA) .writeAndClose(getRandomByteArray()) - assertEquals(2, backupPlugin.getAvailableBackups()?.toList()?.size) - assertTrue(backupPlugin.hasBackup(uri)) + assertEquals(2, storagePlugin.getAvailableBackups()?.toList()?.size) + assertTrue(storagePlugin.hasBackup(uri)) // initializing again (without new restore set) doesn't change number of restore sets - backupPlugin.initializeDevice() - backupPlugin.getOutputStream(token + 1, FILE_BACKUP_METADATA) + storagePlugin.initializeDevice() + storagePlugin.getOutputStream(token + 1, FILE_BACKUP_METADATA) .writeAndClose(getRandomByteArray()) - assertEquals(2, backupPlugin.getAvailableBackups()?.toList()?.size) + assertEquals(2, storagePlugin.getAvailableBackups()?.toList()?.size) // ensure that the new backup dir exist assertTrue(storage.currentSetDir!!.exists()) @@ -121,15 +113,15 @@ class PluginTest : KoinComponent { fun testMetadataWriteRead() = runBlocking(Dispatchers.IO) { every { mockedSettingsManager.getToken() } returns token - backupPlugin.startNewRestoreSet(token) - backupPlugin.initializeDevice() + storagePlugin.startNewRestoreSet(token) + storagePlugin.initializeDevice() // write metadata val metadata = getRandomByteArray() - backupPlugin.getOutputStream(token, FILE_BACKUP_METADATA).writeAndClose(metadata) + storagePlugin.getOutputStream(token, FILE_BACKUP_METADATA).writeAndClose(metadata) // get available backups, expect only one with our token and no error - var availableBackups = backupPlugin.getAvailableBackups()?.toList() + var availableBackups = storagePlugin.getAvailableBackups()?.toList() check(availableBackups != null) assertEquals(1, availableBackups.size) assertEquals(token, availableBackups[0].token) @@ -138,9 +130,9 @@ class PluginTest : KoinComponent { assertReadEquals(metadata, availableBackups[0].inputStreamRetriever()) // initializing again (without changing storage) keeps restore set with same token - backupPlugin.initializeDevice() - backupPlugin.getOutputStream(token, FILE_BACKUP_METADATA).writeAndClose(metadata) - availableBackups = backupPlugin.getAvailableBackups()?.toList() + storagePlugin.initializeDevice() + storagePlugin.getOutputStream(token, FILE_BACKUP_METADATA).writeAndClose(metadata) + availableBackups = storagePlugin.getAvailableBackups()?.toList() check(availableBackups != null) assertEquals(1, availableBackups.size) assertEquals(token, availableBackups[0].token) @@ -157,22 +149,25 @@ class PluginTest : KoinComponent { // write random bytes as APK val apk1 = getRandomByteArray(1337 * 1024) - backupPlugin.getOutputStream(token, "${packageInfo.packageName}.apk").writeAndClose(apk1) + storagePlugin.getOutputStream(token, "${packageInfo.packageName}.apk").writeAndClose(apk1) // assert that read APK bytes match what was written - assertReadEquals(apk1, restorePlugin.getApkInputStream(token, packageInfo.packageName, "")) + assertReadEquals( + apk1, + legacyStoragePlugin.getApkInputStream(token, packageInfo.packageName, "") + ) // write random bytes as another APK val suffix2 = getRandomBase64(23) val apk2 = getRandomByteArray(23 * 1024 * 1024) - backupPlugin.getOutputStream(token, "${packageInfo2.packageName}$suffix2.apk") + storagePlugin.getOutputStream(token, "${packageInfo2.packageName}$suffix2.apk") .writeAndClose(apk2) // assert that read APK bytes match what was written assertReadEquals( apk2, - restorePlugin.getApkInputStream(token, packageInfo2.packageName, suffix2) + legacyStoragePlugin.getApkInputStream(token, packageInfo2.packageName, suffix2) ) } @@ -185,41 +180,41 @@ class PluginTest : KoinComponent { val name2 = getRandomBase64() // no data available initially - assertFalse(backupPlugin.hasData(token, name1)) - assertFalse(backupPlugin.hasData(token, name2)) + assertFalse(storagePlugin.hasData(token, name1)) + assertFalse(storagePlugin.hasData(token, name2)) // write full backup data val data = getRandomByteArray(5 * 1024 * 1024) - backupPlugin.getOutputStream(token, name1).writeAndClose(data) + storagePlugin.getOutputStream(token, name1).writeAndClose(data) // data is available now, but only this token - assertTrue(backupPlugin.hasData(token, name1)) - assertFalse(backupPlugin.hasData(token + 1, name1)) + assertTrue(storagePlugin.hasData(token, name1)) + assertFalse(storagePlugin.hasData(token + 1, name1)) // restore data matches backed up data - assertReadEquals(data, backupPlugin.getInputStream(token, name1)) + assertReadEquals(data, storagePlugin.getInputStream(token, name1)) // write and check data for second package val data2 = getRandomByteArray(5 * 1024 * 1024) - backupPlugin.getOutputStream(token, name2).writeAndClose(data2) - assertTrue(backupPlugin.hasData(token, name2)) - assertReadEquals(data2, backupPlugin.getInputStream(token, name2)) + storagePlugin.getOutputStream(token, name2).writeAndClose(data2) + assertTrue(storagePlugin.hasData(token, name2)) + assertReadEquals(data2, storagePlugin.getInputStream(token, name2)) // remove data of first package again and ensure that no more data is found - backupPlugin.removeData(token, name1) - assertFalse(backupPlugin.hasData(token, name1)) + storagePlugin.removeData(token, name1) + assertFalse(storagePlugin.hasData(token, name1)) // second package is still there - assertTrue(backupPlugin.hasData(token, name2)) + assertTrue(storagePlugin.hasData(token, name2)) // ensure that it gets deleted as well - backupPlugin.removeData(token, name2) - assertFalse(backupPlugin.hasData(token, name2)) + storagePlugin.removeData(token, name2) + assertFalse(storagePlugin.hasData(token, name2)) } private fun initStorage(token: Long) = runBlocking { every { mockedSettingsManager.getToken() } returns token - backupPlugin.initializeDevice() + storagePlugin.initializeDevice() } } diff --git a/app/src/main/java/com/stevesoltys/seedvault/transport/restore/KVRestorePlugin.kt b/app/src/main/java/com/stevesoltys/seedvault/plugins/LegacyStoragePlugin.kt similarity index 61% rename from app/src/main/java/com/stevesoltys/seedvault/transport/restore/KVRestorePlugin.kt rename to app/src/main/java/com/stevesoltys/seedvault/plugins/LegacyStoragePlugin.kt index 6cdd18c5..1dbf797b 100644 --- a/app/src/main/java/com/stevesoltys/seedvault/transport/restore/KVRestorePlugin.kt +++ b/app/src/main/java/com/stevesoltys/seedvault/plugins/LegacyStoragePlugin.kt @@ -1,10 +1,11 @@ -package com.stevesoltys.seedvault.transport.restore +package com.stevesoltys.seedvault.plugins import android.content.pm.PackageInfo import java.io.IOException import java.io.InputStream -interface KVRestorePlugin { +@Deprecated("Only for old v0 backup format") +interface LegacyStoragePlugin { /** * Return true if there is data stored for the given package. @@ -36,4 +37,19 @@ interface KVRestorePlugin { key: String ): InputStream + /** + * Return true if there is data stored for the given package. + */ + @Throws(IOException::class) + suspend fun hasDataForFullPackage(token: Long, packageInfo: PackageInfo): Boolean + + @Throws(IOException::class) + suspend fun getInputStreamForPackage(token: Long, packageInfo: PackageInfo): InputStream + + /** + * Returns an [InputStream] for the given token, for reading an APK that is to be restored. + */ + @Throws(IOException::class) + suspend fun getApkInputStream(token: Long, packageName: String, suffix: String): InputStream + } diff --git a/app/src/main/java/com/stevesoltys/seedvault/transport/backup/BackupPlugin.kt b/app/src/main/java/com/stevesoltys/seedvault/plugins/StoragePlugin.kt similarity index 96% rename from app/src/main/java/com/stevesoltys/seedvault/transport/backup/BackupPlugin.kt rename to app/src/main/java/com/stevesoltys/seedvault/plugins/StoragePlugin.kt index 5157bd1e..5ba57345 100644 --- a/app/src/main/java/com/stevesoltys/seedvault/transport/backup/BackupPlugin.kt +++ b/app/src/main/java/com/stevesoltys/seedvault/plugins/StoragePlugin.kt @@ -1,4 +1,4 @@ -package com.stevesoltys.seedvault.transport.backup +package com.stevesoltys.seedvault.plugins import android.app.backup.RestoreSet import android.net.Uri @@ -7,7 +7,7 @@ import java.io.IOException import java.io.InputStream import java.io.OutputStream -interface BackupPlugin { +interface StoragePlugin { /** * Start a new [RestoreSet] with the given token. diff --git a/app/src/main/java/com/stevesoltys/seedvault/plugins/saf/DocumentsProviderFullRestorePlugin.kt b/app/src/main/java/com/stevesoltys/seedvault/plugins/saf/DocumentsProviderFullRestorePlugin.kt deleted file mode 100644 index 639dd036..00000000 --- a/app/src/main/java/com/stevesoltys/seedvault/plugins/saf/DocumentsProviderFullRestorePlugin.kt +++ /dev/null @@ -1,33 +0,0 @@ -package com.stevesoltys.seedvault.plugins.saf - -import android.content.Context -import android.content.pm.PackageInfo -import com.stevesoltys.seedvault.transport.restore.FullRestorePlugin -import java.io.IOException -import java.io.InputStream - -@Suppress("BlockingMethodInNonBlockingContext", "Deprecation") -@Deprecated("Use only for v0 restore") -internal class DocumentsProviderFullRestorePlugin( - private val context: Context, - private val documentsStorage: DocumentsStorage -) : FullRestorePlugin { - - @Throws(IOException::class) - override suspend fun hasDataForPackage(token: Long, packageInfo: PackageInfo): Boolean { - val backupDir = documentsStorage.getFullBackupDir(token) ?: return false - return backupDir.findFileBlocking(context, packageInfo.packageName) != null - } - - @Throws(IOException::class) - override suspend fun getInputStreamForPackage( - token: Long, - packageInfo: PackageInfo - ): InputStream { - val backupDir = documentsStorage.getFullBackupDir(token) ?: throw IOException() - val packageFile = - backupDir.findFileBlocking(context, packageInfo.packageName) ?: throw IOException() - return documentsStorage.getInputStream(packageFile) - } - -} diff --git a/app/src/main/java/com/stevesoltys/seedvault/plugins/saf/DocumentsProviderKVRestorePlugin.kt b/app/src/main/java/com/stevesoltys/seedvault/plugins/saf/DocumentsProviderLegacyPlugin.kt similarity index 60% rename from app/src/main/java/com/stevesoltys/seedvault/plugins/saf/DocumentsProviderKVRestorePlugin.kt rename to app/src/main/java/com/stevesoltys/seedvault/plugins/saf/DocumentsProviderLegacyPlugin.kt index 76e4c25e..8e5d0952 100644 --- a/app/src/main/java/com/stevesoltys/seedvault/plugins/saf/DocumentsProviderKVRestorePlugin.kt +++ b/app/src/main/java/com/stevesoltys/seedvault/plugins/saf/DocumentsProviderLegacyPlugin.kt @@ -2,17 +2,19 @@ package com.stevesoltys.seedvault.plugins.saf import android.content.Context import android.content.pm.PackageInfo +import androidx.annotation.WorkerThread import androidx.documentfile.provider.DocumentFile -import com.stevesoltys.seedvault.transport.restore.KVRestorePlugin +import com.stevesoltys.seedvault.plugins.LegacyStoragePlugin +import java.io.FileNotFoundException import java.io.IOException import java.io.InputStream -@Suppress("BlockingMethodInNonBlockingContext", "Deprecation") -@Deprecated("Use only for v0 restore") -internal class DocumentsProviderKVRestorePlugin( +@WorkerThread +@Suppress("BlockingMethodInNonBlockingContext", "Deprecation") // all methods do I/O +internal class DocumentsProviderLegacyPlugin( private val context: Context, private val storage: DocumentsStorage -) : KVRestorePlugin { +) : LegacyStoragePlugin { private var packageDir: DocumentFile? = null private var packageChildren: List? = null @@ -59,4 +61,33 @@ internal class DocumentsProviderKVRestorePlugin( return storage.getInputStream(keyFile) } + @Throws(IOException::class) + override suspend fun hasDataForFullPackage(token: Long, packageInfo: PackageInfo): Boolean { + val backupDir = storage.getFullBackupDir(token) ?: return false + return backupDir.findFileBlocking(context, packageInfo.packageName) != null + } + + @Throws(IOException::class) + override suspend fun getInputStreamForPackage( + token: Long, + packageInfo: PackageInfo + ): InputStream { + val backupDir = storage.getFullBackupDir(token) ?: throw IOException() + val packageFile = + backupDir.findFileBlocking(context, packageInfo.packageName) ?: throw IOException() + return storage.getInputStream(packageFile) + } + + @Throws(IOException::class) + override suspend fun getApkInputStream( + token: Long, + packageName: String, + suffix: String + ): InputStream { + val setDir = storage.getSetDir(token) ?: throw IOException() + val file = setDir.findFileBlocking(context, "$packageName$suffix.apk") + ?: throw FileNotFoundException() + return storage.getInputStream(file) + } + } diff --git a/app/src/main/java/com/stevesoltys/seedvault/plugins/saf/DocumentsProviderModule.kt b/app/src/main/java/com/stevesoltys/seedvault/plugins/saf/DocumentsProviderModule.kt index b3ff0d4e..638ee990 100644 --- a/app/src/main/java/com/stevesoltys/seedvault/plugins/saf/DocumentsProviderModule.kt +++ b/app/src/main/java/com/stevesoltys/seedvault/plugins/saf/DocumentsProviderModule.kt @@ -1,18 +1,14 @@ package com.stevesoltys.seedvault.plugins.saf -import com.stevesoltys.seedvault.transport.backup.BackupPlugin -import com.stevesoltys.seedvault.transport.restore.FullRestorePlugin -import com.stevesoltys.seedvault.transport.restore.KVRestorePlugin -import com.stevesoltys.seedvault.transport.restore.RestorePlugin +import com.stevesoltys.seedvault.plugins.LegacyStoragePlugin +import com.stevesoltys.seedvault.plugins.StoragePlugin import org.koin.android.ext.koin.androidContext import org.koin.dsl.module val documentsProviderModule = module { single { DocumentsStorage(androidContext(), get()) } - single { DocumentsProviderBackupPlugin(androidContext(), get()) } - - single { DocumentsProviderKVRestorePlugin(androidContext(), get()) } - single { DocumentsProviderFullRestorePlugin(androidContext(), get()) } - single { DocumentsProviderRestorePlugin(androidContext(), get(), get(), get()) } + single { DocumentsProviderStoragePlugin(androidContext(), get()) } + @Suppress("Deprecation") + single { DocumentsProviderLegacyPlugin(androidContext(), get()) } } diff --git a/app/src/main/java/com/stevesoltys/seedvault/plugins/saf/DocumentsProviderRestorePlugin.kt b/app/src/main/java/com/stevesoltys/seedvault/plugins/saf/DocumentsProviderRestorePlugin.kt deleted file mode 100644 index b701aa5e..00000000 --- a/app/src/main/java/com/stevesoltys/seedvault/plugins/saf/DocumentsProviderRestorePlugin.kt +++ /dev/null @@ -1,33 +0,0 @@ -package com.stevesoltys.seedvault.plugins.saf - -import android.content.Context -import androidx.annotation.WorkerThread -import com.stevesoltys.seedvault.transport.restore.FullRestorePlugin -import com.stevesoltys.seedvault.transport.restore.KVRestorePlugin -import com.stevesoltys.seedvault.transport.restore.RestorePlugin -import java.io.FileNotFoundException -import java.io.IOException -import java.io.InputStream - -@WorkerThread -@Suppress("BlockingMethodInNonBlockingContext") // all methods do I/O -internal class DocumentsProviderRestorePlugin( - private val context: Context, - private val storage: DocumentsStorage, - override val kvRestorePlugin: KVRestorePlugin, - override val fullRestorePlugin: FullRestorePlugin -) : RestorePlugin { - - @Throws(IOException::class) - override suspend fun getApkInputStream( - token: Long, - packageName: String, - suffix: String - ): InputStream { - val setDir = storage.getSetDir(token) ?: throw IOException() - val file = setDir.findFileBlocking(context, "$packageName$suffix.apk") - ?: throw FileNotFoundException() - return storage.getInputStream(file) - } - -} diff --git a/app/src/main/java/com/stevesoltys/seedvault/plugins/saf/DocumentsProviderBackupPlugin.kt b/app/src/main/java/com/stevesoltys/seedvault/plugins/saf/DocumentsProviderStoragePlugin.kt similarity index 95% rename from app/src/main/java/com/stevesoltys/seedvault/plugins/saf/DocumentsProviderBackupPlugin.kt rename to app/src/main/java/com/stevesoltys/seedvault/plugins/saf/DocumentsProviderStoragePlugin.kt index 7f64a620..ee150973 100644 --- a/app/src/main/java/com/stevesoltys/seedvault/plugins/saf/DocumentsProviderBackupPlugin.kt +++ b/app/src/main/java/com/stevesoltys/seedvault/plugins/saf/DocumentsProviderStoragePlugin.kt @@ -5,20 +5,20 @@ import android.content.pm.PackageManager import android.net.Uri import android.util.Log import androidx.documentfile.provider.DocumentFile -import com.stevesoltys.seedvault.transport.backup.BackupPlugin -import com.stevesoltys.seedvault.transport.backup.EncryptedMetadata +import com.stevesoltys.seedvault.plugins.EncryptedMetadata +import com.stevesoltys.seedvault.plugins.StoragePlugin import java.io.FileNotFoundException import java.io.IOException import java.io.InputStream import java.io.OutputStream -private val TAG = DocumentsProviderBackupPlugin::class.java.simpleName +private val TAG = DocumentsProviderStoragePlugin::class.java.simpleName @Suppress("BlockingMethodInNonBlockingContext") -internal class DocumentsProviderBackupPlugin( +internal class DocumentsProviderStoragePlugin( private val context: Context, private val storage: DocumentsStorage -) : BackupPlugin { +) : StoragePlugin { private val packageManager: PackageManager = context.packageManager 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 dcc41656..6ff73c50 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 @@ -8,16 +8,16 @@ import android.util.Log import com.stevesoltys.seedvault.crypto.Crypto import com.stevesoltys.seedvault.metadata.ApkSplit import com.stevesoltys.seedvault.metadata.PackageMetadata +import com.stevesoltys.seedvault.plugins.LegacyStoragePlugin +import com.stevesoltys.seedvault.plugins.StoragePlugin import com.stevesoltys.seedvault.restore.RestorableBackup import com.stevesoltys.seedvault.restore.install.ApkInstallState.FAILED_SYSTEM_APP import com.stevesoltys.seedvault.restore.install.ApkInstallState.IN_PROGRESS import com.stevesoltys.seedvault.restore.install.ApkInstallState.QUEUED import com.stevesoltys.seedvault.restore.install.ApkInstallState.SUCCEEDED -import com.stevesoltys.seedvault.transport.backup.BackupPlugin import com.stevesoltys.seedvault.transport.backup.copyStreamsAndGetHash import com.stevesoltys.seedvault.transport.backup.getSignatures import com.stevesoltys.seedvault.transport.backup.isSystemApp -import com.stevesoltys.seedvault.transport.restore.RestorePlugin import kotlinx.coroutines.TimeoutCancellationException import kotlinx.coroutines.flow.FlowCollector import kotlinx.coroutines.flow.flow @@ -28,8 +28,9 @@ private val TAG = ApkRestore::class.java.simpleName internal class ApkRestore( private val context: Context, - private val backupPlugin: BackupPlugin, - private val restorePlugin: RestorePlugin, + private val storagePlugin: StoragePlugin, + @Suppress("Deprecation") + private val legacyStoragePlugin: LegacyStoragePlugin, private val crypto: Crypto, private val splitCompatChecker: ApkSplitCompatibilityChecker, private val apkInstaller: ApkInstaller @@ -157,7 +158,7 @@ internal class ApkRestore( } /** - * Retrieves APK splits from [RestorePlugin] and caches them locally. + * Retrieves APK splits from [StoragePlugin] and caches them locally. * * @throws SecurityException if a split has an unexpected SHA-256 hash. * @return a list of all APKs that need to be installed @@ -195,7 +196,7 @@ internal class ApkRestore( } /** - * Retrieves an APK from the [RestorePlugin] and caches it locally + * Retrieves an APK from the [StoragePlugin] and caches it locally * while calculating its SHA-256 hash. * * @return a [Pair] of the cached [File] and SHA-256 hash. @@ -214,10 +215,10 @@ internal class ApkRestore( // copy APK to cache file and calculate SHA-256 hash while we are at it val inputStream = if (version == 0.toByte()) { @Suppress("Deprecation") - restorePlugin.getApkInputStream(token, packageName, suffix) + legacyStoragePlugin.getApkInputStream(token, packageName, suffix) } else { val name = crypto.getNameForApk(salt, packageName, suffix) - backupPlugin.getInputStream(token, name) + storagePlugin.getInputStream(token, name) } val sha256 = copyStreamsAndGetHash(inputStream, cachedApk.outputStream()) return Pair(cachedApk, sha256) diff --git a/app/src/main/java/com/stevesoltys/seedvault/transport/backup/BackupCoordinator.kt b/app/src/main/java/com/stevesoltys/seedvault/transport/backup/BackupCoordinator.kt index 7e19d9dd..17a66541 100644 --- a/app/src/main/java/com/stevesoltys/seedvault/transport/backup/BackupCoordinator.kt +++ b/app/src/main/java/com/stevesoltys/seedvault/transport/backup/BackupCoordinator.kt @@ -29,6 +29,7 @@ import com.stevesoltys.seedvault.metadata.PackageState.NO_DATA import com.stevesoltys.seedvault.metadata.PackageState.QUOTA_EXCEEDED import com.stevesoltys.seedvault.metadata.PackageState.UNKNOWN_ERROR import com.stevesoltys.seedvault.metadata.PackageState.WAS_STOPPED +import com.stevesoltys.seedvault.plugins.StoragePlugin import com.stevesoltys.seedvault.plugins.saf.FILE_BACKUP_METADATA import com.stevesoltys.seedvault.settings.SettingsManager import com.stevesoltys.seedvault.ui.notification.BackupNotificationManager @@ -64,7 +65,7 @@ private class CoordinatorState( @Suppress("BlockingMethodInNonBlockingContext") internal class BackupCoordinator( private val context: Context, - private val plugin: BackupPlugin, + private val plugin: StoragePlugin, private val kv: KVBackup, private val full: FullBackup, private val apkBackup: ApkBackup, @@ -508,7 +509,7 @@ internal class BackupCoordinator( } } - private suspend fun BackupPlugin.getMetadataOutputStream(token: Long? = null): OutputStream { + private suspend fun StoragePlugin.getMetadataOutputStream(token: Long? = null): OutputStream { val t = token ?: settingsManager.getToken() ?: throw IOException("no current token") return getOutputStream(t, FILE_BACKUP_METADATA) } diff --git a/app/src/main/java/com/stevesoltys/seedvault/transport/backup/FullBackup.kt b/app/src/main/java/com/stevesoltys/seedvault/transport/backup/FullBackup.kt index e14899b2..06ebbbaa 100644 --- a/app/src/main/java/com/stevesoltys/seedvault/transport/backup/FullBackup.kt +++ b/app/src/main/java/com/stevesoltys/seedvault/transport/backup/FullBackup.kt @@ -11,6 +11,7 @@ import android.util.Log import com.stevesoltys.seedvault.crypto.Crypto import com.stevesoltys.seedvault.header.VERSION import com.stevesoltys.seedvault.header.getADForFull +import com.stevesoltys.seedvault.plugins.StoragePlugin import com.stevesoltys.seedvault.settings.SettingsManager import libcore.io.IoUtils.closeQuietly import java.io.EOFException @@ -38,7 +39,7 @@ private val TAG = FullBackup::class.java.simpleName @Suppress("BlockingMethodInNonBlockingContext") internal class FullBackup( - private val plugin: BackupPlugin, + private val plugin: StoragePlugin, private val settingsManager: SettingsManager, private val inputFactory: InputFactory, private val crypto: Crypto diff --git a/app/src/main/java/com/stevesoltys/seedvault/transport/backup/KVBackup.kt b/app/src/main/java/com/stevesoltys/seedvault/transport/backup/KVBackup.kt index 9d32ca0a..50e5ed7a 100644 --- a/app/src/main/java/com/stevesoltys/seedvault/transport/backup/KVBackup.kt +++ b/app/src/main/java/com/stevesoltys/seedvault/transport/backup/KVBackup.kt @@ -12,6 +12,7 @@ import android.util.Log import com.stevesoltys.seedvault.crypto.Crypto import com.stevesoltys.seedvault.header.VERSION import com.stevesoltys.seedvault.header.getADForKV +import com.stevesoltys.seedvault.plugins.StoragePlugin import com.stevesoltys.seedvault.settings.SettingsManager import java.io.IOException import java.util.zip.GZIPOutputStream @@ -31,7 +32,7 @@ private val TAG = KVBackup::class.java.simpleName @Suppress("BlockingMethodInNonBlockingContext") internal class KVBackup( - private val plugin: BackupPlugin, + private val plugin: StoragePlugin, private val settingsManager: SettingsManager, private val inputFactory: InputFactory, private val crypto: Crypto, diff --git a/app/src/main/java/com/stevesoltys/seedvault/transport/restore/FullRestore.kt b/app/src/main/java/com/stevesoltys/seedvault/transport/restore/FullRestore.kt index 67fc1da3..2828971a 100644 --- a/app/src/main/java/com/stevesoltys/seedvault/transport/restore/FullRestore.kt +++ b/app/src/main/java/com/stevesoltys/seedvault/transport/restore/FullRestore.kt @@ -12,7 +12,8 @@ import com.stevesoltys.seedvault.header.HeaderReader import com.stevesoltys.seedvault.header.MAX_SEGMENT_LENGTH import com.stevesoltys.seedvault.header.UnsupportedVersionException import com.stevesoltys.seedvault.header.getADForFull -import com.stevesoltys.seedvault.transport.backup.BackupPlugin +import com.stevesoltys.seedvault.plugins.LegacyStoragePlugin +import com.stevesoltys.seedvault.plugins.StoragePlugin import libcore.io.IoUtils.closeQuietly import java.io.EOFException import java.io.IOException @@ -33,8 +34,9 @@ private val TAG = FullRestore::class.java.simpleName @Suppress("BlockingMethodInNonBlockingContext") internal class FullRestore( - private val plugin: BackupPlugin, - private val legacyPlugin: FullRestorePlugin, + private val plugin: StoragePlugin, + @Suppress("Deprecation") + private val legacyPlugin: LegacyStoragePlugin, private val outputFactory: OutputFactory, private val headerReader: HeaderReader, private val crypto: Crypto @@ -52,7 +54,7 @@ internal class FullRestore( @Throws(IOException::class) @Deprecated("Use BackupPlugin#hasData() instead") suspend fun hasDataForPackage(token: Long, packageInfo: PackageInfo): Boolean { - return legacyPlugin.hasDataForPackage(token, packageInfo) + return legacyPlugin.hasDataForFullPackage(token, packageInfo) } /** diff --git a/app/src/main/java/com/stevesoltys/seedvault/transport/restore/FullRestorePlugin.kt b/app/src/main/java/com/stevesoltys/seedvault/transport/restore/FullRestorePlugin.kt deleted file mode 100644 index dacd0e0b..00000000 --- a/app/src/main/java/com/stevesoltys/seedvault/transport/restore/FullRestorePlugin.kt +++ /dev/null @@ -1,18 +0,0 @@ -package com.stevesoltys.seedvault.transport.restore - -import android.content.pm.PackageInfo -import java.io.IOException -import java.io.InputStream - -interface FullRestorePlugin { - - /** - * Return true if there is data stored for the given package. - */ - @Throws(IOException::class) - suspend fun hasDataForPackage(token: Long, packageInfo: PackageInfo): Boolean - - @Throws(IOException::class) - suspend fun getInputStreamForPackage(token: Long, packageInfo: PackageInfo): InputStream - -} diff --git a/app/src/main/java/com/stevesoltys/seedvault/transport/restore/KVRestore.kt b/app/src/main/java/com/stevesoltys/seedvault/transport/restore/KVRestore.kt index 7af153fa..520b564a 100644 --- a/app/src/main/java/com/stevesoltys/seedvault/transport/restore/KVRestore.kt +++ b/app/src/main/java/com/stevesoltys/seedvault/transport/restore/KVRestore.kt @@ -15,7 +15,8 @@ import com.stevesoltys.seedvault.header.HeaderReader import com.stevesoltys.seedvault.header.UnsupportedVersionException import com.stevesoltys.seedvault.header.VERSION import com.stevesoltys.seedvault.header.getADForKV -import com.stevesoltys.seedvault.transport.backup.BackupPlugin +import com.stevesoltys.seedvault.plugins.LegacyStoragePlugin +import com.stevesoltys.seedvault.plugins.StoragePlugin import com.stevesoltys.seedvault.transport.backup.KVDb import com.stevesoltys.seedvault.transport.backup.KvDbManager import libcore.io.IoUtils.closeQuietly @@ -41,8 +42,9 @@ private val TAG = KVRestore::class.java.simpleName @Suppress("BlockingMethodInNonBlockingContext") internal class KVRestore( - private val plugin: BackupPlugin, - private val legacyPlugin: KVRestorePlugin, + private val plugin: StoragePlugin, + @Suppress("Deprecation") + private val legacyPlugin: LegacyStoragePlugin, private val outputFactory: OutputFactory, private val headerReader: HeaderReader, private val crypto: Crypto, diff --git a/app/src/main/java/com/stevesoltys/seedvault/transport/restore/RestoreCoordinator.kt b/app/src/main/java/com/stevesoltys/seedvault/transport/restore/RestoreCoordinator.kt index 586a846f..d73e738b 100644 --- a/app/src/main/java/com/stevesoltys/seedvault/transport/restore/RestoreCoordinator.kt +++ b/app/src/main/java/com/stevesoltys/seedvault/transport/restore/RestoreCoordinator.kt @@ -21,7 +21,7 @@ import com.stevesoltys.seedvault.metadata.DecryptionFailedException import com.stevesoltys.seedvault.metadata.MetadataManager import com.stevesoltys.seedvault.metadata.MetadataReader import com.stevesoltys.seedvault.settings.SettingsManager -import com.stevesoltys.seedvault.transport.backup.BackupPlugin +import com.stevesoltys.seedvault.plugins.StoragePlugin import com.stevesoltys.seedvault.ui.notification.BackupNotificationManager import java.io.IOException @@ -46,7 +46,7 @@ internal class RestoreCoordinator( private val settingsManager: SettingsManager, private val metadataManager: MetadataManager, private val notificationManager: BackupNotificationManager, - private val plugin: BackupPlugin, + private val plugin: StoragePlugin, private val kv: KVRestore, private val full: FullRestore, private val metadataReader: MetadataReader diff --git a/app/src/main/java/com/stevesoltys/seedvault/transport/restore/RestoreModule.kt b/app/src/main/java/com/stevesoltys/seedvault/transport/restore/RestoreModule.kt index 7ef3c4ca..7ea9248b 100644 --- a/app/src/main/java/com/stevesoltys/seedvault/transport/restore/RestoreModule.kt +++ b/app/src/main/java/com/stevesoltys/seedvault/transport/restore/RestoreModule.kt @@ -5,8 +5,8 @@ import org.koin.dsl.module val restoreModule = module { single { OutputFactory() } - single { KVRestore(get(), get().kvRestorePlugin, get(), get(), get(), get()) } - single { FullRestore(get(), get().fullRestorePlugin, get(), get(), get()) } + single { KVRestore(get(), get(), get(), get(), get(), get()) } + single { FullRestore(get(), get(), get(), get(), get()) } single { RestoreCoordinator(androidContext(), get(), get(), get(), get(), get(), get(), get(), get()) } diff --git a/app/src/main/java/com/stevesoltys/seedvault/transport/restore/RestorePlugin.kt b/app/src/main/java/com/stevesoltys/seedvault/transport/restore/RestorePlugin.kt deleted file mode 100644 index 6fa75cda..00000000 --- a/app/src/main/java/com/stevesoltys/seedvault/transport/restore/RestorePlugin.kt +++ /dev/null @@ -1,19 +0,0 @@ -package com.stevesoltys.seedvault.transport.restore - -import java.io.IOException -import java.io.InputStream - -interface RestorePlugin { - - val kvRestorePlugin: KVRestorePlugin - - val fullRestorePlugin: FullRestorePlugin - - /** - * Returns an [InputStream] for the given token, for reading an APK that is to be restored. - */ - @Throws(IOException::class) - @Deprecated("Use only for v0 restores") - suspend fun getApkInputStream(token: Long, packageName: String, suffix: String): InputStream - -} diff --git a/app/src/main/java/com/stevesoltys/seedvault/ui/storage/RestoreStorageViewModel.kt b/app/src/main/java/com/stevesoltys/seedvault/ui/storage/RestoreStorageViewModel.kt index 330567a9..05b17dbb 100644 --- a/app/src/main/java/com/stevesoltys/seedvault/ui/storage/RestoreStorageViewModel.kt +++ b/app/src/main/java/com/stevesoltys/seedvault/ui/storage/RestoreStorageViewModel.kt @@ -7,7 +7,7 @@ import androidx.lifecycle.viewModelScope import com.stevesoltys.seedvault.R import com.stevesoltys.seedvault.plugins.saf.DIRECTORY_ROOT import com.stevesoltys.seedvault.settings.SettingsManager -import com.stevesoltys.seedvault.transport.backup.BackupPlugin +import com.stevesoltys.seedvault.plugins.StoragePlugin import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import java.io.IOException @@ -16,7 +16,7 @@ private val TAG = RestoreStorageViewModel::class.java.simpleName internal class RestoreStorageViewModel( private val app: Application, - private val backupPlugin: BackupPlugin, + private val storagePlugin: StoragePlugin, settingsManager: SettingsManager ) : StorageViewModel(app, settingsManager) { @@ -25,7 +25,7 @@ internal class RestoreStorageViewModel( override fun onLocationSet(uri: Uri) { viewModelScope.launch(Dispatchers.IO) { val hasBackup = try { - backupPlugin.hasBackup(uri) + storagePlugin.hasBackup(uri) } catch (e: IOException) { Log.e(TAG, "Error reading URI: $uri", e) false diff --git a/app/src/test/java/com/stevesoltys/seedvault/plugins/saf/BackupPluginTest.kt b/app/src/test/java/com/stevesoltys/seedvault/plugins/saf/StoragePluginTest.kt similarity index 93% rename from app/src/test/java/com/stevesoltys/seedvault/plugins/saf/BackupPluginTest.kt rename to app/src/test/java/com/stevesoltys/seedvault/plugins/saf/StoragePluginTest.kt index fa8b2e50..c4a1e074 100644 --- a/app/src/test/java/com/stevesoltys/seedvault/plugins/saf/BackupPluginTest.kt +++ b/app/src/test/java/com/stevesoltys/seedvault/plugins/saf/StoragePluginTest.kt @@ -12,11 +12,11 @@ import kotlinx.coroutines.runBlocking import org.junit.jupiter.api.Test @Suppress("BlockingMethodInNonBlockingContext") -internal class BackupPluginTest : BackupTest() { +internal class StoragePluginTest : BackupTest() { private val storage = mockk() - private val plugin = DocumentsProviderBackupPlugin(context, storage) + private val plugin = DocumentsProviderStoragePlugin(context, storage) private val setDir: DocumentFile = mockk() private val backupFile: DocumentFile = mockk() 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 981ace2e..7f3bbf4f 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 @@ -11,11 +11,11 @@ import com.stevesoltys.seedvault.metadata.ApkSplit import com.stevesoltys.seedvault.metadata.PackageMetadata import com.stevesoltys.seedvault.metadata.PackageMetadataMap import com.stevesoltys.seedvault.metadata.PackageState +import com.stevesoltys.seedvault.plugins.LegacyStoragePlugin +import com.stevesoltys.seedvault.plugins.StoragePlugin import com.stevesoltys.seedvault.restore.RestorableBackup import com.stevesoltys.seedvault.transport.TransportTest import com.stevesoltys.seedvault.transport.backup.ApkBackup -import com.stevesoltys.seedvault.transport.backup.BackupPlugin -import com.stevesoltys.seedvault.transport.restore.RestorePlugin import io.mockk.coEvery import io.mockk.every import io.mockk.mockk @@ -46,16 +46,17 @@ internal class ApkBackupRestoreTest : TransportTest() { private val strictContext: Context = mockk().apply { every { packageManager } returns pm } - private val backupPlugin: BackupPlugin = mockk() - private val restorePlugin: RestorePlugin = mockk() + @Suppress("Deprecation") + private val legacyStoragePlugin: LegacyStoragePlugin = mockk() + private val storagePlugin: StoragePlugin = mockk() private val splitCompatChecker: ApkSplitCompatibilityChecker = mockk() private val apkInstaller: ApkInstaller = mockk() private val apkBackup = ApkBackup(pm, crypto, settingsManager, metadataManager) private val apkRestore: ApkRestore = ApkRestore( context = strictContext, - backupPlugin = backupPlugin, - restorePlugin = restorePlugin, + storagePlugin = storagePlugin, + legacyStoragePlugin = legacyStoragePlugin, crypto = crypto, splitCompatChecker = splitCompatChecker, apkInstaller = apkInstaller @@ -129,7 +130,7 @@ internal class ApkBackupRestoreTest : TransportTest() { every { strictContext.cacheDir } returns tmpFile every { crypto.getNameForApk(salt, packageName, "") } returns name - coEvery { backupPlugin.getInputStream(token, name) } returns inputStream + coEvery { storagePlugin.getInputStream(token, name) } returns inputStream every { pm.getPackageArchiveInfo(capture(apkPath), any()) } returns packageInfo every { @Suppress("UNRESOLVED_REFERENCE") @@ -143,7 +144,7 @@ internal class ApkBackupRestoreTest : TransportTest() { splitCompatChecker.isCompatible(metadata.deviceName, listOf(splitName)) } returns true every { crypto.getNameForApk(salt, packageName, splitName) } returns suffixName - coEvery { backupPlugin.getInputStream(token, suffixName) } returns splitInputStream + coEvery { storagePlugin.getInputStream(token, suffixName) } returns splitInputStream coEvery { apkInstaller.install(capture(cacheFiles), packageName, installerName, any()) } returns MutableInstallResult(1).apply { 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 6f616083..86be9580 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 @@ -14,6 +14,8 @@ import com.stevesoltys.seedvault.getRandomString import com.stevesoltys.seedvault.metadata.ApkSplit import com.stevesoltys.seedvault.metadata.PackageMetadata import com.stevesoltys.seedvault.metadata.PackageMetadataMap +import com.stevesoltys.seedvault.plugins.LegacyStoragePlugin +import com.stevesoltys.seedvault.plugins.StoragePlugin import com.stevesoltys.seedvault.restore.RestorableBackup import com.stevesoltys.seedvault.restore.install.ApkInstallState.FAILED import com.stevesoltys.seedvault.restore.install.ApkInstallState.FAILED_SYSTEM_APP @@ -21,8 +23,6 @@ import com.stevesoltys.seedvault.restore.install.ApkInstallState.IN_PROGRESS import com.stevesoltys.seedvault.restore.install.ApkInstallState.QUEUED import com.stevesoltys.seedvault.restore.install.ApkInstallState.SUCCEEDED import com.stevesoltys.seedvault.transport.TransportTest -import com.stevesoltys.seedvault.transport.backup.BackupPlugin -import com.stevesoltys.seedvault.transport.restore.RestorePlugin import io.mockk.coEvery import io.mockk.every import io.mockk.mockk @@ -50,15 +50,15 @@ internal class ApkRestoreTest : TransportTest() { private val strictContext: Context = mockk().apply { every { packageManager } returns pm } - private val backupPlugin: BackupPlugin = mockk() - private val restorePlugin: RestorePlugin = mockk() + private val storagePlugin: StoragePlugin = mockk() + private val legacyStoragePlugin: LegacyStoragePlugin = mockk() private val splitCompatChecker: ApkSplitCompatibilityChecker = mockk() private val apkInstaller: ApkInstaller = mockk() private val apkRestore: ApkRestore = ApkRestore( strictContext, - backupPlugin, - restorePlugin, + storagePlugin, + legacyStoragePlugin, crypto, splitCompatChecker, apkInstaller @@ -96,7 +96,7 @@ internal class ApkRestoreTest : TransportTest() { every { strictContext.cacheDir } returns File(tmpDir.toString()) every { crypto.getNameForApk(salt, packageName, "") } returns name - coEvery { backupPlugin.getInputStream(token, name) } returns apkInputStream + coEvery { storagePlugin.getInputStream(token, name) } returns apkInputStream apkRestore.restore(backup).collectIndexed { i, value -> assertQueuedFailFinished(i, value) @@ -110,7 +110,7 @@ internal class ApkRestoreTest : TransportTest() { every { strictContext.cacheDir } returns File(tmpDir.toString()) every { crypto.getNameForApk(salt, packageName, "") } returns name - coEvery { backupPlugin.getInputStream(token, name) } returns apkInputStream + coEvery { storagePlugin.getInputStream(token, name) } returns apkInputStream every { pm.getPackageArchiveInfo(any(), any()) } returns packageInfo apkRestore.restore(backup).collectIndexed { i, value -> @@ -169,7 +169,9 @@ internal class ApkRestoreTest : TransportTest() { every { strictContext.cacheDir } returns File(tmpDir.toString()) @Suppress("Deprecation") - coEvery { restorePlugin.getApkInputStream(token, packageName, "") } returns apkInputStream + coEvery { + legacyStoragePlugin.getApkInputStream(token, packageName, "") + } returns apkInputStream every { pm.getPackageArchiveInfo(any(), any()) } returns packageInfo every { @Suppress("UNRESOLVED_REFERENCE") @@ -299,7 +301,7 @@ internal class ApkRestoreTest : TransportTest() { every { splitCompatChecker.isCompatible(deviceName, listOf(splitName)) } returns true every { crypto.getNameForApk(salt, packageName, splitName) } returns suffixName coEvery { - backupPlugin.getInputStream(token, suffixName) + storagePlugin.getInputStream(token, suffixName) } returns ByteArrayInputStream(getRandomByteArray()) apkRestore.restore(backup).collectIndexed { i, value -> @@ -322,7 +324,7 @@ internal class ApkRestoreTest : TransportTest() { every { splitCompatChecker.isCompatible(deviceName, listOf(splitName)) } returns true every { crypto.getNameForApk(salt, packageName, splitName) } returns suffixName - coEvery { backupPlugin.getInputStream(token, suffixName) } throws IOException() + coEvery { storagePlugin.getInputStream(token, suffixName) } throws IOException() apkRestore.restore(backup).collectIndexed { i, value -> assertQueuedProgressFailFinished(i, value) @@ -358,9 +360,9 @@ internal class ApkRestoreTest : TransportTest() { val suffixName1 = getRandomString() val suffixName2 = getRandomString() every { crypto.getNameForApk(salt, packageName, split1Name) } returns suffixName1 - coEvery { backupPlugin.getInputStream(token, suffixName1) } returns split1InputStream + coEvery { storagePlugin.getInputStream(token, suffixName1) } returns split1InputStream every { crypto.getNameForApk(salt, packageName, split2Name) } returns suffixName2 - coEvery { backupPlugin.getInputStream(token, suffixName2) } returns split2InputStream + coEvery { storagePlugin.getInputStream(token, suffixName2) } returns split2InputStream coEvery { apkInstaller.install(match { it.size == 3 }, packageName, installerName, any()) @@ -387,7 +389,7 @@ internal class ApkRestoreTest : TransportTest() { private fun cacheBaseApkAndGetInfo(tmpDir: Path) { every { strictContext.cacheDir } returns File(tmpDir.toString()) every { crypto.getNameForApk(salt, packageName, "") } returns name - coEvery { backupPlugin.getInputStream(token, name) } returns apkInputStream + coEvery { storagePlugin.getInputStream(token, name) } returns apkInputStream every { pm.getPackageArchiveInfo(any(), any()) } returns packageInfo every { @Suppress("UNRESOLVED_REFERENCE") diff --git a/app/src/test/java/com/stevesoltys/seedvault/transport/CoordinatorIntegrationTest.kt b/app/src/test/java/com/stevesoltys/seedvault/transport/CoordinatorIntegrationTest.kt index 282a6bac..b7ee1c08 100644 --- a/app/src/test/java/com/stevesoltys/seedvault/transport/CoordinatorIntegrationTest.kt +++ b/app/src/test/java/com/stevesoltys/seedvault/transport/CoordinatorIntegrationTest.kt @@ -16,19 +16,18 @@ import com.stevesoltys.seedvault.metadata.BackupType import com.stevesoltys.seedvault.metadata.MetadataReaderImpl import com.stevesoltys.seedvault.metadata.PackageMetadata import com.stevesoltys.seedvault.metadata.PackageState.UNKNOWN_ERROR +import com.stevesoltys.seedvault.plugins.LegacyStoragePlugin +import com.stevesoltys.seedvault.plugins.StoragePlugin import com.stevesoltys.seedvault.plugins.saf.FILE_BACKUP_METADATA import com.stevesoltys.seedvault.transport.backup.ApkBackup import com.stevesoltys.seedvault.transport.backup.BackupCoordinator -import com.stevesoltys.seedvault.transport.backup.BackupPlugin import com.stevesoltys.seedvault.transport.backup.FullBackup import com.stevesoltys.seedvault.transport.backup.InputFactory import com.stevesoltys.seedvault.transport.backup.KVBackup import com.stevesoltys.seedvault.transport.backup.PackageService import com.stevesoltys.seedvault.transport.backup.TestKvDbManager import com.stevesoltys.seedvault.transport.restore.FullRestore -import com.stevesoltys.seedvault.transport.restore.FullRestorePlugin import com.stevesoltys.seedvault.transport.restore.KVRestore -import com.stevesoltys.seedvault.transport.restore.KVRestorePlugin import com.stevesoltys.seedvault.transport.restore.OutputFactory import com.stevesoltys.seedvault.transport.restore.RestoreCoordinator import com.stevesoltys.seedvault.ui.notification.BackupNotificationManager @@ -61,7 +60,9 @@ internal class CoordinatorIntegrationTest : TransportTest() { private val notificationManager = mockk() private val dbManager = TestKvDbManager() - private val backupPlugin = mockk() + @Suppress("Deprecation") + private val legacyPlugin = mockk() + private val backupPlugin = mockk() private val kvBackup = KVBackup(backupPlugin, settingsManager, inputFactory, cryptoImpl, dbManager) private val fullBackup = FullBackup(backupPlugin, settingsManager, inputFactory, cryptoImpl) @@ -80,18 +81,16 @@ internal class CoordinatorIntegrationTest : TransportTest() { notificationManager ) - private val kvRestorePlugin = mockk() private val kvRestore = KVRestore( backupPlugin, - kvRestorePlugin, + legacyPlugin, outputFactory, headerReader, cryptoImpl, dbManager ) - private val fullRestorePlugin = mockk() private val fullRestore = - FullRestore(backupPlugin, fullRestorePlugin, outputFactory, headerReader, cryptoImpl) + FullRestore(backupPlugin, legacyPlugin, outputFactory, headerReader, cryptoImpl) private val restore = RestoreCoordinator( context, crypto, diff --git a/app/src/test/java/com/stevesoltys/seedvault/transport/backup/BackupCoordinatorTest.kt b/app/src/test/java/com/stevesoltys/seedvault/transport/backup/BackupCoordinatorTest.kt index a169fe16..915f4de1 100644 --- a/app/src/test/java/com/stevesoltys/seedvault/transport/backup/BackupCoordinatorTest.kt +++ b/app/src/test/java/com/stevesoltys/seedvault/transport/backup/BackupCoordinatorTest.kt @@ -22,6 +22,7 @@ import com.stevesoltys.seedvault.metadata.PackageState.NO_DATA import com.stevesoltys.seedvault.metadata.PackageState.QUOTA_EXCEEDED import com.stevesoltys.seedvault.metadata.PackageState.UNKNOWN_ERROR import com.stevesoltys.seedvault.metadata.PackageState.WAS_STOPPED +import com.stevesoltys.seedvault.plugins.StoragePlugin import com.stevesoltys.seedvault.plugins.saf.FILE_BACKUP_METADATA import com.stevesoltys.seedvault.settings.Storage import com.stevesoltys.seedvault.ui.notification.BackupNotificationManager @@ -44,7 +45,7 @@ import kotlin.random.Random @Suppress("BlockingMethodInNonBlockingContext") internal class BackupCoordinatorTest : BackupTest() { - private val plugin = mockk() + private val plugin = mockk() private val kv = mockk() private val full = mockk() private val apkBackup = mockk() diff --git a/app/src/test/java/com/stevesoltys/seedvault/transport/backup/FullBackupTest.kt b/app/src/test/java/com/stevesoltys/seedvault/transport/backup/FullBackupTest.kt index cf311451..ed9dd25c 100644 --- a/app/src/test/java/com/stevesoltys/seedvault/transport/backup/FullBackupTest.kt +++ b/app/src/test/java/com/stevesoltys/seedvault/transport/backup/FullBackupTest.kt @@ -6,6 +6,7 @@ import android.app.backup.BackupTransport.TRANSPORT_PACKAGE_REJECTED import android.app.backup.BackupTransport.TRANSPORT_QUOTA_EXCEEDED import com.stevesoltys.seedvault.header.VERSION import com.stevesoltys.seedvault.header.getADForFull +import com.stevesoltys.seedvault.plugins.StoragePlugin import io.mockk.Runs import io.mockk.coEvery import io.mockk.every @@ -23,7 +24,7 @@ import kotlin.random.Random @Suppress("BlockingMethodInNonBlockingContext") internal class FullBackupTest : BackupTest() { - private val plugin = mockk() + private val plugin = mockk() private val backup = FullBackup(plugin, settingsManager, inputFactory, crypto) private val bytes = ByteArray(23).apply { Random.nextBytes(this) } diff --git a/app/src/test/java/com/stevesoltys/seedvault/transport/backup/KVBackupTest.kt b/app/src/test/java/com/stevesoltys/seedvault/transport/backup/KVBackupTest.kt index a4476b64..83ce4ec7 100644 --- a/app/src/test/java/com/stevesoltys/seedvault/transport/backup/KVBackupTest.kt +++ b/app/src/test/java/com/stevesoltys/seedvault/transport/backup/KVBackupTest.kt @@ -12,6 +12,7 @@ import com.stevesoltys.seedvault.getRandomString import com.stevesoltys.seedvault.header.MAX_KEY_LENGTH_SIZE import com.stevesoltys.seedvault.header.VERSION import com.stevesoltys.seedvault.header.getADForKV +import com.stevesoltys.seedvault.plugins.StoragePlugin import io.mockk.CapturingSlot import io.mockk.Runs import io.mockk.coEvery @@ -31,7 +32,7 @@ import kotlin.random.Random @Suppress("BlockingMethodInNonBlockingContext") internal class KVBackupTest : BackupTest() { - private val plugin = mockk() + private val plugin = mockk() private val dataInput = mockk() private val dbManager = mockk() diff --git a/app/src/test/java/com/stevesoltys/seedvault/transport/restore/FullRestoreTest.kt b/app/src/test/java/com/stevesoltys/seedvault/transport/restore/FullRestoreTest.kt index e6898050..73044e0d 100644 --- a/app/src/test/java/com/stevesoltys/seedvault/transport/restore/FullRestoreTest.kt +++ b/app/src/test/java/com/stevesoltys/seedvault/transport/restore/FullRestoreTest.kt @@ -11,7 +11,8 @@ import com.stevesoltys.seedvault.header.UnsupportedVersionException import com.stevesoltys.seedvault.header.VERSION import com.stevesoltys.seedvault.header.VersionHeader import com.stevesoltys.seedvault.header.getADForFull -import com.stevesoltys.seedvault.transport.backup.BackupPlugin +import com.stevesoltys.seedvault.plugins.LegacyStoragePlugin +import com.stevesoltys.seedvault.plugins.StoragePlugin import io.mockk.CapturingSlot import io.mockk.Runs import io.mockk.coEvery @@ -33,8 +34,8 @@ import kotlin.random.Random @Suppress("BlockingMethodInNonBlockingContext") internal class FullRestoreTest : RestoreTest() { - private val plugin = mockk() - private val legacyPlugin = mockk() + private val plugin = mockk() + private val legacyPlugin = mockk() private val restore = FullRestore(plugin, legacyPlugin, outputFactory, headerReader, crypto) private val encrypted = getRandomByteArray() @@ -50,7 +51,7 @@ internal class FullRestoreTest : RestoreTest() { @Suppress("deprecation") fun `v0 hasDataForPackage() delegates to plugin`() = runBlocking { val result = Random.nextBoolean() - coEvery { legacyPlugin.hasDataForPackage(token, packageInfo) } returns result + coEvery { legacyPlugin.hasDataForFullPackage(token, packageInfo) } returns result assertEquals(result, restore.hasDataForPackage(token, packageInfo)) } diff --git a/app/src/test/java/com/stevesoltys/seedvault/transport/restore/KVRestoreTest.kt b/app/src/test/java/com/stevesoltys/seedvault/transport/restore/KVRestoreTest.kt index a2ae238f..7ab12f90 100644 --- a/app/src/test/java/com/stevesoltys/seedvault/transport/restore/KVRestoreTest.kt +++ b/app/src/test/java/com/stevesoltys/seedvault/transport/restore/KVRestoreTest.kt @@ -10,9 +10,10 @@ import com.stevesoltys.seedvault.header.UnsupportedVersionException import com.stevesoltys.seedvault.header.VERSION import com.stevesoltys.seedvault.header.VersionHeader import com.stevesoltys.seedvault.header.getADForKV -import com.stevesoltys.seedvault.transport.backup.BackupPlugin +import com.stevesoltys.seedvault.plugins.LegacyStoragePlugin import com.stevesoltys.seedvault.transport.backup.KVDb import com.stevesoltys.seedvault.transport.backup.KvDbManager +import com.stevesoltys.seedvault.plugins.StoragePlugin import io.mockk.Runs import io.mockk.coEvery import io.mockk.every @@ -35,8 +36,8 @@ import kotlin.random.Random @Suppress("BlockingMethodInNonBlockingContext") internal class KVRestoreTest : RestoreTest() { - private val plugin = mockk() - private val legacyPlugin = mockk() + private val plugin = mockk() + private val legacyPlugin = mockk() private val dbManager = mockk() private val output = mockk() private val restore = diff --git a/app/src/test/java/com/stevesoltys/seedvault/transport/restore/RestoreCoordinatorTest.kt b/app/src/test/java/com/stevesoltys/seedvault/transport/restore/RestoreCoordinatorTest.kt index 357098f6..9f4dffa2 100644 --- a/app/src/test/java/com/stevesoltys/seedvault/transport/restore/RestoreCoordinatorTest.kt +++ b/app/src/test/java/com/stevesoltys/seedvault/transport/restore/RestoreCoordinatorTest.kt @@ -16,8 +16,8 @@ import com.stevesoltys.seedvault.metadata.MetadataReader import com.stevesoltys.seedvault.metadata.PackageMetadata import com.stevesoltys.seedvault.settings.Storage import com.stevesoltys.seedvault.transport.TransportTest -import com.stevesoltys.seedvault.transport.backup.BackupPlugin -import com.stevesoltys.seedvault.transport.backup.EncryptedMetadata +import com.stevesoltys.seedvault.plugins.StoragePlugin +import com.stevesoltys.seedvault.plugins.EncryptedMetadata import com.stevesoltys.seedvault.ui.notification.BackupNotificationManager import io.mockk.Runs import io.mockk.coEvery @@ -39,7 +39,7 @@ import kotlin.random.Random internal class RestoreCoordinatorTest : TransportTest() { private val notificationManager: BackupNotificationManager = mockk() - private val plugin = mockk() + private val plugin = mockk() private val kv = mockk() private val full = mockk() private val metadataReader = mockk() diff --git a/app/src/test/java/com/stevesoltys/seedvault/transport/restore/RestoreV0IntegrationTest.kt b/app/src/test/java/com/stevesoltys/seedvault/transport/restore/RestoreV0IntegrationTest.kt index 07d4b5a6..85e8d610 100644 --- a/app/src/test/java/com/stevesoltys/seedvault/transport/restore/RestoreV0IntegrationTest.kt +++ b/app/src/test/java/com/stevesoltys/seedvault/transport/restore/RestoreV0IntegrationTest.kt @@ -13,10 +13,11 @@ import com.stevesoltys.seedvault.crypto.KeyManagerTestImpl import com.stevesoltys.seedvault.encodeBase64 import com.stevesoltys.seedvault.header.HeaderReaderImpl import com.stevesoltys.seedvault.metadata.MetadataReaderImpl +import com.stevesoltys.seedvault.plugins.LegacyStoragePlugin import com.stevesoltys.seedvault.toByteArrayFromHex import com.stevesoltys.seedvault.transport.TransportTest -import com.stevesoltys.seedvault.transport.backup.BackupPlugin import com.stevesoltys.seedvault.transport.backup.KvDbManager +import com.stevesoltys.seedvault.plugins.StoragePlugin import com.stevesoltys.seedvault.ui.notification.BackupNotificationManager import io.mockk.coEvery import io.mockk.every @@ -49,19 +50,19 @@ internal class RestoreV0IntegrationTest : TransportTest() { private val metadataReader = MetadataReaderImpl(cryptoImpl) private val notificationManager = mockk() - private val backupPlugin = mockk() - private val kvRestorePlugin = mockk() + @Suppress("Deprecation") + private val legacyPlugin = mockk() + private val backupPlugin = mockk() private val kvRestore = KVRestore( backupPlugin, - kvRestorePlugin, + legacyPlugin, outputFactory, headerReader, cryptoImpl, dbManager ) - private val fullRestorePlugin = mockk() private val fullRestore = - FullRestore(backupPlugin, fullRestorePlugin, outputFactory, headerReader, cryptoImpl) + FullRestore(backupPlugin, legacyPlugin, outputFactory, headerReader, cryptoImpl) private val restore = RestoreCoordinator( context, crypto, @@ -161,7 +162,7 @@ internal class RestoreV0IntegrationTest : TransportTest() { assertEquals(TRANSPORT_OK, restore.startRestore(token, arrayOf(packageInfo))) // find data for K/V backup - coEvery { kvRestorePlugin.hasDataForPackage(token, packageInfo) } returns true + coEvery { legacyPlugin.hasDataForPackage(token, packageInfo) } returns true val restoreDescription = restore.nextRestorePackage() ?: fail() assertEquals(packageInfo.packageName, restoreDescription.packageName) @@ -171,10 +172,10 @@ internal class RestoreV0IntegrationTest : TransportTest() { val backupDataOutput = mockk() val rInputStream = ByteArrayInputStream(encryptedAppData) val rInputStream2 = ByteArrayInputStream(encryptedAppData2) - coEvery { kvRestorePlugin.listRecords(token, packageInfo) } returns listOf(key64, key264) + coEvery { legacyPlugin.listRecords(token, packageInfo) } returns listOf(key64, key264) every { outputFactory.getBackupDataOutput(fileDescriptor) } returns backupDataOutput coEvery { - kvRestorePlugin.getInputStreamForRecord( + legacyPlugin.getInputStreamForRecord( token, packageInfo, key64 @@ -183,7 +184,7 @@ internal class RestoreV0IntegrationTest : TransportTest() { every { backupDataOutput.writeEntityHeader(key, appData.size) } returns 1137 every { backupDataOutput.writeEntityData(appData, appData.size) } returns appData.size coEvery { - kvRestorePlugin.getInputStreamForRecord( + legacyPlugin.getInputStreamForRecord( token, packageInfo, key264 @@ -212,8 +213,8 @@ internal class RestoreV0IntegrationTest : TransportTest() { assertEquals(TRANSPORT_OK, restore.startRestore(token, arrayOf(packageInfo))) // find data only for full backup - coEvery { kvRestorePlugin.hasDataForPackage(token, packageInfo) } returns false - coEvery { fullRestorePlugin.hasDataForPackage(token, packageInfo) } returns true + coEvery { legacyPlugin.hasDataForPackage(token, packageInfo) } returns false + coEvery { legacyPlugin.hasDataForFullPackage(token, packageInfo) } returns true val restoreDescription = restore.nextRestorePackage() ?: fail() assertEquals(packageInfo.packageName, restoreDescription.packageName) @@ -223,7 +224,7 @@ internal class RestoreV0IntegrationTest : TransportTest() { val inputStream = ByteArrayInputStream(encryptedData) val outputStream = ByteArrayOutputStream() coEvery { - fullRestorePlugin.getInputStreamForPackage( + legacyPlugin.getInputStreamForPackage( token, packageInfo )