Clean up code after refactorings

This commit is contained in:
Torsten Grote 2024-09-23 12:04:50 -03:00
parent 5c75574f65
commit 7b0e02c451
No known key found for this signature in database
GPG key ID: 3E5F77D92CF891FF
59 changed files with 84 additions and 240 deletions

View file

@ -10,7 +10,6 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.MediumTest import androidx.test.filters.MediumTest
import androidx.test.platform.app.InstrumentationRegistry import androidx.test.platform.app.InstrumentationRegistry
import com.stevesoltys.seedvault.backend.LegacyStoragePlugin import com.stevesoltys.seedvault.backend.LegacyStoragePlugin
import com.stevesoltys.seedvault.backend.getAvailableBackupFileHandles
import com.stevesoltys.seedvault.backend.saf.DocumentsProviderLegacyPlugin import com.stevesoltys.seedvault.backend.saf.DocumentsProviderLegacyPlugin
import com.stevesoltys.seedvault.backend.saf.DocumentsStorage import com.stevesoltys.seedvault.backend.saf.DocumentsStorage
import com.stevesoltys.seedvault.settings.SettingsManager import com.stevesoltys.seedvault.settings.SettingsManager

View file

@ -13,7 +13,6 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.MediumTest import androidx.test.filters.MediumTest
import com.stevesoltys.seedvault.repo.BackupData import com.stevesoltys.seedvault.repo.BackupData
import com.stevesoltys.seedvault.repo.BackupReceiver import com.stevesoltys.seedvault.repo.BackupReceiver
import com.stevesoltys.seedvault.settings.SettingsManager
import io.mockk.CapturingSlot import io.mockk.CapturingSlot
import io.mockk.Runs import io.mockk.Runs
import io.mockk.coEvery import io.mockk.coEvery
@ -34,7 +33,6 @@ import kotlin.test.assertEquals
@MediumTest @MediumTest
class KvBackupInstrumentationTest : KoinComponent { class KvBackupInstrumentationTest : KoinComponent {
private val settingsManager: SettingsManager by inject()
private val backupReceiver: BackupReceiver = mockk() private val backupReceiver: BackupReceiver = mockk()
private val inputFactory: InputFactory = mockk() private val inputFactory: InputFactory = mockk()
private val dbManager: KvDbManager by inject() private val dbManager: KvDbManager by inject()

View file

@ -13,9 +13,9 @@ import com.stevesoltys.seedvault.proto.SnapshotKt.blob
import com.stevesoltys.seedvault.repo.AppBackupManager import com.stevesoltys.seedvault.repo.AppBackupManager
import com.stevesoltys.seedvault.repo.BackupData import com.stevesoltys.seedvault.repo.BackupData
import com.stevesoltys.seedvault.repo.BackupReceiver import com.stevesoltys.seedvault.repo.BackupReceiver
import com.stevesoltys.seedvault.transport.backup.PackageService
import com.stevesoltys.seedvault.repo.SnapshotCreatorFactory
import com.stevesoltys.seedvault.repo.Loader import com.stevesoltys.seedvault.repo.Loader
import com.stevesoltys.seedvault.repo.SnapshotCreatorFactory
import com.stevesoltys.seedvault.transport.backup.PackageService
import io.mockk.Runs import io.mockk.Runs
import io.mockk.coEvery import io.mockk.coEvery
import io.mockk.every import io.mockk.every

View file

@ -86,11 +86,9 @@ open class App : Application() {
settingsManager = get(), settingsManager = get(),
keyManager = get(), keyManager = get(),
backendManager = get(), backendManager = get(),
metadataManager = get(),
appListRetriever = get(), appListRetriever = get(),
storageBackup = get(), storageBackup = get(),
backupManager = get(), backupManager = get(),
backupInitializer = get(),
backupStateManager = get(), backupStateManager = get(),
) )
} }

View file

