From 8d949e2d64083dc6a5ba620a5c82e3d5d0fd8bb1 Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Wed, 25 Sep 2024 14:12:09 -0300 Subject: [PATCH] Support adb shell bmgr backupnow We don't get notified about the start nor the end of such a backup run, so we need hacks to do initialization and finalization. --- .../seedvault/repo/AppBackupManager.kt | 27 +++++++++++++++++++ .../transport/ConfigurableBackupTransport.kt | 4 +-- .../ConfigurableBackupTransportService.kt | 8 ++++++ .../transport/backup/BackupCoordinator.kt | 9 +++++-- .../transport/backup/BackupCoordinatorTest.kt | 4 +++ 5 files changed, 48 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/stevesoltys/seedvault/repo/AppBackupManager.kt b/app/src/main/java/com/stevesoltys/seedvault/repo/AppBackupManager.kt index fae3b4db..5af26180 100644 --- a/app/src/main/java/com/stevesoltys/seedvault/repo/AppBackupManager.kt +++ b/app/src/main/java/com/stevesoltys/seedvault/repo/AppBackupManager.kt @@ -38,9 +38,13 @@ internal class AppBackupManager( /** * A temporary [SnapshotCreator] that has a lifetime only valid during the backup run. */ + @Volatile var snapshotCreator: SnapshotCreator? = null private set + @Volatile + private var startedViaAdb = false + /** * Call this method before doing any kind of backup work. * It will @@ -113,6 +117,29 @@ internal class AppBackupManager( } } + /** + * When doing backups with `adb shell bmgr backupnow`, + * we don't get a chance to do our initialization in [beforeBackup], + * so we use this opportunity to do it now. + */ + suspend fun ensureBackupPrepared() = if (snapshotCreator == null) { + log.warn { "Backup not prepared. If not started via `adb shell bmgr` that's a bug" } + startedViaAdb = true + beforeBackup() + } else Unit + + /** + * We don't get notified when backups ran from `adb shell bmgr backupnow` end, + * so [afterBackupFinished] will not run, so we need to find a place + */ + suspend fun finalizeBackupIfNeeded() { + if (startedViaAdb) { + log.warn { "Backup not finalized. If not started via `adb shell bmgr` that's a bug" } + startedViaAdb = false + afterBackupFinished(true) // is there a way to know if success or not? + } + } + /** * Returns true if the repo identified by [repoId] can be transferred to this device. * This is the case when it isn't the same as the current repoId and the version is latest. diff --git a/app/src/main/java/com/stevesoltys/seedvault/transport/ConfigurableBackupTransport.kt b/app/src/main/java/com/stevesoltys/seedvault/transport/ConfigurableBackupTransport.kt index 02c8c5b3..87236862 100644 --- a/app/src/main/java/com/stevesoltys/seedvault/transport/ConfigurableBackupTransport.kt +++ b/app/src/main/java/com/stevesoltys/seedvault/transport/ConfigurableBackupTransport.kt @@ -127,8 +127,8 @@ class ConfigurableBackupTransport internal constructor(private val context: Cont return backupCoordinator.isAppEligibleForBackup(targetPackage, isFullBackup) } - override fun getBackupQuota(packageName: String, isFullBackup: Boolean): Long { - return backupCoordinator.getBackupQuota(packageName, isFullBackup) + override fun getBackupQuota(packageName: String, isFullBackup: Boolean): Long = runBlocking { + backupCoordinator.getBackupQuota(packageName, isFullBackup) } override fun clearBackupData(packageInfo: PackageInfo): Int = runBlocking { diff --git a/app/src/main/java/com/stevesoltys/seedvault/transport/ConfigurableBackupTransportService.kt b/app/src/main/java/com/stevesoltys/seedvault/transport/ConfigurableBackupTransportService.kt index 4627bd72..168db648 100644 --- a/app/src/main/java/com/stevesoltys/seedvault/transport/ConfigurableBackupTransportService.kt +++ b/app/src/main/java/com/stevesoltys/seedvault/transport/ConfigurableBackupTransportService.kt @@ -12,9 +12,11 @@ import android.os.IBinder import android.util.Log import com.stevesoltys.seedvault.crypto.KeyManager import com.stevesoltys.seedvault.permitDiskReads +import com.stevesoltys.seedvault.repo.AppBackupManager import com.stevesoltys.seedvault.ui.notification.BackupNotificationManager import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.runBlocking import org.koin.core.component.KoinComponent import org.koin.core.component.inject @@ -35,6 +37,7 @@ class ConfigurableBackupTransportService : Service(), KoinComponent { private val keyManager: KeyManager by inject() private val backupManager: IBackupManager by inject() + private val appBackupManager: AppBackupManager by inject() private val notificationManager: BackupNotificationManager by inject() override fun onCreate() { @@ -62,6 +65,11 @@ class ConfigurableBackupTransportService : Service(), KoinComponent { notificationManager.onServiceDestroyed() transport = null mIsRunning.value = false + runBlocking { + // This is a hack for `adb shell bmgr backupnow`. Better would be a foreground service, + // but since this isn't a typical use-case we don't bother for now. + appBackupManager.finalizeBackupIfNeeded() + } Log.d(TAG, "Service destroyed.") } 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 1fdcf070..5edf9321 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 @@ -126,9 +126,14 @@ internal class BackupCoordinator( * otherwise for key-value backup. * @return Current limit on backup size in bytes. */ - fun getBackupQuota(packageName: String, isFullBackup: Boolean): Long { - // report back quota + suspend fun getBackupQuota(packageName: String, isFullBackup: Boolean): Long { Log.i(TAG, "Get backup quota for $packageName. Is full backup: $isFullBackup.") + + if (!isFullBackup) { + // hack for `adb shell bmgr backupnow` + // which starts with a K/V backup calling this method, so we hook in here + appBackupManager.ensureBackupPrepared() + } val quota = settingsManager.quota Log.i(TAG, "Reported quota of $quota bytes.") return quota 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 b2e40835..5c300f99 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 @@ -85,6 +85,10 @@ internal class BackupCoordinatorTest : BackupTest() { val quota = Random.nextLong() every { settingsManager.quota } returns quota + if (!isFullBackup) { // hack for `adb shell bmgr` which starts with a K/V backup + coEvery { appBackupManager.ensureBackupPrepared() } just Runs + } + assertEquals(quota, backup.getBackupQuota(packageInfo.packageName, isFullBackup)) }