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()
)
}
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 <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.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")!!

View file

@ -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

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.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<Boolean> = 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()
}

View file

@ -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

View file

@ -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
}
}
}