@ -10,9 +10,9 @@ import android.util.Log
import androidx.annotation.WorkerThread import androidx.annotation.WorkerThread
import com.stevesoltys.seedvault.getStorageContext import com.stevesoltys.seedvault.getStorageContext
import com.stevesoltys.seedvault.permitDiskReads import com.stevesoltys.seedvault.permitDiskReads
import com.stevesoltys.seedvault.repo.BlobCache
import com.stevesoltys.seedvault.settings.SettingsManager import com.stevesoltys.seedvault.settings.SettingsManager
import com.stevesoltys.seedvault.settings.StoragePluginType import com.stevesoltys.seedvault.settings.StoragePluginType
import com.stevesoltys.seedvault.repo.BlobCache
import org.calyxos.seedvault.core.backends.Backend import org.calyxos.seedvault.core.backends.Backend
import org.calyxos.seedvault.core.backends.BackendFactory import org.calyxos.seedvault.core.backends.BackendFactory
import org.calyxos.seedvault.core.backends.BackendProperties import org.calyxos.seedvault.core.backends.BackendProperties
@ -89,6 +89,7 @@ class BackendManager(
mBackend = backend mBackend = backend
mBackendProperties = storageProperties mBackendProperties = storageProperties
blobCache.clearLocalCache() blobCache.clearLocalCache()
// TODO not critical, but nice to have: clear also local snapshot cache
} }
/** /**

View file

@ -29,7 +29,6 @@ import org.calyxos.seedvault.core.backends.saf.SafProperties
import org.calyxos.seedvault.core.backends.saf.getTreeDocumentFile import org.calyxos.seedvault.core.backends.saf.getTreeDocumentFile
import java.io.IOException import java.io.IOException
import java.io.InputStream import java.io.InputStream
import java.io.OutputStream
import kotlin.coroutines.resume import kotlin.coroutines.resume
@Deprecated("") @Deprecated("")
@ -51,7 +50,7 @@ internal class DocumentsStorage(
private val context: Context get() = appContext.getStorageContext { safStorage.isUsb } private val context: Context get() = appContext.getStorageContext { safStorage.isUsb }
private val contentResolver: ContentResolver get() = context.contentResolver private val contentResolver: ContentResolver get() = context.contentResolver
internal var rootBackupDir: DocumentFile? = null private var rootBackupDir: DocumentFile? = null
get() = runBlocking { get() = runBlocking {
if (field == null) { if (field == null) {
val parent = safStorage.getDocumentFile(context) val parent = safStorage.getDocumentFile(context)
@ -94,16 +93,6 @@ internal class DocumentsStorage(
} }
} }
@Throws(IOException::class)
fun getOutputStream(file: DocumentFile): OutputStream {
return try {
contentResolver.openOutputStream(file.uri, "wt") ?: throw IOException()
} catch (e: Exception) {
// SAF can throw all sorts of exceptions, so wrap it in IOException
throw IOException(e)
}
}
} }
/** /**
@ -192,7 +181,7 @@ suspend fun DocumentFile.findFileBlocking(context: Context, displayName: String)
@Throws(IOException::class, TimeoutCancellationException::class) @Throws(IOException::class, TimeoutCancellationException::class)
internal suspend fun getLoadedCursor(timeout: Long = 15_000, query: () -> Cursor?) = internal suspend fun getLoadedCursor(timeout: Long = 15_000, query: () -> Cursor?) =
withTimeout(timeout) { withTimeout(timeout) {
suspendCancellableCoroutine<Cursor> { cont -> suspendCancellableCoroutine { cont ->
val cursor = query() ?: throw IOException() val cursor = query() ?: throw IOException()
cont.invokeOnCancellation { cursor.close() } cont.invokeOnCancellation { cursor.close() }
val loading = cursor.extras.getBoolean(EXTRA_LOADING, false) val loading = cursor.extras.getBoolean(EXTRA_LOADING, false)

View file

@ -139,17 +139,6 @@ internal object StorageRootResolver {
return if (index != -1) getInt(index) else 0 return if (index != -1) getInt(index) else 0
} }
private fun Cursor.getLong(columnName: String): Long? {
val index = getColumnIndex(columnName)
if (index == -1) return null
val value = getString(index) ?: return null
return try {
java.lang.Long.parseLong(value)
} catch (e: NumberFormatException) {
null
}
}
fun getIcon(context: Context, authority: String, rootId: String, icon: Int): Drawable? { fun getIcon(context: Context, authority: String, rootId: String, icon: Int): Drawable? {
return getPackageIcon(context, authority, icon) ?: when { return getPackageIcon(context, authority, icon) ?: when {
authority == AUTHORITY_STORAGE && rootId == ROOT_ID_DEVICE -> { authority == AUTHORITY_STORAGE && rootId == ROOT_ID_DEVICE -> {

View file

@ -102,17 +102,6 @@ internal interface Crypto {
@Deprecated("only for v1") @Deprecated("only for v1")
fun getNameForApk(salt: String, packageName: String, suffix: String = ""): String fun getNameForApk(salt: String, packageName: String, suffix: String = ""): String
/**
* Returns a [AesGcmHkdfStreaming] encrypting stream
* that gets encrypted and authenticated the given associated data.
*/
@Deprecated("only for v1")
@Throws(IOException::class, GeneralSecurityException::class)
fun newEncryptingStreamV1(
outputStream: OutputStream,
associatedData: ByteArray,
): OutputStream
/** /**
* Returns a [AesGcmHkdfStreaming] decrypting stream * Returns a [AesGcmHkdfStreaming] decrypting stream
* that gets decrypted and authenticated the given associated data. * that gets decrypted and authenticated the given associated data.
@ -245,13 +234,6 @@ internal class CryptoImpl(
return messageDigest.digest() return messageDigest.digest()
} }
@Deprecated("only for v1")
@Throws(IOException::class, GeneralSecurityException::class)
override fun newEncryptingStreamV1(
outputStream: OutputStream,
associatedData: ByteArray,
): OutputStream = CoreCrypto.newEncryptingStream(keyV1, outputStream, associatedData)
@Deprecated("only for v1") @Deprecated("only for v1")
@Throws(IOException::class, GeneralSecurityException::class) @Throws(IOException::class, GeneralSecurityException::class)
override fun newDecryptingStreamV1( override fun newDecryptingStreamV1(

View file

@ -33,12 +33,6 @@ internal class MetadataWriterImpl : MetadataWriter {
if (packageMetadata.size != null) { if (packageMetadata.size != null) {
put(JSON_PACKAGE_SIZE, packageMetadata.size) put(JSON_PACKAGE_SIZE, packageMetadata.size)
} }
if (packageMetadata.system) {
put(JSON_PACKAGE_SYSTEM, true)
}
if (packageMetadata.isLaunchableSystemApp) {
put(JSON_PACKAGE_SYSTEM_LAUNCHER, true)
}
}) })
} }
return json.toString().toByteArray(Utf8) return json.toString().toByteArray(Utf8)

View file

@ -144,6 +144,7 @@ internal class AppBackupManager(
@Throws(IOException::class) @Throws(IOException::class)
suspend fun removeBackupRepo() { suspend fun removeBackupRepo() {
blobCache.clearLocalCache() blobCache.clearLocalCache()
// TODO not critical, but nice to have: clear also local snapshot cache
backendManager.backend.remove(TopLevelFolder(crypto.repoId)) backendManager.backend.remove(TopLevelFolder(crypto.repoId))
} }

View file

@ -19,6 +19,6 @@ val repoModule = module {
val snapshotFolder = File(androidContext().filesDir, FOLDER_SNAPSHOTS) val snapshotFolder = File(androidContext().filesDir, FOLDER_SNAPSHOTS)
SnapshotManager(snapshotFolder, get(), get(), get()) SnapshotManager(snapshotFolder, get(), get(), get())
} }
factory { SnapshotCreatorFactory(androidContext(), get(), get(), get(), get()) } factory { SnapshotCreatorFactory(androidContext(), get(), get(), get()) }
factory { Pruner(get(), get(), get()) } factory { Pruner(get(), get(), get()) }
} }

View file

@ -23,7 +23,6 @@ import com.stevesoltys.seedvault.proto.Snapshot
import com.stevesoltys.seedvault.proto.Snapshot.Apk import com.stevesoltys.seedvault.proto.Snapshot.Apk
import com.stevesoltys.seedvault.proto.Snapshot.App import com.stevesoltys.seedvault.proto.Snapshot.App
import com.stevesoltys.seedvault.proto.Snapshot.Blob import com.stevesoltys.seedvault.proto.Snapshot.Blob
import com.stevesoltys.seedvault.settings.SettingsManager
import com.stevesoltys.seedvault.transport.backup.PackageService import com.stevesoltys.seedvault.transport.backup.PackageService
import com.stevesoltys.seedvault.transport.backup.isSystemApp import com.stevesoltys.seedvault.transport.backup.isSystemApp
import io.github.oshai.kotlinlogging.KotlinLogging import io.github.oshai.kotlinlogging.KotlinLogging
@ -38,7 +37,6 @@ internal class SnapshotCreator(
private val context: Context, private val context: Context,
private val clock: Clock, private val clock: Clock,
private val packageService: PackageService, private val packageService: PackageService,
private val settingsManager: SettingsManager,
private val metadataManager: MetadataManager, private val metadataManager: MetadataManager,
) { ) {

View file

@ -8,7 +8,6 @@ package com.stevesoltys.seedvault.repo
import android.content.Context import android.content.Context
import com.stevesoltys.seedvault.Clock import com.stevesoltys.seedvault.Clock
import com.stevesoltys.seedvault.metadata.MetadataManager import com.stevesoltys.seedvault.metadata.MetadataManager
import com.stevesoltys.seedvault.settings.SettingsManager
import com.stevesoltys.seedvault.transport.backup.PackageService import com.stevesoltys.seedvault.transport.backup.PackageService
/** /**
@ -18,9 +17,8 @@ internal class SnapshotCreatorFactory(
private val context: Context, private val context: Context,
private val clock: Clock, private val clock: Clock,
private val packageService: PackageService, private val packageService: PackageService,
private val settingsManager: SettingsManager,
private val metadataManager: MetadataManager, private val metadataManager: MetadataManager,
) { ) {
fun createSnapshotCreator() = fun createSnapshotCreator() =
SnapshotCreator(context, clock, packageService, settingsManager, metadataManager) SnapshotCreator(context, clock, packageService, metadataManager)
} }

View file

@ -27,7 +27,6 @@ import com.stevesoltys.seedvault.backend.BackendManager
import com.stevesoltys.seedvault.metadata.PackageMetadataMap import com.stevesoltys.seedvault.metadata.PackageMetadataMap
import com.stevesoltys.seedvault.metadata.PackageState import com.stevesoltys.seedvault.metadata.PackageState
import com.stevesoltys.seedvault.restore.install.isInstalled import com.stevesoltys.seedvault.restore.install.isInstalled
import com.stevesoltys.seedvault.settings.SettingsManager
import com.stevesoltys.seedvault.transport.TRANSPORT_ID import com.stevesoltys.seedvault.transport.TRANSPORT_ID
import com.stevesoltys.seedvault.transport.restore.RestorableBackup import com.stevesoltys.seedvault.transport.restore.RestorableBackup
import com.stevesoltys.seedvault.transport.restore.RestoreCoordinator import com.stevesoltys.seedvault.transport.restore.RestoreCoordinator
@ -55,7 +54,6 @@ internal data class AppRestoreResult(
internal class AppDataRestoreManager( internal class AppDataRestoreManager(
private val context: Context, private val context: Context,
private val backupManager: IBackupManager, private val backupManager: IBackupManager,
private val settingsManager: SettingsManager,
private val restoreCoordinator: RestoreCoordinator, private val restoreCoordinator: RestoreCoordinator,
private val backendManager: BackendManager, private val backendManager: BackendManager,
) { ) {

View file

@ -96,7 +96,7 @@ internal class AppSelectionManager(
val backend = backendManager.backend val backend = backendManager.backend
val token = restorableBackup.token val token = restorableBackup.token
backend.load(LegacyAppBackupFile.IconsFile(token)).use { backend.load(LegacyAppBackupFile.IconsFile(token)).use {
iconManager.downloadIconsV1(restorableBackup.version, token, it) iconManager.downloadIconsV1(token, it)
} }
} else if (restorableBackup.version >= 2) { } else if (restorableBackup.version >= 2) {
val repoId = restorableBackup.repoId ?: error("No repoId in v2 backup") val repoId = restorableBackup.repoId ?: error("No repoId in v2 backup")

View file

@ -83,7 +83,7 @@ internal class RestoreViewModel(
private val appSelectionManager = private val appSelectionManager =
AppSelectionManager(app, backendManager, iconManager, viewModelScope) AppSelectionManager(app, backendManager, iconManager, viewModelScope)
private val appDataRestoreManager = AppDataRestoreManager( private val appDataRestoreManager = AppDataRestoreManager(
app, backupManager, settingsManager, restoreCoordinator, backendManager app, backupManager, restoreCoordinator, backendManager
) )
private val mDisplayFragment = MutableLiveEvent<DisplayFragment>() private val mDisplayFragment = MutableLiveEvent<DisplayFragment>()

View file

@ -21,15 +21,15 @@ import com.stevesoltys.seedvault.crypto.Crypto
import com.stevesoltys.seedvault.encodeBase64 import com.stevesoltys.seedvault.encodeBase64
import com.stevesoltys.seedvault.metadata.ApkSplit import com.stevesoltys.seedvault.metadata.ApkSplit
import com.stevesoltys.seedvault.metadata.PackageMetadata import com.stevesoltys.seedvault.metadata.PackageMetadata
import com.stevesoltys.seedvault.repo.Loader
import com.stevesoltys.seedvault.repo.getBlobHandles
import com.stevesoltys.seedvault.restore.RestoreService import com.stevesoltys.seedvault.restore.RestoreService
import com.stevesoltys.seedvault.restore.install.ApkInstallState.FAILED import com.stevesoltys.seedvault.restore.install.ApkInstallState.FAILED
import com.stevesoltys.seedvault.restore.install.ApkInstallState.FAILED_SYSTEM_APP 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.IN_PROGRESS
import com.stevesoltys.seedvault.restore.install.ApkInstallState.QUEUED import com.stevesoltys.seedvault.restore.install.ApkInstallState.QUEUED
import com.stevesoltys.seedvault.restore.install.ApkInstallState.SUCCEEDED import com.stevesoltys.seedvault.restore.install.ApkInstallState.SUCCEEDED
import com.stevesoltys.seedvault.repo.getBlobHandles
import com.stevesoltys.seedvault.transport.backup.isSystemApp import com.stevesoltys.seedvault.transport.backup.isSystemApp
import com.stevesoltys.seedvault.repo.Loader
import com.stevesoltys.seedvault.transport.restore.RestorableBackup import com.stevesoltys.seedvault.transport.restore.RestorableBackup
import com.stevesoltys.seedvault.worker.hashSignature import com.stevesoltys.seedvault.worker.hashSignature
import kotlinx.coroutines.TimeoutCancellationException import kotlinx.coroutines.TimeoutCancellationException

View file

@ -84,7 +84,7 @@ internal class InstallProgressAdapter(
if (item.icon == null) iconJob = scope.launch { if (item.icon == null) iconJob = scope.launch {
iconLoader(item, appIcon::setImageDrawable) iconLoader(item, appIcon::setImageDrawable)
} else appIcon.setImageDrawable(item.icon) } else appIcon.setImageDrawable(item.icon)
appName.text = item.name ?: getAppName(v.context, item.packageName.toString()) appName.text = item.name ?: getAppName(v.context, item.packageName)
appInfo.visibility = GONE appInfo.visibility = GONE
when (item.state) { when (item.state) {
IN_PROGRESS -> { IN_PROGRESS -> {

View file

@ -80,8 +80,7 @@ internal class AppListRetriever(
AppStatus( AppStatus(
packageName = packageName, packageName = packageName,
enabled = settingsManager.isBackupEnabled(packageName), enabled = settingsManager.isBackupEnabled(packageName),
icon = data.iconRes?.let { getDrawable(context, it) } icon = getDrawable(context, data.iconRes) ?: getIconFromPackageManager(packageName),
?: getIconFromPackageManager(packageName),
name = context.getString(data.nameRes), name = context.getString(data.nameRes),
time = metadata?.time ?: 0, time = metadata?.time ?: 0,
size = metadata?.size, size = metadata?.size,

View file

@ -16,8 +16,8 @@ import androidx.preference.PreferenceManager
import androidx.work.ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE import androidx.work.ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE
import androidx.work.ExistingPeriodicWorkPolicy.UPDATE import androidx.work.ExistingPeriodicWorkPolicy.UPDATE
import com.stevesoltys.seedvault.R import com.stevesoltys.seedvault.R
import com.stevesoltys.seedvault.permitDiskReads
import com.stevesoltys.seedvault.backend.BackendManager import com.stevesoltys.seedvault.backend.BackendManager
import com.stevesoltys.seedvault.permitDiskReads
import com.stevesoltys.seedvault.settings.preference.M3ListPreference import com.stevesoltys.seedvault.settings.preference.M3ListPreference
import org.koin.android.ext.android.inject import org.koin.android.ext.android.inject
import org.koin.androidx.viewmodel.ext.android.sharedViewModel import org.koin.androidx.viewmodel.ext.android.sharedViewModel

View file

@ -35,12 +35,10 @@ import androidx.work.ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE
import androidx.work.WorkManager import androidx.work.WorkManager
import com.stevesoltys.seedvault.BackupStateManager import com.stevesoltys.seedvault.BackupStateManager
import com.stevesoltys.seedvault.R import com.stevesoltys.seedvault.R
import com.stevesoltys.seedvault.crypto.KeyManager
import com.stevesoltys.seedvault.metadata.MetadataManager
import com.stevesoltys.seedvault.permitDiskReads
import com.stevesoltys.seedvault.backend.BackendManager import com.stevesoltys.seedvault.backend.BackendManager
import com.stevesoltys.seedvault.crypto.KeyManager
import com.stevesoltys.seedvault.permitDiskReads
import com.stevesoltys.seedvault.storage.StorageBackupJobService import com.stevesoltys.seedvault.storage.StorageBackupJobService
import com.stevesoltys.seedvault.transport.backup.BackupInitializer
import com.stevesoltys.seedvault.ui.LiveEvent import com.stevesoltys.seedvault.ui.LiveEvent
import com.stevesoltys.seedvault.ui.MutableLiveEvent import com.stevesoltys.seedvault.ui.MutableLiveEvent
import com.stevesoltys.seedvault.ui.RequireProvisioningViewModel import com.stevesoltys.seedvault.ui.RequireProvisioningViewModel
@ -68,11 +66,9 @@ internal class SettingsViewModel(
settingsManager: SettingsManager, settingsManager: SettingsManager,
keyManager: KeyManager, keyManager: KeyManager,
backendManager: BackendManager, backendManager: BackendManager,
private val metadataManager: MetadataManager,
private val appListRetriever: AppListRetriever, private val appListRetriever: AppListRetriever,
private val storageBackup: StorageBackup, private val storageBackup: StorageBackup,
private val backupManager: IBackupManager, private val backupManager: IBackupManager,
private val backupInitializer: BackupInitializer,
backupStateManager: BackupStateManager, backupStateManager: BackupStateManager,
) : RequireProvisioningViewModel(app, settingsManager, keyManager, backendManager) { ) : RequireProvisioningViewModel(app, settingsManager, keyManager, backendManager) {

View file

@ -5,8 +5,8 @@
package com.stevesoltys.seedvault.storage package com.stevesoltys.seedvault.storage
import com.stevesoltys.seedvault.crypto.KeyManager
import com.stevesoltys.seedvault.backend.BackendManager import com.stevesoltys.seedvault.backend.BackendManager
import com.stevesoltys.seedvault.crypto.KeyManager
import org.calyxos.backup.storage.api.StorageBackup import org.calyxos.backup.storage.api.StorageBackup
import org.koin.dsl.module import org.koin.dsl.module

View file

@ -17,7 +17,6 @@ import android.os.ParcelFileDescriptor
import android.util.Log import android.util.Log
import com.stevesoltys.seedvault.R import com.stevesoltys.seedvault.R
import com.stevesoltys.seedvault.settings.SettingsActivity import com.stevesoltys.seedvault.settings.SettingsActivity
import com.stevesoltys.seedvault.settings.SettingsManager
import com.stevesoltys.seedvault.transport.backup.BackupCoordinator import com.stevesoltys.seedvault.transport.backup.BackupCoordinator
import com.stevesoltys.seedvault.transport.restore.RestoreCoordinator import com.stevesoltys.seedvault.transport.restore.RestoreCoordinator
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
@ -43,7 +42,6 @@ class ConfigurableBackupTransport internal constructor(private val context: Cont
private val backupCoordinator by inject<BackupCoordinator>() private val backupCoordinator by inject<BackupCoordinator>()
private val restoreCoordinator by inject<RestoreCoordinator>() private val restoreCoordinator by inject<RestoreCoordinator>()
private val settingsManager by inject<SettingsManager>()
override fun transportDirName(): String { override fun transportDirName(): String {
return TRANSPORT_DIRECTORY_NAME return TRANSPORT_DIRECTORY_NAME

View file

@ -20,7 +20,6 @@ import android.content.pm.PackageInfo
import android.os.ParcelFileDescriptor import android.os.ParcelFileDescriptor
import android.util.Log import android.util.Log
import androidx.annotation.WorkerThread import androidx.annotation.WorkerThread
import com.stevesoltys.seedvault.Clock
import com.stevesoltys.seedvault.backend.BackendManager import com.stevesoltys.seedvault.backend.BackendManager
import com.stevesoltys.seedvault.metadata.BackupType import com.stevesoltys.seedvault.metadata.BackupType
import com.stevesoltys.seedvault.metadata.MetadataManager import com.stevesoltys.seedvault.metadata.MetadataManager
@ -64,14 +63,12 @@ internal class BackupCoordinator(
private val appBackupManager: AppBackupManager, private val appBackupManager: AppBackupManager,
private val kv: KVBackup, private val kv: KVBackup,
private val full: FullBackup, private val full: FullBackup,
private val clock: Clock,
private val packageService: PackageService, private val packageService: PackageService,
private val metadataManager: MetadataManager, private val metadataManager: MetadataManager,
private val settingsManager: SettingsManager, private val settingsManager: SettingsManager,
private val nm: BackupNotificationManager, private val nm: BackupNotificationManager,
) { ) {
private val backend get() = backendManager.backend
private val snapshotCreator private val snapshotCreator
get() = appBackupManager.snapshotCreator ?: error("No SnapshotCreator") get() = appBackupManager.snapshotCreator ?: error("No SnapshotCreator")
private val state = CoordinatorState( private val state = CoordinatorState(
@ -92,6 +89,8 @@ internal class BackupCoordinator(
* *
* If the transport returns anything other than [TRANSPORT_OK] from this method, * If the transport returns anything other than [TRANSPORT_OK] from this method,
* the OS will halt the current initialize operation and schedule a retry in the near future. * the OS will halt the current initialize operation and schedule a retry in the near future.
* Attention: [finishBackup] will not be called in this case.
*
* Even if the transport is in a state * Even if the transport is in a state
* such that attempting to "initialize" the backend storage is meaningless - * such that attempting to "initialize" the backend storage is meaningless -
* for example, if there is no current live data-set at all, * for example, if there is no current live data-set at all,
@ -103,12 +102,8 @@ internal class BackupCoordinator(
* [TRANSPORT_ERROR] (to retry following network error or other failure). * [TRANSPORT_ERROR] (to retry following network error or other failure).
*/ */
fun initializeDevice(): Int { fun initializeDevice(): Int {
// we don't respect the intended system behavior here by always starting a new [RestoreSet]
// instead of simply deleting the current one
Log.i(TAG, "Initialize Device!") Log.i(TAG, "Initialize Device!")
// we don't respect the intended system behavior of erasing all stored data
// [finishBackup] will only be called when we return [TRANSPORT_OK] here
// so we remember that we initialized successfully
state.calledInitialize = true state.calledInitialize = true
return TRANSPORT_OK return TRANSPORT_OK
} }

