Tolerate unexpected exceptions in DocumentsStorage and ApkRestore
diff --git a/app/src/main/java/com/stevesoltys/seedvault/plugins/saf/DocumentsStorage.kt b/app/src/main/java/com/stevesoltys/seedvault/plugins/saf/DocumentsStorage.kt
index 7e970a7..593f494 100644
--- a/app/src/main/java/com/stevesoltys/seedvault/plugins/saf/DocumentsStorage.kt
+++ b/app/src/main/java/com/stevesoltys/seedvault/plugins/saf/DocumentsStorage.kt
@@ -134,12 +134,22 @@
 
     @Throws(IOException::class)
     fun getInputStream(file: DocumentFile): InputStream {
-        return contentResolver.openInputStream(file.uri) ?: throw IOException()
+        return try {
+            contentResolver.openInputStream(file.uri) ?: throw IOException()
+        } catch (e: Exception) {
+            // SAF can throw all sorts of exceptions, so wrap it in IOException
+            throw IOException(e)
+        }
     }
 
     @Throws(IOException::class)
     fun getOutputStream(file: DocumentFile): OutputStream {
-        return contentResolver.openOutputStream(file.uri, "wt") ?: throw IOException()
+        return try {
+            contentResolver.openOutputStream(file.uri, "wt") ?: throw IOException()
+        } catch (e: Exception) {
+            // SAF can throw all sorts of exceptions, so wrap it in IOException
+            throw IOException(e)
+        }
     }
 
 }
@@ -161,8 +171,10 @@
                 throw IOException("File named ${this.name}, but should be $name")
             }
         } ?: throw IOException()
-    } catch (e: IllegalArgumentException) {
-        // Can be thrown by FileSystemProvider#isChildDocument() when flash drive is not plugged-in
+    } catch (e: Exception) {
+        // SAF can throw all sorts of exceptions, so wrap it in IOException.
+        // E.g. IllegalArgumentException can be thrown by FileSystemProvider#isChildDocument()
+        // when flash drive is not plugged-in:
         // http://aosp.opersys.com/xref/android-11.0.0_r8/xref/frameworks/base/core/java/com/android/internal/content/FileSystemProvider.java#135
         throw IOException(e)
     }
@@ -248,7 +260,7 @@
 suspend fun DocumentFile.findFileBlocking(context: Context, displayName: String): DocumentFile? {
     val files = try {
         listFilesBlocking(context)
-    } catch (e: IOException) {
+    } catch (e: Exception) {
         Log.e(TAG, "Error finding file blocking", e)
         return null
     }
diff --git a/app/src/main/java/com/stevesoltys/seedvault/restore/install/ApkRestore.kt b/app/src/main/java/com/stevesoltys/seedvault/restore/install/ApkRestore.kt
index 59600b3..c469f00 100644
--- a/app/src/main/java/com/stevesoltys/seedvault/restore/install/ApkRestore.kt
+++ b/app/src/main/java/com/stevesoltys/seedvault/restore/install/ApkRestore.kt
@@ -76,6 +76,9 @@
             } catch (e: TimeoutCancellationException) {
                 Log.e(TAG, "Timeout while re-installing APK for $packageName.", e)
                 emit(installResult.fail(packageName))
+            } catch (e: Exception) {
+                Log.e(TAG, "Unexpected exception while re-installing APK for $packageName.", e)
+                emit(installResult.fail(packageName))
             }
         }
         installResult.isFinished = true
diff --git a/app/src/main/java/com/stevesoltys/seedvault/transport/backup/ApkBackup.kt b/app/src/main/java/com/stevesoltys/seedvault/transport/backup/ApkBackup.kt
index 1942f00..b248b8d 100644
--- a/app/src/main/java/com/stevesoltys/seedvault/transport/backup/ApkBackup.kt
+++ b/app/src/main/java/com/stevesoltys/seedvault/transport/backup/ApkBackup.kt
@@ -17,7 +17,6 @@
 import com.stevesoltys.seedvault.settings.SettingsManager
 import java.io.File
 import java.io.FileInputStream
-import java.io.FileNotFoundException
 import java.io.IOException
 import java.io.InputStream
 import java.io.OutputStream
@@ -145,10 +144,8 @@
         val apk = File(apkPath)
         return try {
             apk.inputStream()
-        } catch (e: FileNotFoundException) {
-            Log.e(TAG, "Error opening ${apk.absolutePath} for backup.", e)
-            throw IOException(e)
-        } catch (e: SecurityException) {
+        } catch (e: Exception) {
+            // SAF may throw all sorts of exceptions, so wrap them in IOException
             Log.e(TAG, "Error opening ${apk.absolutePath} for backup.", e)
             throw IOException(e)
         }