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.
This commit is contained in:
parent
e602bbe2ab
commit
8d949e2d64
5 changed files with 48 additions and 4 deletions
|
@ -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.
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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.")
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue