Handle new FLAG_DATA_NOT_CHANGED for K/V backups
This commit is contained in:
parent
25695d72b8
commit
8bdbe6d681
3 changed files with 64 additions and 2 deletions
|
@ -1,6 +1,12 @@
|
||||||
package com.stevesoltys.seedvault.transport.backup
|
package com.stevesoltys.seedvault.transport.backup
|
||||||
|
|
||||||
|
import android.app.backup.BackupTransport.FLAG_DATA_NOT_CHANGED
|
||||||
|
import android.app.backup.BackupTransport.FLAG_INCREMENTAL
|
||||||
|
import android.app.backup.BackupTransport.FLAG_NON_INCREMENTAL
|
||||||
|
import android.app.backup.BackupTransport.FLAG_USER_INITIATED
|
||||||
import android.app.backup.BackupTransport.TRANSPORT_ERROR
|
import android.app.backup.BackupTransport.TRANSPORT_ERROR
|
||||||
|
import android.app.backup.BackupTransport.TRANSPORT_NON_INCREMENTAL_BACKUP_REQUIRED
|
||||||
|
import android.app.backup.BackupTransport.TRANSPORT_NOT_INITIALIZED
|
||||||
import android.app.backup.BackupTransport.TRANSPORT_OK
|
import android.app.backup.BackupTransport.TRANSPORT_OK
|
||||||
import android.app.backup.BackupTransport.TRANSPORT_PACKAGE_REJECTED
|
import android.app.backup.BackupTransport.TRANSPORT_PACKAGE_REJECTED
|
||||||
import android.app.backup.BackupTransport.TRANSPORT_QUOTA_EXCEEDED
|
import android.app.backup.BackupTransport.TRANSPORT_QUOTA_EXCEEDED
|
||||||
|
@ -163,6 +169,42 @@ internal class BackupCoordinator(
|
||||||
Log.i(TAG, "Request incremental backup time. Returned $this")
|
Log.i(TAG, "Request incremental backup time. Returned $this")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send one application's key/value data update to the backup destination.
|
||||||
|
* The transport may send the data immediately, or may buffer it.
|
||||||
|
* If this method returns [TRANSPORT_OK], [finishBackup] will then be called
|
||||||
|
* to ensure the data is sent and recorded successfully.
|
||||||
|
*
|
||||||
|
* If the backup data is a diff against the previous backup
|
||||||
|
* then the flag [FLAG_INCREMENTAL] will be set.
|
||||||
|
* Otherwise, if the data is a complete backup set,
|
||||||
|
* then [FLAG_NON_INCREMENTAL] will be set.
|
||||||
|
* Before P neither flag will be set regardless of whether the backup is incremental or not.
|
||||||
|
*
|
||||||
|
* If [FLAG_INCREMENTAL] is set and the transport does not have data
|
||||||
|
* for this package in its storage backend then it cannot apply the incremental diff.
|
||||||
|
* Thus it should return [TRANSPORT_NON_INCREMENTAL_BACKUP_REQUIRED]
|
||||||
|
* to indicate that backup manager should delete its state
|
||||||
|
* and retry the package as a non-incremental backup.
|
||||||
|
*
|
||||||
|
* Note that if an app (e.g. com.whatsapp) has no data to backup,
|
||||||
|
* this method will NOT even be called for the app.
|
||||||
|
*
|
||||||
|
* @param packageInfo The identity of the application whose data is being backed up.
|
||||||
|
* This specifically includes the signature list for the package.
|
||||||
|
* @param data Descriptor of file with data that resulted from invoking the application's
|
||||||
|
* BackupService.doBackup() method. This may be a pipe rather than a file on
|
||||||
|
* persistent media, so it may not be seekable.
|
||||||
|
* @param flags a combination of [FLAG_USER_INITIATED], [FLAG_NON_INCREMENTAL],
|
||||||
|
* [FLAG_INCREMENTAL], [FLAG_DATA_NOT_CHANGED], or 0.
|
||||||
|
* @return one of [TRANSPORT_OK] (OK so far),
|
||||||
|
* [TRANSPORT_PACKAGE_REJECTED] (to suppress backup of this package, but let others proceed),
|
||||||
|
* [TRANSPORT_ERROR] (on network error or other failure),
|
||||||
|
* [TRANSPORT_NON_INCREMENTAL_BACKUP_REQUIRED] (if the transport cannot accept
|
||||||
|
* an incremental backup for this package), or
|
||||||
|
* [TRANSPORT_NOT_INITIALIZED] (if the backend dataset has become lost due to
|
||||||
|
* inactivity purge or some other reason and needs re-initializing)
|
||||||
|
*/
|
||||||
suspend fun performIncrementalBackup(
|
suspend fun performIncrementalBackup(
|
||||||
packageInfo: PackageInfo,
|
packageInfo: PackageInfo,
|
||||||
data: ParcelFileDescriptor,
|
data: ParcelFileDescriptor,
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package com.stevesoltys.seedvault.transport.backup
|
package com.stevesoltys.seedvault.transport.backup
|
||||||
|
|
||||||
|
import android.app.backup.BackupTransport.FLAG_DATA_NOT_CHANGED
|
||||||
import android.app.backup.BackupTransport.FLAG_INCREMENTAL
|
import android.app.backup.BackupTransport.FLAG_INCREMENTAL
|
||||||
import android.app.backup.BackupTransport.FLAG_NON_INCREMENTAL
|
import android.app.backup.BackupTransport.FLAG_NON_INCREMENTAL
|
||||||
import android.app.backup.BackupTransport.TRANSPORT_ERROR
|
import android.app.backup.BackupTransport.TRANSPORT_ERROR
|
||||||
|
@ -8,12 +9,12 @@ import android.app.backup.BackupTransport.TRANSPORT_OK
|
||||||
import android.content.pm.PackageInfo
|
import android.content.pm.PackageInfo
|
||||||
import android.os.ParcelFileDescriptor
|
import android.os.ParcelFileDescriptor
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import com.stevesoltys.seedvault.ui.notification.BackupNotificationManager
|
|
||||||
import com.stevesoltys.seedvault.MAGIC_PACKAGE_MANAGER
|
import com.stevesoltys.seedvault.MAGIC_PACKAGE_MANAGER
|
||||||
import com.stevesoltys.seedvault.crypto.Crypto
|
import com.stevesoltys.seedvault.crypto.Crypto
|
||||||
import com.stevesoltys.seedvault.encodeBase64
|
import com.stevesoltys.seedvault.encodeBase64
|
||||||
import com.stevesoltys.seedvault.header.HeaderWriter
|
import com.stevesoltys.seedvault.header.HeaderWriter
|
||||||
import com.stevesoltys.seedvault.header.VersionHeader
|
import com.stevesoltys.seedvault.header.VersionHeader
|
||||||
|
import com.stevesoltys.seedvault.ui.notification.BackupNotificationManager
|
||||||
import libcore.io.IoUtils.closeQuietly
|
import libcore.io.IoUtils.closeQuietly
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
|
|
||||||
|
@ -45,11 +46,15 @@ internal class KVBackup(
|
||||||
data: ParcelFileDescriptor,
|
data: ParcelFileDescriptor,
|
||||||
flags: Int
|
flags: Int
|
||||||
): Int {
|
): Int {
|
||||||
|
val dataNotChanged = flags and FLAG_DATA_NOT_CHANGED != 0
|
||||||
val isIncremental = flags and FLAG_INCREMENTAL != 0
|
val isIncremental = flags and FLAG_INCREMENTAL != 0
|
||||||
val isNonIncremental = flags and FLAG_NON_INCREMENTAL != 0
|
val isNonIncremental = flags and FLAG_NON_INCREMENTAL != 0
|
||||||
val packageName = packageInfo.packageName
|
val packageName = packageInfo.packageName
|
||||||
|
|
||||||
when {
|
when {
|
||||||
|
dataNotChanged -> {
|
||||||
|
Log.i(TAG, "No K/V backup data has changed for $packageName")
|
||||||
|
}
|
||||||
isIncremental -> {
|
isIncremental -> {
|
||||||
Log.i(TAG, "Performing incremental K/V backup for $packageName")
|
Log.i(TAG, "Performing incremental K/V backup for $packageName")
|
||||||
}
|
}
|
||||||
|
@ -65,6 +70,9 @@ internal class KVBackup(
|
||||||
if (this.state != null) throw AssertionError()
|
if (this.state != null) throw AssertionError()
|
||||||
this.state = KVBackupState(packageInfo)
|
this.state = KVBackupState(packageInfo)
|
||||||
|
|
||||||
|
// no need for backup when no data has changed
|
||||||
|
if (dataNotChanged) return TRANSPORT_OK
|
||||||
|
|
||||||
// check if we have existing data for the given package
|
// check if we have existing data for the given package
|
||||||
val hasDataForPackage = try {
|
val hasDataForPackage = try {
|
||||||
plugin.hasDataForPackage(packageInfo)
|
plugin.hasDataForPackage(packageInfo)
|
||||||
|
|
|
@ -1,17 +1,18 @@
|
||||||
package com.stevesoltys.seedvault.transport.backup
|
package com.stevesoltys.seedvault.transport.backup
|
||||||
|
|
||||||
import android.app.backup.BackupDataInput
|
import android.app.backup.BackupDataInput
|
||||||
|
import android.app.backup.BackupTransport.FLAG_DATA_NOT_CHANGED
|
||||||
import android.app.backup.BackupTransport.FLAG_INCREMENTAL
|
import android.app.backup.BackupTransport.FLAG_INCREMENTAL
|
||||||
import android.app.backup.BackupTransport.FLAG_NON_INCREMENTAL
|
import android.app.backup.BackupTransport.FLAG_NON_INCREMENTAL
|
||||||
import android.app.backup.BackupTransport.TRANSPORT_ERROR
|
import android.app.backup.BackupTransport.TRANSPORT_ERROR
|
||||||
import android.app.backup.BackupTransport.TRANSPORT_NON_INCREMENTAL_BACKUP_REQUIRED
|
import android.app.backup.BackupTransport.TRANSPORT_NON_INCREMENTAL_BACKUP_REQUIRED
|
||||||
import android.app.backup.BackupTransport.TRANSPORT_OK
|
import android.app.backup.BackupTransport.TRANSPORT_OK
|
||||||
import android.content.pm.PackageInfo
|
import android.content.pm.PackageInfo
|
||||||
import com.stevesoltys.seedvault.ui.notification.BackupNotificationManager
|
|
||||||
import com.stevesoltys.seedvault.Utf8
|
import com.stevesoltys.seedvault.Utf8
|
||||||
import com.stevesoltys.seedvault.getRandomString
|
import com.stevesoltys.seedvault.getRandomString
|
||||||
import com.stevesoltys.seedvault.header.MAX_KEY_LENGTH_SIZE
|
import com.stevesoltys.seedvault.header.MAX_KEY_LENGTH_SIZE
|
||||||
import com.stevesoltys.seedvault.header.VersionHeader
|
import com.stevesoltys.seedvault.header.VersionHeader
|
||||||
|
import com.stevesoltys.seedvault.ui.notification.BackupNotificationManager
|
||||||
import io.mockk.Runs
|
import io.mockk.Runs
|
||||||
import io.mockk.coEvery
|
import io.mockk.coEvery
|
||||||
import io.mockk.every
|
import io.mockk.every
|
||||||
|
@ -150,6 +151,17 @@ internal class KVBackupTest : BackupTest() {
|
||||||
assertFalse(backup.hasState())
|
assertFalse(backup.hasState())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `package with no new data comes back ok right away`() = runBlocking {
|
||||||
|
assertEquals(TRANSPORT_OK, backup.performBackup(packageInfo, data, FLAG_DATA_NOT_CHANGED))
|
||||||
|
assertTrue(backup.hasState())
|
||||||
|
|
||||||
|
every { plugin.packageFinished(packageInfo) } just Runs
|
||||||
|
|
||||||
|
assertEquals(TRANSPORT_OK, backup.finishBackup())
|
||||||
|
assertFalse(backup.hasState())
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `exception while reading next header`() = runBlocking {
|
fun `exception while reading next header`() = runBlocking {
|
||||||
initPlugin(false)
|
initPlugin(false)
|
||||||
|
|
Loading…
Reference in a new issue