Fix or permit certain disk reads on UI thread

This commit is contained in:
Torsten Grote 2020-10-05 11:55:50 -03:00 committed by Chirayu Desai
parent 1d2c74bf2c
commit 0612f79195
6 changed files with 46 additions and 8 deletions

View file

@ -79,7 +79,9 @@ class App : Application() {
.build() .build()
) )
} }
migrateTokenFromMetadataToSettingsManager() permitDiskReads {
migrateTokenFromMetadataToSettingsManager()
}
} }
private val settingsManager: SettingsManager by inject() private val settingsManager: SettingsManager by inject()
@ -106,3 +108,21 @@ const val ANCESTRAL_RECORD_KEY = "@ancestral_record@"
const val GLOBAL_METADATA_KEY = "@meta@" const val GLOBAL_METADATA_KEY = "@meta@"
fun isDebugBuild() = Build.TYPE == "userdebug" fun isDebugBuild() = Build.TYPE == "userdebug"
fun <T> 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()
}
}

View file

@ -26,6 +26,7 @@ import androidx.preference.TwoStatePreference
import com.stevesoltys.seedvault.R import com.stevesoltys.seedvault.R
import com.stevesoltys.seedvault.UsbMonitor import com.stevesoltys.seedvault.UsbMonitor
import com.stevesoltys.seedvault.isMassStorage import com.stevesoltys.seedvault.isMassStorage
import com.stevesoltys.seedvault.permitDiskReads
import com.stevesoltys.seedvault.restore.RestoreActivity import com.stevesoltys.seedvault.restore.RestoreActivity
import com.stevesoltys.seedvault.ui.toRelativeTime import com.stevesoltys.seedvault.ui.toRelativeTime
import org.koin.android.ext.android.inject import org.koin.android.ext.android.inject
@ -67,7 +68,9 @@ class SettingsFragment : PreferenceFragmentCompat() {
} }
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.settings, rootKey) permitDiskReads {
setPreferencesFromResource(R.xml.settings, rootKey)
}
setHasOptionsMenu(true) setHasOptionsMenu(true)
backup = findPreference("backup")!! backup = findPreference("backup")!!

View file

@ -6,6 +6,7 @@ import android.net.Uri
import androidx.annotation.UiThread import androidx.annotation.UiThread
import androidx.documentfile.provider.DocumentFile import androidx.documentfile.provider.DocumentFile
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import com.stevesoltys.seedvault.permitDiskReads
import com.stevesoltys.seedvault.transport.backup.BackupCoordinator import com.stevesoltys.seedvault.transport.backup.BackupCoordinator
import java.util.concurrent.ConcurrentSkipListSet import java.util.concurrent.ConcurrentSkipListSet
@ -25,7 +26,9 @@ private const val PREF_KEY_BACKUP_APP_BLACKLIST = "backupAppBlacklist"
class SettingsManager(context: Context) { class SettingsManager(context: Context) {
private val prefs = PreferenceManager.getDefaultSharedPreferences(context) private val prefs = permitDiskReads {
PreferenceManager.getDefaultSharedPreferences(context)
}
@Volatile @Volatile
private var token: Long? = null private var token: Long? = null

View file

@ -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.QUOTA_EXCEEDED
import com.stevesoltys.seedvault.metadata.PackageState.UNKNOWN_ERROR import com.stevesoltys.seedvault.metadata.PackageState.UNKNOWN_ERROR
import com.stevesoltys.seedvault.metadata.PackageState.WAS_STOPPED 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
import com.stevesoltys.seedvault.restore.AppRestoreStatus.FAILED_NOT_ALLOWED import com.stevesoltys.seedvault.restore.AppRestoreStatus.FAILED_NOT_ALLOWED
import com.stevesoltys.seedvault.restore.AppRestoreStatus.FAILED_NO_DATA 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.RequireProvisioningViewModel
import com.stevesoltys.seedvault.ui.notification.BackupNotificationManager import com.stevesoltys.seedvault.ui.notification.BackupNotificationManager
import com.stevesoltys.seedvault.ui.notification.getAppName import com.stevesoltys.seedvault.ui.notification.getAppName
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import java.util.Locale import java.util.Locale
@ -67,7 +67,11 @@ internal class SettingsViewModel(
internal val appEditMode: LiveData<Boolean> = mAppEditMode internal val appEditMode: LiveData<Boolean> = mAppEditMode
init { 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 // ensures the lastBackupTime LiveData gets set
metadataManager.getLastBackupTime() metadataManager.getLastBackupTime()
} }

View file

@ -19,9 +19,12 @@ import android.content.pm.PackageManager
import android.util.Log import android.util.Log
import com.stevesoltys.seedvault.transport.restore.ApkRestoreStatus.FAILED import com.stevesoltys.seedvault.transport.restore.ApkRestoreStatus.FAILED
import com.stevesoltys.seedvault.transport.restore.ApkRestoreStatus.SUCCEEDED import com.stevesoltys.seedvault.transport.restore.ApkRestoreStatus.SUCCEEDED
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.callbackFlow import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.launch
import java.io.File import java.io.File
import java.io.IOException 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") Log.d(TAG, "Received result for $packageName: success=$success $statusMsg")
// delete cached APK file // delete cached APK file on I/O thread
cachedApk.delete() GlobalScope.launch(Dispatchers.IO) {
cachedApk.delete()
}
// update status and offer result // update status and offer result
val status = if (success) SUCCEEDED else FAILED val status = if (success) SUCCEEDED else FAILED

View file

@ -13,6 +13,7 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import com.stevesoltys.seedvault.R import com.stevesoltys.seedvault.R
import com.stevesoltys.seedvault.isMassStorage import com.stevesoltys.seedvault.isMassStorage
import com.stevesoltys.seedvault.permitDiskReads
import com.stevesoltys.seedvault.settings.BackupManagerSettings import com.stevesoltys.seedvault.settings.BackupManagerSettings
import com.stevesoltys.seedvault.settings.FlashDrive import com.stevesoltys.seedvault.settings.FlashDrive
import com.stevesoltys.seedvault.settings.SettingsManager import com.stevesoltys.seedvault.settings.SettingsManager
@ -49,7 +50,9 @@ internal abstract class StorageViewModel(
): Boolean { ): Boolean {
val storage = settingsManager.getStorage() ?: return false val storage = settingsManager.getStorage() ?: return false
if (storage.isUsb) return true if (storage.isUsb) return true
return storage.getDocumentFile(context).isDirectory return permitDiskReads {
storage.getDocumentFile(context).isDirectory
}
} }
} }