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
|
||||
|
||||
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_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_PACKAGE_REJECTED
|
||||
import android.app.backup.BackupTransport.TRANSPORT_QUOTA_EXCEEDED
|
||||
|
@ -163,6 +169,42 @@ internal class BackupCoordinator(
|
|||
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(
|
||||
packageInfo: PackageInfo,
|
||||
data: ParcelFileDescriptor,
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
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.TRANSPORT_ERROR
|
||||
|
@ -8,12 +9,12 @@ import android.app.backup.BackupTransport.TRANSPORT_OK
|
|||
import android.content.pm.PackageInfo
|
||||
import android.os.ParcelFileDescriptor
|
||||
import android.util.Log
|
||||
import com.stevesoltys.seedvault.ui.notification.BackupNotificationManager
|
||||
import com.stevesoltys.seedvault.MAGIC_PACKAGE_MANAGER
|
||||
import com.stevesoltys.seedvault.crypto.Crypto
|
||||
import com.stevesoltys.seedvault.encodeBase64
|
||||
import com.stevesoltys.seedvault.header.HeaderWriter
|
||||
import com.stevesoltys.seedvault.header.VersionHeader
|
||||
import com.stevesoltys.seedvault.ui.notification.BackupNotificationManager
|
||||
import libcore.io.IoUtils.closeQuietly
|
||||
import java.io.IOException
|
||||
|
||||
|
@ -45,11 +46,15 @@ internal class KVBackup(
|
|||
data: ParcelFileDescriptor,
|
||||
flags: Int
|
||||
): Int {
|
||||
val dataNotChanged = flags and FLAG_DATA_NOT_CHANGED != 0
|
||||
val isIncremental = flags and FLAG_INCREMENTAL != 0
|
||||
val isNonIncremental = flags and FLAG_NON_INCREMENTAL != 0
|
||||
val packageName = packageInfo.packageName
|
||||
|
||||
when {
|
||||
dataNotChanged -> {
|
||||
Log.i(TAG, "No K/V backup data has changed for $packageName")
|
||||
}
|
||||
isIncremental -> {
|
||||
Log.i(TAG, "Performing incremental K/V backup for $packageName")
|
||||
}
|
||||
|
@ -65,6 +70,9 @@ internal class KVBackup(
|
|||
if (this.state != null) throw AssertionError()
|
||||
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
|
||||
val hasDataForPackage = try {
|
||||
plugin.hasDataForPackage(packageInfo)
|
||||
|
|
|
@ -1,17 +1,18 @@
|
|||
package com.stevesoltys.seedvault.transport.backup
|
||||
|
||||
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_NON_INCREMENTAL
|
||||
import android.app.backup.BackupTransport.TRANSPORT_ERROR
|
||||
import android.app.backup.BackupTransport.TRANSPORT_NON_INCREMENTAL_BACKUP_REQUIRED
|
||||
import android.app.backup.BackupTransport.TRANSPORT_OK
|
||||
import android.content.pm.PackageInfo
|
||||
import com.stevesoltys.seedvault.ui.notification.BackupNotificationManager
|
||||
import com.stevesoltys.seedvault.Utf8
|
||||
import com.stevesoltys.seedvault.getRandomString
|
||||
import com.stevesoltys.seedvault.header.MAX_KEY_LENGTH_SIZE
|
||||
import com.stevesoltys.seedvault.header.VersionHeader
|
||||
import com.stevesoltys.seedvault.ui.notification.BackupNotificationManager
|
||||
import io.mockk.Runs
|
||||
import io.mockk.coEvery
|
||||
import io.mockk.every
|
||||
|
@ -150,6 +151,17 @@ internal class KVBackupTest : BackupTest() {
|
|||
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
|
||||
fun `exception while reading next header`() = runBlocking {
|
||||
initPlugin(false)
|
||||
|
|
Loading…
Reference in a new issue