View file

@ -41,7 +41,6 @@ val backupModule = module {
appBackupManager = get(), appBackupManager = get(),
kv = get(), kv = get(),
full = get(), full = get(),
clock = get(),
packageService = get(), packageService = get(),
metadataManager = get(), metadataManager = get(),
settingsManager = get(), settingsManager = get(),

View file

@ -138,14 +138,15 @@ internal class FullBackup(
suspend fun cancelFullBackup() { suspend fun cancelFullBackup() {
val state = this.state ?: error("No state when canceling") val state = this.state ?: error("No state when canceling")
Log.i(TAG, "Cancel full backup for ${state.packageName}") Log.i(TAG, "Cancel full backup for ${state.packageName}")
// TODO check if worth keeping the blobs. they've been uploaded already and may be re-usable // finalize the receiver
// so we could add them to the snapshot's blobMap or just let prune remove them at the end
try { try {
backupReceiver.finalize(getOwner(state.packageName)) backupReceiver.finalize(getOwner(state.packageName))
} catch (e: Exception) { } catch (e: Exception) {
// as the backup was cancelled anyway, we don't care if finalizing had an error // as the backup was cancelled anyway, we don't care if finalizing had an error
Log.e(TAG, "Error finalizing backup in cancelFullBackup().", e) Log.e(TAG, "Error finalizing backup in cancelFullBackup().", e)
} }
// If the transport receives this callback, it will *not* receive a call to [finishBackup].
// It needs to tear down any ongoing backup state here.
clearState() clearState()
} }

View file

@ -125,11 +125,6 @@ internal class PackageService(
packageInfo.allowsBackup() packageInfo.allowsBackup()
} }
/**
* A list of apps that do not allow backup.
*/
val userNotAllowedApps: List<PackageInfo> = emptyList()
val launchableSystemApps: List<ResolveInfo> val launchableSystemApps: List<ResolveInfo>
@WorkerThread @WorkerThread
get() { get() {

View file

@ -18,11 +18,10 @@ import android.util.Log.isLoggable
import com.stevesoltys.seedvault.ERROR_BACKUP_CANCELLED import com.stevesoltys.seedvault.ERROR_BACKUP_CANCELLED
import com.stevesoltys.seedvault.MAGIC_PACKAGE_MANAGER import com.stevesoltys.seedvault.MAGIC_PACKAGE_MANAGER
import com.stevesoltys.seedvault.R import com.stevesoltys.seedvault.R
import com.stevesoltys.seedvault.metadata.MetadataManager
import com.stevesoltys.seedvault.settings.SettingsManager
import com.stevesoltys.seedvault.repo.AppBackupManager import com.stevesoltys.seedvault.repo.AppBackupManager
import com.stevesoltys.seedvault.transport.backup.PackageService
import com.stevesoltys.seedvault.repo.hexFromProto import com.stevesoltys.seedvault.repo.hexFromProto
import com.stevesoltys.seedvault.settings.SettingsManager
import com.stevesoltys.seedvault.transport.backup.PackageService
import com.stevesoltys.seedvault.worker.AppBackupPruneWorker import com.stevesoltys.seedvault.worker.AppBackupPruneWorker
import com.stevesoltys.seedvault.worker.BackupRequester import com.stevesoltys.seedvault.worker.BackupRequester
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
@ -38,7 +37,6 @@ internal class NotificationBackupObserver(
) : IBackupObserver.Stub(), KoinComponent { ) : IBackupObserver.Stub(), KoinComponent {
private val nm: BackupNotificationManager by inject() private val nm: BackupNotificationManager by inject()
private val metadataManager: MetadataManager by inject()
private val packageService: PackageService by inject() private val packageService: PackageService by inject()
private val settingsManager: SettingsManager by inject() private val settingsManager: SettingsManager by inject()
private val appBackupManager: AppBackupManager by inject() private val appBackupManager: AppBackupManager by inject()
@ -153,7 +151,7 @@ internal class NotificationBackupObserver(
success = snapshot != null success = snapshot != null
snapshot snapshot
} }
val size = if (snapshot != null) { // TODO count size of APKs separately val size = if (snapshot != null) { // TODO for later: count size of APKs separately
val chunkIds = snapshot.appsMap.values.flatMap { it.chunkIdsList } val chunkIds = snapshot.appsMap.values.flatMap { it.chunkIdsList }
chunkIds.sumOf { chunkIds.sumOf {
snapshot.blobsMap[it.hexFromProto()]?.uncompressedLength?.toLong() ?: 0L snapshot.blobsMap[it.hexFromProto()]?.uncompressedLength?.toLong() ?: 0L

View file

@ -16,7 +16,6 @@ import com.stevesoltys.seedvault.R
import com.stevesoltys.seedvault.backend.BackendManager import com.stevesoltys.seedvault.backend.BackendManager
import com.stevesoltys.seedvault.backend.saf.SafHandler import com.stevesoltys.seedvault.backend.saf.SafHandler
import com.stevesoltys.seedvault.backend.webdav.WebDavHandler import com.stevesoltys.seedvault.backend.webdav.WebDavHandler
import org.calyxos.seedvault.core.backends.webdav.WebDavProperties
import com.stevesoltys.seedvault.settings.SettingsManager import com.stevesoltys.seedvault.settings.SettingsManager
import com.stevesoltys.seedvault.storage.StorageBackupJobService import com.stevesoltys.seedvault.storage.StorageBackupJobService
import com.stevesoltys.seedvault.transport.backup.BackupInitializer import com.stevesoltys.seedvault.transport.backup.BackupInitializer
@ -28,6 +27,7 @@ import org.calyxos.backup.storage.api.StorageBackup
import org.calyxos.backup.storage.backup.BackupJobService import org.calyxos.backup.storage.backup.BackupJobService
import org.calyxos.seedvault.core.backends.Backend import org.calyxos.seedvault.core.backends.Backend
import org.calyxos.seedvault.core.backends.saf.SafProperties import org.calyxos.seedvault.core.backends.saf.SafProperties
import org.calyxos.seedvault.core.backends.webdav.WebDavProperties
import java.io.IOException import java.io.IOException
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit

View file

@ -24,8 +24,6 @@ import com.stevesoltys.seedvault.ui.INTENT_EXTRA_IS_RESTORE
import com.stevesoltys.seedvault.ui.INTENT_EXTRA_IS_SETUP_WIZARD import com.stevesoltys.seedvault.ui.INTENT_EXTRA_IS_SETUP_WIZARD
import org.koin.androidx.viewmodel.ext.android.getViewModel import org.koin.androidx.viewmodel.ext.android.getViewModel
private val TAG = StorageActivity::class.java.name
class StorageActivity : BackupActivity() { class StorageActivity : BackupActivity() {
private lateinit var viewModel: StorageViewModel private lateinit var viewModel: StorageViewModel

View file

@ -16,7 +16,6 @@ import com.stevesoltys.seedvault.R
import com.stevesoltys.seedvault.backend.BackendManager import com.stevesoltys.seedvault.backend.BackendManager
import com.stevesoltys.seedvault.backend.saf.SafHandler import com.stevesoltys.seedvault.backend.saf.SafHandler
import com.stevesoltys.seedvault.backend.webdav.WebDavHandler import com.stevesoltys.seedvault.backend.webdav.WebDavHandler
import org.calyxos.seedvault.core.backends.webdav.WebDavProperties
import com.stevesoltys.seedvault.settings.SettingsManager import com.stevesoltys.seedvault.settings.SettingsManager
import com.stevesoltys.seedvault.ui.LiveEvent import com.stevesoltys.seedvault.ui.LiveEvent
import com.stevesoltys.seedvault.ui.MutableLiveEvent import com.stevesoltys.seedvault.ui.MutableLiveEvent
@ -26,6 +25,7 @@ import kotlinx.coroutines.launch
import org.calyxos.seedvault.core.backends.Backend import org.calyxos.seedvault.core.backends.Backend
import org.calyxos.seedvault.core.backends.saf.SafProperties import org.calyxos.seedvault.core.backends.saf.SafProperties
import org.calyxos.seedvault.core.backends.webdav.WebDavConfig import org.calyxos.seedvault.core.backends.webdav.WebDavConfig
import org.calyxos.seedvault.core.backends.webdav.WebDavProperties
internal abstract class StorageViewModel( internal abstract class StorageViewModel(
private val app: Application, private val app: Application,
@ -48,8 +48,6 @@ internal abstract class StorageViewModel(
private var safOption: SafOption? = null private var safOption: SafOption? = null
internal var isSetupWizard: Boolean = false internal var isSetupWizard: Boolean = false
internal val hasStorageSet: Boolean
get() = backendManager.backendProperties != null
abstract val isRestoreOperation: Boolean abstract val isRestoreOperation: Boolean
internal fun loadStorageRoots() { internal fun loadStorageRoots() {

View file

@ -17,11 +17,11 @@ import com.stevesoltys.seedvault.proto.Snapshot
import com.stevesoltys.seedvault.proto.Snapshot.Apk import com.stevesoltys.seedvault.proto.Snapshot.Apk
import com.stevesoltys.seedvault.proto.Snapshot.Blob import com.stevesoltys.seedvault.proto.Snapshot.Blob
import com.stevesoltys.seedvault.proto.SnapshotKt.split import com.stevesoltys.seedvault.proto.SnapshotKt.split
import com.stevesoltys.seedvault.settings.SettingsManager
import com.stevesoltys.seedvault.repo.AppBackupManager import com.stevesoltys.seedvault.repo.AppBackupManager
import com.stevesoltys.seedvault.repo.BackupReceiver import com.stevesoltys.seedvault.repo.BackupReceiver
import com.stevesoltys.seedvault.repo.forProto import com.stevesoltys.seedvault.repo.forProto
import com.stevesoltys.seedvault.repo.hexFromProto import com.stevesoltys.seedvault.repo.hexFromProto
import com.stevesoltys.seedvault.settings.SettingsManager
import com.stevesoltys.seedvault.transport.backup.isNotUpdatedSystemApp import com.stevesoltys.seedvault.transport.backup.isNotUpdatedSystemApp
import com.stevesoltys.seedvault.transport.backup.isTestOnly import com.stevesoltys.seedvault.transport.backup.isTestOnly
import org.calyxos.seedvault.core.toHexString import org.calyxos.seedvault.core.toHexString

View file

@ -8,7 +8,7 @@ package com.stevesoltys.seedvault.worker
import android.content.Context import android.content.Context
import android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC import android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC
import android.util.Log import android.util.Log
import androidx.work.BackoffPolicy import androidx.work.BackoffPolicy.EXPONENTIAL
import androidx.work.CoroutineWorker import androidx.work.CoroutineWorker
import androidx.work.ExistingWorkPolicy.REPLACE import androidx.work.ExistingWorkPolicy.REPLACE
import androidx.work.ForegroundInfo import androidx.work.ForegroundInfo
@ -36,7 +36,7 @@ class AppBackupPruneWorker(
fun scheduleNow(context: Context) { fun scheduleNow(context: Context) {
val workRequest = OneTimeWorkRequestBuilder<AppBackupPruneWorker>() val workRequest = OneTimeWorkRequestBuilder<AppBackupPruneWorker>()
.setExpedited(RUN_AS_NON_EXPEDITED_WORK_REQUEST) .setExpedited(RUN_AS_NON_EXPEDITED_WORK_REQUEST)
.setBackoffCriteria(BackoffPolicy.EXPONENTIAL, Duration.ofSeconds(10)) .setBackoffCriteria(EXPONENTIAL, Duration.ofSeconds(10))
.build() .build()
val workManager = WorkManager.getInstance(context) val workManager = WorkManager.getInstance(context)
Log.i(TAG, "Asking to prune app backups now...") Log.i(TAG, "Asking to prune app backups now...")

View file

@ -24,8 +24,8 @@ import androidx.work.WorkManager
import androidx.work.WorkerParameters import androidx.work.WorkerParameters
import com.stevesoltys.seedvault.R import com.stevesoltys.seedvault.R
import com.stevesoltys.seedvault.backend.BackendManager import com.stevesoltys.seedvault.backend.BackendManager
import com.stevesoltys.seedvault.settings.SettingsManager
import com.stevesoltys.seedvault.repo.AppBackupManager import com.stevesoltys.seedvault.repo.AppBackupManager
import com.stevesoltys.seedvault.settings.SettingsManager
import com.stevesoltys.seedvault.ui.notification.BackupNotificationManager import com.stevesoltys.seedvault.ui.notification.BackupNotificationManager
import com.stevesoltys.seedvault.ui.notification.NOTIFICATION_ID_OBSERVER import com.stevesoltys.seedvault.ui.notification.NOTIFICATION_ID_OBSERVER
import org.koin.core.component.KoinComponent import org.koin.core.component.KoinComponent

View file

@ -20,8 +20,8 @@ import com.stevesoltys.seedvault.crypto.TYPE_ICONS
import com.stevesoltys.seedvault.proto.Snapshot import com.stevesoltys.seedvault.proto.Snapshot
import com.stevesoltys.seedvault.repo.AppBackupManager import com.stevesoltys.seedvault.repo.AppBackupManager
import com.stevesoltys.seedvault.repo.BackupReceiver import com.stevesoltys.seedvault.repo.BackupReceiver
import com.stevesoltys.seedvault.transport.backup.PackageService
import com.stevesoltys.seedvault.repo.Loader import com.stevesoltys.seedvault.repo.Loader
import com.stevesoltys.seedvault.transport.backup.PackageService
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import org.calyxos.backup.storage.crypto.StreamCrypto.toByteArray import org.calyxos.backup.storage.crypto.StreamCrypto.toByteArray
@ -150,13 +150,13 @@ internal class IconManager(
*/ */
@Suppress("DEPRECATION") @Suppress("DEPRECATION")
@Throws(IOException::class, SecurityException::class, GeneralSecurityException::class) @Throws(IOException::class, SecurityException::class, GeneralSecurityException::class)
fun downloadIconsV1(version: Byte, token: Long, inputStream: InputStream): Set<String> { fun downloadIconsV1(token: Long, inputStream: InputStream): Set<String> {
Log.d(TAG, "Start downloading icons") Log.d(TAG, "Start downloading icons")
val folder = File(context.cacheDir, CACHE_FOLDER) val folder = File(context.cacheDir, CACHE_FOLDER)
if (!folder.isDirectory && !folder.mkdirs()) if (!folder.isDirectory && !folder.mkdirs())
throw IOException("Can't create cache folder for icons") throw IOException("Can't create cache folder for icons")
val set = mutableSetOf<String>() val set = mutableSetOf<String>()
crypto.newDecryptingStreamV1(inputStream, getAD(version, token)).use { cryptoStream -> crypto.newDecryptingStreamV1(inputStream, getAD(1.toByte(), token)).use { cryptoStream ->
ZipInputStream(cryptoStream).use { zip -> ZipInputStream(cryptoStream).use { zip ->
var entry = zip.nextEntry var entry = zip.nextEntry
while (entry != null) { while (entry != null) {

View file

@ -21,7 +21,6 @@ import java.io.ByteArrayOutputStream
import java.io.IOException import java.io.IOException
import kotlin.random.Random import kotlin.random.Random
@Suppress("DEPRECATION")
@TestInstance(PER_METHOD) @TestInstance(PER_METHOD)
class CryptoIntegrationTest { class CryptoIntegrationTest {
@ -41,17 +40,6 @@ class CryptoIntegrationTest {
assertThat(crypto.getRandomBytes(42), not(equalTo(crypto.getRandomBytes(42)))) assertThat(crypto.getRandomBytes(42), not(equalTo(crypto.getRandomBytes(42))))
} }
@Test
fun `decrypting encrypted cleartext works v1`() {
val ad = Random.nextBytes(42)
val outputStream = ByteArrayOutputStream()
crypto.newEncryptingStreamV1(outputStream, ad).use { it.write(cleartext) }
val inputStream = ByteArrayInputStream(outputStream.toByteArray())
crypto.newDecryptingStreamV1(inputStream, ad).use {
assertReadEquals(cleartext, it)
}
}
@Test @Test
fun `decrypting encrypted cleartext works v2`() { fun `decrypting encrypted cleartext works v2`() {
val ad = Random.nextBytes(42) val ad = Random.nextBytes(42)
@ -63,18 +51,6 @@ class CryptoIntegrationTest {
} }
} }
@Test
fun `decrypting encrypted cleartext fails with different AD v1`() {
val outputStream = ByteArrayOutputStream()
crypto.newEncryptingStreamV1(outputStream, Random.nextBytes(42)).use { it.write(cleartext) }
val inputStream = ByteArrayInputStream(outputStream.toByteArray())
assertThrows(IOException::class.java) {
crypto.newDecryptingStreamV1(inputStream, Random.nextBytes(41)).use {
it.read()
}
}
}
@Test @Test
fun `decrypting encrypted cleartext fails with different AD v2`() { fun `decrypting encrypted cleartext fails with different AD v2`() {
val outputStream = ByteArrayOutputStream() val outputStream = ByteArrayOutputStream()

View file

@ -11,8 +11,8 @@ import io.mockk.every
import io.mockk.just import io.mockk.just
import io.mockk.mockk import io.mockk.mockk
import io.mockk.slot import io.mockk.slot
import junit.framework.Assert.assertTrue import org.junit.jupiter.api.Assertions.assertArrayEquals
import org.junit.Assert.assertArrayEquals import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance import org.junit.jupiter.api.TestInstance
import org.junit.jupiter.api.TestInstance.Lifecycle.PER_METHOD import org.junit.jupiter.api.TestInstance.Lifecycle.PER_METHOD

View file

@ -21,7 +21,6 @@ import com.stevesoltys.seedvault.metadata.PackageState.APK_AND_DATA
import com.stevesoltys.seedvault.metadata.PackageState.NOT_ALLOWED import com.stevesoltys.seedvault.metadata.PackageState.NOT_ALLOWED
import com.stevesoltys.seedvault.metadata.PackageState.NO_DATA import com.stevesoltys.seedvault.metadata.PackageState.NO_DATA
import com.stevesoltys.seedvault.metadata.PackageState.WAS_STOPPED import com.stevesoltys.seedvault.metadata.PackageState.WAS_STOPPED
import com.stevesoltys.seedvault.settings.SettingsManager
import io.mockk.Runs import io.mockk.Runs
import io.mockk.every import io.mockk.every
import io.mockk.just import io.mockk.just
@ -49,7 +48,6 @@ class MetadataManagerTest {
private val clock: Clock = mockk() private val clock: Clock = mockk()
private val metadataWriter: MetadataWriter = mockk() private val metadataWriter: MetadataWriter = mockk()
private val metadataReader: MetadataReader = mockk() private val metadataReader: MetadataReader = mockk()
private val settingsManager: SettingsManager = mockk()
private val manager = MetadataManager( private val manager = MetadataManager(
context = context, context = context,

View file

@ -86,7 +86,7 @@ internal class BackupReceiverTest : TransportTest() {
} }
@Test @Test
fun `readFromStream`() = runBlocking { fun readFromStream() = runBlocking {
val bytes = getRandomByteArray() val bytes = getRandomByteArray()
val chunkBytes1 = getRandomByteArray() val chunkBytes1 = getRandomByteArray()
val chunkBytes2 = getRandomByteArray() val chunkBytes2 = getRandomByteArray()

View file

@ -38,8 +38,7 @@ internal class SnapshotCreatorTest : TransportTest() {
private val ctx: Context = ApplicationProvider.getApplicationContext() private val ctx: Context = ApplicationProvider.getApplicationContext()
private val packageService: PackageService = mockk() private val packageService: PackageService = mockk()
private val snapshotCreator = private val snapshotCreator = SnapshotCreator(ctx, clock, packageService, metadataManager)
SnapshotCreator(ctx, clock, packageService, settingsManager, metadataManager)
@Test @Test
fun `test onApkBackedUp`() { fun `test onApkBackedUp`() {

View file

@ -22,16 +22,16 @@ import com.stevesoltys.seedvault.getRandomString
import com.stevesoltys.seedvault.metadata.PackageMetadata import com.stevesoltys.seedvault.metadata.PackageMetadata
import com.stevesoltys.seedvault.metadata.PackageMetadataMap import com.stevesoltys.seedvault.metadata.PackageMetadataMap
import com.stevesoltys.seedvault.proto.Snapshot import com.stevesoltys.seedvault.proto.Snapshot
import com.stevesoltys.seedvault.repo.AppBackupManager
import com.stevesoltys.seedvault.repo.BackupReceiver
import com.stevesoltys.seedvault.repo.Loader
import com.stevesoltys.seedvault.repo.SnapshotCreator
import com.stevesoltys.seedvault.repo.SnapshotManager
import com.stevesoltys.seedvault.repo.hexFromProto
import com.stevesoltys.seedvault.restore.install.ApkInstallState.IN_PROGRESS import com.stevesoltys.seedvault.restore.install.ApkInstallState.IN_PROGRESS
import com.stevesoltys.seedvault.restore.install.ApkInstallState.QUEUED import com.stevesoltys.seedvault.restore.install.ApkInstallState.QUEUED
import com.stevesoltys.seedvault.restore.install.ApkInstallState.SUCCEEDED import com.stevesoltys.seedvault.restore.install.ApkInstallState.SUCCEEDED
import com.stevesoltys.seedvault.repo.SnapshotManager
import com.stevesoltys.seedvault.transport.TransportTest import com.stevesoltys.seedvault.transport.TransportTest
import com.stevesoltys.seedvault.repo.AppBackupManager
import com.stevesoltys.seedvault.repo.BackupReceiver
import com.stevesoltys.seedvault.repo.SnapshotCreator
import com.stevesoltys.seedvault.repo.hexFromProto
import com.stevesoltys.seedvault.repo.Loader
import com.stevesoltys.seedvault.transport.restore.RestorableBackup import com.stevesoltys.seedvault.transport.restore.RestorableBackup
import com.stevesoltys.seedvault.worker.ApkBackup import com.stevesoltys.seedvault.worker.ApkBackup
import io.mockk.Runs import io.mockk.Runs
@ -41,7 +41,6 @@ import io.mockk.just
import io.mockk.mockk import io.mockk.mockk
import io.mockk.mockkStatic import io.mockk.mockkStatic
import io.mockk.slot import io.mockk.slot
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import org.calyxos.seedvault.core.backends.AppBackupFileType import org.calyxos.seedvault.core.backends.AppBackupFileType
import org.calyxos.seedvault.core.backends.Backend import org.calyxos.seedvault.core.backends.Backend

View file

@ -29,15 +29,15 @@ import com.stevesoltys.seedvault.metadata.PackageMetadataMap
import com.stevesoltys.seedvault.proto.SnapshotKt.blob import com.stevesoltys.seedvault.proto.SnapshotKt.blob
import com.stevesoltys.seedvault.proto.SnapshotKt.split import com.stevesoltys.seedvault.proto.SnapshotKt.split
import com.stevesoltys.seedvault.proto.copy import com.stevesoltys.seedvault.proto.copy
import com.stevesoltys.seedvault.transport.restore.RestorableBackup import com.stevesoltys.seedvault.repo.Loader
import com.stevesoltys.seedvault.repo.hexFromProto
import com.stevesoltys.seedvault.restore.install.ApkInstallState.FAILED import com.stevesoltys.seedvault.restore.install.ApkInstallState.FAILED
import com.stevesoltys.seedvault.restore.install.ApkInstallState.FAILED_SYSTEM_APP 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.IN_PROGRESS
import com.stevesoltys.seedvault.restore.install.ApkInstallState.QUEUED import com.stevesoltys.seedvault.restore.install.ApkInstallState.QUEUED
import com.stevesoltys.seedvault.restore.install.ApkInstallState.SUCCEEDED import com.stevesoltys.seedvault.restore.install.ApkInstallState.SUCCEEDED
import com.stevesoltys.seedvault.transport.TransportTest import com.stevesoltys.seedvault.transport.TransportTest
import com.stevesoltys.seedvault.repo.hexFromProto import com.stevesoltys.seedvault.transport.restore.RestorableBackup
import com.stevesoltys.seedvault.repo.Loader
import io.mockk.Runs import io.mockk.Runs
import io.mockk.coEvery import io.mockk.coEvery
import io.mockk.every import io.mockk.every

View file

@ -26,14 +26,14 @@ import com.stevesoltys.seedvault.getRandomString
import com.stevesoltys.seedvault.metadata.ApkSplit import com.stevesoltys.seedvault.metadata.ApkSplit
import com.stevesoltys.seedvault.metadata.PackageMetadata import com.stevesoltys.seedvault.metadata.PackageMetadata
import com.stevesoltys.seedvault.metadata.PackageMetadataMap import com.stevesoltys.seedvault.metadata.PackageMetadataMap
import com.stevesoltys.seedvault.transport.restore.RestorableBackup import com.stevesoltys.seedvault.repo.Loader
import com.stevesoltys.seedvault.restore.install.ApkInstallState.FAILED import com.stevesoltys.seedvault.restore.install.ApkInstallState.FAILED
import com.stevesoltys.seedvault.restore.install.ApkInstallState.FAILED_SYSTEM_APP 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.IN_PROGRESS
import com.stevesoltys.seedvault.restore.install.ApkInstallState.QUEUED import com.stevesoltys.seedvault.restore.install.ApkInstallState.QUEUED
import com.stevesoltys.seedvault.restore.install.ApkInstallState.SUCCEEDED import com.stevesoltys.seedvault.restore.install.ApkInstallState.SUCCEEDED
import com.stevesoltys.seedvault.transport.TransportTest import com.stevesoltys.seedvault.transport.TransportTest
import com.stevesoltys.seedvault.repo.Loader import com.stevesoltys.seedvault.transport.restore.RestorableBackup
import io.mockk.Runs import io.mockk.Runs
import io.mockk.coEvery import io.mockk.coEvery
import io.mockk.every import io.mockk.every

View file

@ -9,9 +9,9 @@ import com.stevesoltys.seedvault.getRandomString
import com.stevesoltys.seedvault.transport.TransportTest import com.stevesoltys.seedvault.transport.TransportTest
import io.mockk.every import io.mockk.every
import io.mockk.mockk import io.mockk.mockk
import org.junit.Assert.assertEquals import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.Assert.assertFalse import org.junit.jupiter.api.Assertions.assertFalse
import org.junit.Assert.assertTrue import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import kotlin.random.Random import kotlin.random.Random

View file

@ -93,16 +93,15 @@ internal class CoordinatorIntegrationTest : TransportTest() {
) )
private val packageService: PackageService = mockk() private val packageService: PackageService = mockk()
private val backup = BackupCoordinator( private val backup = BackupCoordinator(
context, context = context,
backendManager, backendManager = backendManager,
appBackupManager, appBackupManager = appBackupManager,
kvBackup, kv = kvBackup,
fullBackup, full = fullBackup,
clock, packageService = packageService,
packageService, metadataManager = metadataManager,
metadataManager, settingsManager = settingsManager,
settingsManager, nm = notificationManager,
notificationManager
) )
private val kvRestore = KVRestore( private val kvRestore = KVRestore(

View file

@ -13,7 +13,6 @@ import android.os.ParcelFileDescriptor
import com.stevesoltys.seedvault.backend.BackendManager import com.stevesoltys.seedvault.backend.BackendManager
import com.stevesoltys.seedvault.getRandomString import com.stevesoltys.seedvault.getRandomString
import com.stevesoltys.seedvault.metadata.BackupType import com.stevesoltys.seedvault.metadata.BackupType
import com.stevesoltys.seedvault.metadata.PackageMetadata
import com.stevesoltys.seedvault.metadata.PackageState.NO_DATA import com.stevesoltys.seedvault.metadata.PackageState.NO_DATA
import com.stevesoltys.seedvault.metadata.PackageState.QUOTA_EXCEEDED import com.stevesoltys.seedvault.metadata.PackageState.QUOTA_EXCEEDED
import com.stevesoltys.seedvault.metadata.PackageState.UNKNOWN_ERROR import com.stevesoltys.seedvault.metadata.PackageState.UNKNOWN_ERROR
@ -51,7 +50,6 @@ internal class BackupCoordinatorTest : BackupTest() {
appBackupManager = appBackupManager, appBackupManager = appBackupManager,
kv = kv, kv = kv,
full = full, full = full,
clock = clock,
packageService = packageService, packageService = packageService,
metadataManager = metadataManager, metadataManager = metadataManager,
settingsManager = settingsManager, settingsManager = settingsManager,
@ -60,7 +58,6 @@ internal class BackupCoordinatorTest : BackupTest() {
private val backend = mockk<Backend>() private val backend = mockk<Backend>()
private val fileDescriptor: ParcelFileDescriptor = mockk() private val fileDescriptor: ParcelFileDescriptor = mockk()
private val packageMetadata: PackageMetadata = mockk()
private val safProperties = SafProperties( private val safProperties = SafProperties(
config = Uri.EMPTY, config = Uri.EMPTY,
name = getRandomString(), name = getRandomString(),

View file

@ -66,7 +66,7 @@ internal class BackupCreationTest : BackupTest() {
private val appBackupManager = mockk<AppBackupManager>() private val appBackupManager = mockk<AppBackupManager>()
private val packageService = mockk<PackageService>() private val packageService = mockk<PackageService>()
private val snapshotCreator = private val snapshotCreator =
SnapshotCreator(context, clock, packageService, settingsManager, mockk(relaxed = true)) SnapshotCreator(context, clock, packageService, mockk(relaxed = true))
private val notificationManager = mockk<BackupNotificationManager>() private val notificationManager = mockk<BackupNotificationManager>()
private val db = TestKvDbManager() private val db = TestKvDbManager()
@ -80,7 +80,6 @@ internal class BackupCreationTest : BackupTest() {
appBackupManager = appBackupManager, appBackupManager = appBackupManager,
kv = kvBackup, kv = kvBackup,
full = fullBackup, full = fullBackup,
clock = clock,
packageService = packageService, packageService = packageService,
metadataManager = metadataManager, metadataManager = metadataManager,
settingsManager = settingsManager, settingsManager = settingsManager,

View file

@ -31,7 +31,6 @@ import io.mockk.coVerify
import io.mockk.every import io.mockk.every
import io.mockk.just import io.mockk.just
import io.mockk.mockk import io.mockk.mockk
import io.mockk.mockkStatic
import io.mockk.verify import io.mockk.verify
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import org.calyxos.seedvault.core.backends.AppBackupFileType import org.calyxos.seedvault.core.backends.AppBackupFileType
@ -90,28 +89,17 @@ internal class RestoreCoordinatorTest : TransportTest() {
chunkIds = listOf(chunkId2), chunkIds = listOf(chunkId2),
) )
mockkStatic("com.stevesoltys.seedvault.backend.BackendExtKt")
every { backendManager.backend } returns backend every { backendManager.backend } returns backend
} }
@Test @Test
fun `getAvailableRestoreSets() builds set from plugin response`() = runBlocking { fun `getAvailableRestoreSets() builds set from plugin response`() = runBlocking {
val info1 = FileInfo(LegacyAppBackupFile.Metadata(token), 1) val handle1 = LegacyAppBackupFile.Metadata(token)
val info2 = FileInfo(LegacyAppBackupFile.Metadata(token + 1), 2) val handle2 = LegacyAppBackupFile.Metadata(token + 1)
coEvery { coEvery { backend.getAvailableBackupFileHandles() } returns listOf(handle1, handle2)
backend.list( coEvery { backend.load(handle1) } returns inputStream
topLevelFolder = null, coEvery { backend.load(handle2) } returns inputStream
AppBackupFileType.Snapshot::class, LegacyAppBackupFile.Metadata::class,
callback = captureLambda<(FileInfo) -> Unit>()
)
} answers {
val callback = lambda<(FileInfo) -> Unit>().captured
callback(info1)
callback(info2)
}
coEvery { backend.load(info1.fileHandle) } returns inputStream
coEvery { backend.load(info2.fileHandle) } returns inputStream
every { metadataReader.readMetadata(inputStream, token) } returns metadata every { metadataReader.readMetadata(inputStream, token) } returns metadata
every { metadataReader.readMetadata(inputStream, token + 1) } returns metadata every { metadataReader.readMetadata(inputStream, token + 1) } returns metadata
every { inputStream.close() } just Runs every { inputStream.close() } just Runs
@ -146,22 +134,12 @@ internal class RestoreCoordinatorTest : TransportTest() {
@Test @Test
fun `startRestore() fetches metadata if missing`() = runBlocking { fun `startRestore() fetches metadata if missing`() = runBlocking {
val info1 = FileInfo(LegacyAppBackupFile.Metadata(token), 1) val handle1 = LegacyAppBackupFile.Metadata(token)
val info2 = FileInfo(LegacyAppBackupFile.Metadata(token + 1), 2) val handle2 = LegacyAppBackupFile.Metadata(token + 1)
coEvery { coEvery { backend.getAvailableBackupFileHandles() } returns listOf(handle1, handle2)
backend.list( coEvery { backend.load(handle1) } returns inputStream
topLevelFolder = null, coEvery { backend.load(handle2) } returns inputStream
AppBackupFileType.Snapshot::class, LegacyAppBackupFile.Metadata::class,
callback = captureLambda<(FileInfo) -> Unit>()
)
} answers {
val callback = lambda<(FileInfo) -> Unit>().captured
callback(info1)
callback(info2)
}
coEvery { backend.load(info1.fileHandle) } returns inputStream
coEvery { backend.load(info2.fileHandle) } returns inputStream
every { metadataReader.readMetadata(inputStream, token) } returns metadata every { metadataReader.readMetadata(inputStream, token) } returns metadata
every { metadataReader.readMetadata(inputStream, token + 1) } returns metadata every { metadataReader.readMetadata(inputStream, token + 1) } returns metadata
every { inputStream.close() } just Runs every { inputStream.close() } just Runs
@ -273,21 +251,10 @@ internal class RestoreCoordinatorTest : TransportTest() {
@Test @Test
fun `startRestore() errors when it can't find snapshots`() = runBlocking { fun `startRestore() errors when it can't find snapshots`() = runBlocking {
val handle = AppBackupFileType.Snapshot(repoId, getRandomByteArray(32).toHexString()) val handle = AppBackupFileType.Snapshot(repoId, getRandomByteArray(32).toHexString())
val info = FileInfo(handle, 1)
every { backendManager.backendProperties } returns safStorage every { backendManager.backendProperties } returns safStorage
every { safStorage.isUnavailableUsb(context) } returns false every { safStorage.isUnavailableUsb(context) } returns false
coEvery { backend.getAvailableBackupFileHandles() } returns listOf(handle)
coEvery {
backend.list(
topLevelFolder = null,
AppBackupFileType.Snapshot::class, LegacyAppBackupFile.Metadata::class,
callback = captureLambda<(FileInfo) -> Unit>()
)
} answers {
val callback = lambda<(FileInfo) -> Unit>().captured
callback(info)
}
coEvery { snapshotManager.loadSnapshot(handle) } returns snapshot.copy { coEvery { snapshotManager.loadSnapshot(handle) } returns snapshot.copy {
token = this@RestoreCoordinatorTest.token - 1 // unexpected token token = this@RestoreCoordinatorTest.token - 1 // unexpected token
} }

View file

@ -23,8 +23,8 @@ import com.stevesoltys.seedvault.proto.copy
import com.stevesoltys.seedvault.repo.AppBackupManager import com.stevesoltys.seedvault.repo.AppBackupManager
import com.stevesoltys.seedvault.repo.BackupData import com.stevesoltys.seedvault.repo.BackupData
import com.stevesoltys.seedvault.repo.BackupReceiver import com.stevesoltys.seedvault.repo.BackupReceiver
import com.stevesoltys.seedvault.transport.backup.BackupTest
import com.stevesoltys.seedvault.repo.SnapshotCreator import com.stevesoltys.seedvault.repo.SnapshotCreator
import com.stevesoltys.seedvault.transport.backup.BackupTest
import io.mockk.Runs import io.mockk.Runs
import io.mockk.coEvery import io.mockk.coEvery
import io.mockk.coVerify import io.mockk.coVerify

View file

@ -23,6 +23,5 @@ public object Constants {
public val appSnapshotRegex: Regex = Regex("(^[a-f0-9]{64})\\.snapshot$") public val appSnapshotRegex: Regex = Regex("(^[a-f0-9]{64})\\.snapshot$")
public val fileSnapshotRegex: Regex = Regex("(^[0-9]{13})\\.SeedSnap$") // good until year 2286 public val fileSnapshotRegex: Regex = Regex("(^[0-9]{13})\\.SeedSnap$") // good until year 2286
public const val MIME_TYPE: String = "application/octet-stream" public const val MIME_TYPE: String = "application/octet-stream"
public const val CHUNK_FOLDER_COUNT: Int = 256
} }

View file

@ -16,7 +16,6 @@ import org.calyxos.backup.storage.api.BackupFile
import org.calyxos.backup.storage.api.StorageBackup import org.calyxos.backup.storage.api.StorageBackup
import org.calyxos.backup.storage.backup.NotificationBackupObserver import org.calyxos.backup.storage.backup.NotificationBackupObserver
import kotlin.time.DurationUnit import kotlin.time.DurationUnit
import kotlin.time.ExperimentalTime
import kotlin.time.toDuration import kotlin.time.toDuration
data class BackupProgress( data class BackupProgress(
@ -91,7 +90,6 @@ internal class BackupStats(
liveData.postValue(BackupProgress(filesProcessed, totalFiles, null)) liveData.postValue(BackupProgress(filesProcessed, totalFiles, null))
} }
@OptIn(ExperimentalTime::class)
override suspend fun onBackupComplete(backupDuration: Long?) { override suspend fun onBackupComplete(backupDuration: Long?) {
super.onBackupComplete(backupDuration) super.onBackupComplete(backupDuration)
@ -162,7 +160,6 @@ internal class BackupStats(
liveData.postValue(BackupProgress(filesProcessed, totalFiles, text)) liveData.postValue(BackupProgress(filesProcessed, totalFiles, text))
} }
@OptIn(ExperimentalTime::class)
override suspend fun onPruneComplete(pruneDuration: Long) { override suspend fun onPruneComplete(pruneDuration: Long) {
super.onPruneComplete(pruneDuration) super.onPruneComplete(pruneDuration)

View file

@ -10,17 +10,17 @@ import android.security.keystore.KeyProperties.PURPOSE_ENCRYPT
import android.security.keystore.KeyProperties.PURPOSE_SIGN import android.security.keystore.KeyProperties.PURPOSE_SIGN
import android.security.keystore.KeyProperties.PURPOSE_VERIFY import android.security.keystore.KeyProperties.PURPOSE_VERIFY
import android.security.keystore.KeyProtection import android.security.keystore.KeyProtection
import org.calyxos.seedvault.core.crypto.CoreCrypto.ALGORITHM_HMAC
import java.security.KeyStore import java.security.KeyStore
import javax.crypto.SecretKey import javax.crypto.SecretKey
import javax.crypto.spec.SecretKeySpec import javax.crypto.spec.SecretKeySpec
object KeyManager: org.calyxos.seedvault.core.crypto.KeyManager { object KeyManager : org.calyxos.seedvault.core.crypto.KeyManager {
private const val KEY_SIZE = 256 private const val KEY_SIZE = 256
internal const val KEY_SIZE_BYTES = KEY_SIZE / 8 private const val KEY_SIZE_BYTES = KEY_SIZE / 8
private const val KEY_ALIAS_MASTER = "com.stevesoltys.seedvault.master" private const val KEY_ALIAS_MASTER = "com.stevesoltys.seedvault.master"
private const val ANDROID_KEY_STORE = "AndroidKeyStore" private const val ANDROID_KEY_STORE = "AndroidKeyStore"
private const val ALGORITHM_HMAC = "HmacSHA256"
private const val FAKE_SEED = "This is a legacy backup key 1234" private const val FAKE_SEED = "This is a legacy backup key 1234"

View file

@ -14,10 +14,8 @@ import org.calyxos.backup.storage.api.BackupFile
import org.calyxos.backup.storage.scanner.DocumentScanner import org.calyxos.backup.storage.scanner.DocumentScanner
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Date import java.util.Date
import kotlin.time.ExperimentalTime
import kotlin.time.measureTimedValue import kotlin.time.measureTimedValue
@OptIn(ExperimentalTime::class)
fun scanTree(context: Context, documentScanner: DocumentScanner, treeUri: Uri): String { fun scanTree(context: Context, documentScanner: DocumentScanner, treeUri: Uri): String {
val sb = StringBuilder() val sb = StringBuilder()
val timedResult = measureTimedValue { val timedResult = measureTimedValue {

View file

@ -13,7 +13,6 @@ import org.calyxos.backup.storage.api.BackupFile
import org.calyxos.backup.storage.scanner.MediaScanner import org.calyxos.backup.storage.scanner.MediaScanner
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Date import java.util.Date
import kotlin.time.ExperimentalTime
import kotlin.time.TimedValue import kotlin.time.TimedValue
import kotlin.time.measureTimedValue import kotlin.time.measureTimedValue
@ -27,7 +26,6 @@ data class ScanResult(
} }
} }
@OptIn(ExperimentalTime::class)
fun scanUri(context: Context, mediaScanner: MediaScanner, uri: Uri): String { fun scanUri(context: Context, mediaScanner: MediaScanner, uri: Uri): String {
val sb = StringBuilder() val sb = StringBuilder()
val timedResult = measureTimedValue { val timedResult = measureTimedValue {
@ -57,7 +55,6 @@ fun dump(context: Context, mediaFiles: List<BackupFile>, sb: StringBuilder? = nu
return ScanResult(itemsFound, totalSize) return ScanResult(itemsFound, totalSize)
} }
@OptIn(ExperimentalTime::class)
fun appendStats( fun appendStats(
context: Context, context: Context,
sb: StringBuilder, sb: StringBuilder,

View file

@ -17,7 +17,6 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.Toast import android.widget.Toast
import android.widget.Toast.LENGTH_SHORT import android.widget.Toast.LENGTH_SHORT
import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import de.grobox.storagebackuptester.MainViewModel import de.grobox.storagebackuptester.MainViewModel

View file

@ -6,4 +6,5 @@
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" /> <background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" /> <foreground android:drawable="@drawable/ic_launcher_foreground" />
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon> </adaptive-icon>

View file

@ -14,7 +14,7 @@
<item name="colorSecondaryVariant">@color/teal_200</item> <item name="colorSecondaryVariant">@color/teal_200</item>
<item name="colorOnSecondary">@color/black</item> <item name="colorOnSecondary">@color/black</item>
<!-- Status bar color. --> <!-- Status bar color. -->
<item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item> <item name="android:statusBarColor">?attr/colorPrimaryVariant</item>
<!-- Customize your theme here. --> <!-- Customize your theme here. -->
<item name="colorAccent">@color/matrix</item> <item name="colorAccent">@color/matrix</item>
</style> </style>

View file

@ -4,8 +4,6 @@
SPDX-License-Identifier: Apache-2.0 SPDX-License-Identifier: Apache-2.0
--> -->
<resources> <resources>
<color name="purple_200">#FFBB86FC</color>
<color name="purple_500">#FF6200EE</color>
<color name="purple_700">#FF3700B3</color> <color name="purple_700">#FF3700B3</color>
<color name="teal_200">#FF03DAC5</color> <color name="teal_200">#FF03DAC5</color>
<color name="teal_700">#FF018786</color> <color name="teal_700">#FF018786</color>

View file

@ -11,7 +11,6 @@ import kotlin.contracts.InvocationKind
import kotlin.contracts.contract import kotlin.contracts.contract
import kotlin.time.Duration import kotlin.time.Duration
import kotlin.time.DurationUnit import kotlin.time.DurationUnit
import kotlin.time.ExperimentalTime
import kotlin.time.toDuration import kotlin.time.toDuration
/** /**
@ -20,7 +19,7 @@ import kotlin.time.toDuration
* So when building with AOSP 11, things will blow up. * So when building with AOSP 11, things will blow up.
*/ */
@OptIn(ExperimentalContracts::class, ExperimentalTime::class) @OptIn(ExperimentalContracts::class)
internal inline fun measure(block: () -> Unit): Duration { internal inline fun measure(block: () -> Unit): Duration {
contract { contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE) callsInPlace(block, InvocationKind.EXACTLY_ONCE)
@ -30,7 +29,7 @@ internal inline fun measure(block: () -> Unit): Duration {
return (System.currentTimeMillis() - start).toDuration(DurationUnit.MILLISECONDS) return (System.currentTimeMillis() - start).toDuration(DurationUnit.MILLISECONDS)
} }
@OptIn(ExperimentalContracts::class, ExperimentalTime::class) @OptIn(ExperimentalContracts::class)
internal inline fun <T> measure(text: String, block: () -> T): T { internal inline fun <T> measure(text: String, block: () -> T): T {
contract { contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE) callsInPlace(block, InvocationKind.EXACTLY_ONCE)