From 7401ead553cded3432b91c966ebb027597a20988 Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Mon, 19 Oct 2020 15:44:36 -0300 Subject: [PATCH] Request backoff when asked to backup to network storage while no internet available K/V backups are normally only attempted when charging and having an (un-metered) internet connection. However, if the system could not do a backup for more than a day, it ignores these requirements and still attempts a backup run. If a backup storage is used that is only accessible on the internet, but there is no internet connection, the backup attempt will fail. Therefore, we check if our storage requires the internet and if so, we treat it similar to a removable storage, by rejecting backup attempts and suppressing error notifications. --- README.md | 3 +- app/src/main/AndroidManifest.xml | 3 ++ .../seedvault/settings/SettingsManager.kt | 8 +++-- .../transport/backup/BackupCoordinator.kt | 35 ++++++++++++------- .../ui/storage/StorageRootFetcher.kt | 10 ++++-- .../seedvault/ui/storage/StorageViewModel.kt | 2 +- .../transport/backup/BackupCoordinatorTest.kt | 2 +- 7 files changed, 44 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 2ce6cad4..4dd2ad78 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,8 @@ It uses the same internal APIs as `adb backup` which is deprecated and thus need ## Permissions * `android.permission.BACKUP` to back up application data. -* `android.permission.MANAGE_DOCUMENTS` to retrieve the available storage roots. +* `android.permission.ACCESS_NETWORK_STATE` to check if there is internet access when network storage is used. +* `android.permission.MANAGE_DOCUMENTS` to retrieve the available storage roots. * `android.permission.MANAGE_USB` to access the serial number of USB mass storage devices. * `android.permission.WRITE_SECURE_SETTINGS` to change system backup settings and enable call log backup. * `android.permission.QUERY_ALL_PACKAGES` to get information about all installed apps for backup. diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 2cb592db..71c760ca 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -9,6 +9,9 @@ android:name="android.permission.BACKUP" tools:ignore="ProtectedPermissions" /> + + + Unit)? = null ) { @@ -144,10 +146,11 @@ internal class StorageRootFetcher(private val context: Context, private val isRe if (!supportsCreate || !supportsIsChild) return null val rootId = cursor.getString(COLUMN_ROOT_ID)!! if (authority == AUTHORITY_STORAGE && rootId == ROOT_ID_HOME) return null + val documentId = cursor.getString(COLUMN_DOCUMENT_ID) ?: return null return StorageRoot( authority = authority, rootId = rootId, - documentId = cursor.getString(COLUMN_DOCUMENT_ID)!!, + documentId = documentId, icon = getIcon(context, authority, rootId, cursor.getInt(COLUMN_ICON)), title = cursor.getString(COLUMN_TITLE)!!, summary = cursor.getString(COLUMN_SUMMARY), @@ -155,7 +158,8 @@ internal class StorageRootFetcher(private val context: Context, private val isRe // AOSP 11 reports -1 instead of null if (bytes == -1L) null else bytes }, - isUsb = flags and FLAG_REMOVABLE_USB != 0 + isUsb = flags and FLAG_REMOVABLE_USB != 0, + requiresNetwork = flags and FLAG_LOCAL_ONLY == 0 // not local only == requires network ) } @@ -175,6 +179,7 @@ internal class StorageRootFetcher(private val context: Context, private val isRe summary = context.getString(R.string.storage_fake_drive_summary), availableBytes = null, isUsb = true, + requiresNetwork = false, enabled = false ) roots.add(root) @@ -216,6 +221,7 @@ internal class StorageRootFetcher(private val context: Context, private val isRe summary = context.getString(summaryRes), availableBytes = null, isUsb = false, + requiresNetwork = true, enabled = !isInstalled || isRestore, overrideClickListener = { if (isInstalled) context.startActivity(intent) diff --git a/app/src/main/java/com/stevesoltys/seedvault/ui/storage/StorageViewModel.kt b/app/src/main/java/com/stevesoltys/seedvault/ui/storage/StorageViewModel.kt index 72047d7c..e5e48b01 100644 --- a/app/src/main/java/com/stevesoltys/seedvault/ui/storage/StorageViewModel.kt +++ b/app/src/main/java/com/stevesoltys/seedvault/ui/storage/StorageViewModel.kt @@ -101,7 +101,7 @@ internal abstract class StorageViewModel( } else { root.title } - val storage = Storage(uri, name, root.isUsb) + val storage = Storage(uri, name, root.isUsb, root.requiresNetwork) settingsManager.setStorage(storage) if (storage.isUsb) { 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 03967e66..f9d6a549 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 @@ -63,7 +63,7 @@ internal class BackupCoordinatorTest : BackupTest() { private val metadataOutputStream = mockk() private val fileDescriptor: ParcelFileDescriptor = mockk() private val packageMetadata: PackageMetadata = mockk() - private val storage = Storage(Uri.EMPTY, getRandomString(), false) + private val storage = Storage(Uri.EMPTY, getRandomString(), false, false) @Test fun `starting a new restore set works as expected`() = runBlocking {