diff --git a/app/src/main/java/com/stevesoltys/seedvault/App.kt b/app/src/main/java/com/stevesoltys/seedvault/App.kt index d369d523..b9f8dff8 100644 --- a/app/src/main/java/com/stevesoltys/seedvault/App.kt +++ b/app/src/main/java/com/stevesoltys/seedvault/App.kt @@ -79,7 +79,9 @@ class App : Application() { .build() ) } - migrateTokenFromMetadataToSettingsManager() + permitDiskReads { + migrateTokenFromMetadataToSettingsManager() + } } private val settingsManager: SettingsManager by inject() @@ -106,3 +108,21 @@ const val ANCESTRAL_RECORD_KEY = "@ancestral_record@" const val GLOBAL_METADATA_KEY = "@meta@" fun isDebugBuild() = Build.TYPE == "userdebug" + +fun permitDiskReads(func: () -> T): T { + return if (isDebugBuild()) { + val oldThreadPolicy = StrictMode.getThreadPolicy() + StrictMode.setThreadPolicy( + StrictMode.ThreadPolicy.Builder(oldThreadPolicy) + .permitDiskReads() + .build() + ) + try { + func() + } finally { + StrictMode.setThreadPolicy(oldThreadPolicy) + } + } else { + func() + } +} diff --git a/app/src/main/java/com/stevesoltys/seedvault/settings/SettingsFragment.kt b/app/src/main/java/com/stevesoltys/seedvault/settings/SettingsFragment.kt index cded2c24..6fdaebb9 100644 --- a/app/src/main/java/com/stevesoltys/seedvault/settings/SettingsFragment.kt +++ b/app/src/main/java/com/stevesoltys/seedvault/settings/SettingsFragment.kt @@ -26,6 +26,7 @@ import androidx.preference.TwoStatePreference import com.stevesoltys.seedvault.R import com.stevesoltys.seedvault.UsbMonitor import com.stevesoltys.seedvault.isMassStorage +import com.stevesoltys.seedvault.permitDiskReads import com.stevesoltys.seedvault.restore.RestoreActivity import com.stevesoltys.seedvault.ui.toRelativeTime import org.koin.android.ext.android.inject @@ -67,7 +68,9 @@ class SettingsFragment : PreferenceFragmentCompat() { } override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { - setPreferencesFromResource(R.xml.settings, rootKey) + permitDiskReads { + setPreferencesFromResource(R.xml.settings, rootKey) + } setHasOptionsMenu(true) backup = findPreference("backup")!! diff --git a/app/src/main/java/com/stevesoltys/seedvault/settings/SettingsManager.kt b/app/src/main/java/com/stevesoltys/seedvault/settings/SettingsManager.kt index 2ac3cb44..92c18321 100644 --- a/app/src/main/java/com/stevesoltys/seedvault/settings/SettingsManager.kt +++ b/app/src/main/java/com/stevesoltys/seedvault/settings/SettingsManager.kt @@ -6,6 +6,7 @@ import android.net.Uri import androidx.annotation.UiThread import androidx.documentfile.provider.DocumentFile import androidx.preference.PreferenceManager +import com.stevesoltys.seedvault.permitDiskReads import com.stevesoltys.seedvault.transport.backup.BackupCoordinator import java.util.concurrent.ConcurrentSkipListSet @@ -25,7 +26,9 @@ private const val PREF_KEY_BACKUP_APP_BLACKLIST = "backupAppBlacklist" class SettingsManager(context: Context) { - private val prefs = PreferenceManager.getDefaultSharedPreferences(context) + private val prefs = permitDiskReads { + PreferenceManager.getDefaultSharedPreferences(context) + } @Volatile private var token: Long? = null diff --git a/app/src/main/java/com/stevesoltys/seedvault/settings/SettingsViewModel.kt b/app/src/main/java/com/stevesoltys/seedvault/settings/SettingsViewModel.kt index f8a8d74f..7332d2b7 100644 --- a/app/src/main/java/com/stevesoltys/seedvault/settings/SettingsViewModel.kt +++ b/app/src/main/java/com/stevesoltys/seedvault/settings/SettingsViewModel.kt @@ -24,6 +24,7 @@ import com.stevesoltys.seedvault.metadata.PackageState.NO_DATA import com.stevesoltys.seedvault.metadata.PackageState.QUOTA_EXCEEDED import com.stevesoltys.seedvault.metadata.PackageState.UNKNOWN_ERROR import com.stevesoltys.seedvault.metadata.PackageState.WAS_STOPPED +import com.stevesoltys.seedvault.permitDiskReads import com.stevesoltys.seedvault.restore.AppRestoreStatus.FAILED import com.stevesoltys.seedvault.restore.AppRestoreStatus.FAILED_NOT_ALLOWED import com.stevesoltys.seedvault.restore.AppRestoreStatus.FAILED_NO_DATA @@ -36,7 +37,6 @@ import com.stevesoltys.seedvault.transport.requestBackup import com.stevesoltys.seedvault.ui.RequireProvisioningViewModel import com.stevesoltys.seedvault.ui.notification.BackupNotificationManager import com.stevesoltys.seedvault.ui.notification.getAppName -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import java.util.Locale @@ -67,7 +67,11 @@ internal class SettingsViewModel( internal val appEditMode: LiveData = mAppEditMode init { - viewModelScope.launch(Dispatchers.IO) { + val scope = permitDiskReads { + // this shouldn't cause disk reads, but it still does + viewModelScope + } + scope.launch { // ensures the lastBackupTime LiveData gets set metadataManager.getLastBackupTime() } diff --git a/app/src/main/java/com/stevesoltys/seedvault/transport/restore/ApkInstaller.kt b/app/src/main/java/com/stevesoltys/seedvault/transport/restore/ApkInstaller.kt index ec31fd48..eaef33f5 100644 --- a/app/src/main/java/com/stevesoltys/seedvault/transport/restore/ApkInstaller.kt +++ b/app/src/main/java/com/stevesoltys/seedvault/transport/restore/ApkInstaller.kt @@ -19,9 +19,12 @@ import android.content.pm.PackageManager import android.util.Log import com.stevesoltys.seedvault.transport.restore.ApkRestoreStatus.FAILED import com.stevesoltys.seedvault.transport.restore.ApkRestoreStatus.SUCCEEDED +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.callbackFlow +import kotlinx.coroutines.launch import java.io.File import java.io.IOException @@ -101,8 +104,10 @@ internal class ApkInstaller(private val context: Context) { } Log.d(TAG, "Received result for $packageName: success=$success $statusMsg") - // delete cached APK file - cachedApk.delete() + // delete cached APK file on I/O thread + GlobalScope.launch(Dispatchers.IO) { + cachedApk.delete() + } // update status and offer result val status = if (success) SUCCEEDED else FAILED 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 ea824aa1..72047d7c 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 @@ -13,6 +13,7 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import com.stevesoltys.seedvault.R import com.stevesoltys.seedvault.isMassStorage +import com.stevesoltys.seedvault.permitDiskReads import com.stevesoltys.seedvault.settings.BackupManagerSettings import com.stevesoltys.seedvault.settings.FlashDrive import com.stevesoltys.seedvault.settings.SettingsManager @@ -49,7 +50,9 @@ internal abstract class StorageViewModel( ): Boolean { val storage = settingsManager.getStorage() ?: return false if (storage.isUsb) return true - return storage.getDocumentFile(context).isDirectory + return permitDiskReads { + storage.getDocumentFile(context).isDirectory + } } }