1
0
Fork 0

Fix #1032: Crash altering sessions DB on main thread

master
Colin Lee 2019-03-15 11:26:07 -05:00 committed by Jeff Boek
parent 9255962219
commit 6e1655e935
4 changed files with 60 additions and 23 deletions

View File

@ -0,0 +1,23 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.fenix.ext
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import mozilla.components.browser.session.SessionManager
import mozilla.components.feature.session.bundling.SessionBundleStorage
suspend fun SessionBundleStorage.archive(sessionManager: SessionManager) {
withContext(Dispatchers.IO) {
save(sessionManager.createSnapshot())
launch(Dispatchers.Main) {
sessionManager.sessions.filter { !it.private }.forEach {
sessionManager.remove(it)
}
}
new()
}
}

View File

@ -21,15 +21,20 @@ import androidx.lifecycle.Observer
import androidx.navigation.Navigation import androidx.navigation.Navigation
import kotlinx.android.synthetic.main.fragment_home.* import kotlinx.android.synthetic.main.fragment_home.*
import kotlinx.android.synthetic.main.fragment_home.view.* import kotlinx.android.synthetic.main.fragment_home.view.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import mozilla.components.browser.menu.BrowserMenu import mozilla.components.browser.menu.BrowserMenu
import mozilla.components.browser.session.Session import mozilla.components.browser.session.Session
import mozilla.components.browser.session.SessionManager import mozilla.components.browser.session.SessionManager
import mozilla.components.feature.session.bundling.SessionBundleStorage import org.mozilla.fenix.BrowserDirection
import org.mozilla.fenix.BrowsingModeManager import org.mozilla.fenix.BrowsingModeManager
import org.mozilla.fenix.DefaultThemeManager import org.mozilla.fenix.DefaultThemeManager
import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.BrowserDirection
import org.mozilla.fenix.R import org.mozilla.fenix.R
import org.mozilla.fenix.ext.archive
import org.mozilla.fenix.ext.requireComponents import org.mozilla.fenix.ext.requireComponents
import org.mozilla.fenix.home.sessions.ArchivedSession import org.mozilla.fenix.home.sessions.ArchivedSession
import org.mozilla.fenix.home.sessions.SessionsAction import org.mozilla.fenix.home.sessions.SessionsAction
@ -44,30 +49,27 @@ import org.mozilla.fenix.mvi.ActionBusFactory
import org.mozilla.fenix.mvi.getAutoDisposeObservable import org.mozilla.fenix.mvi.getAutoDisposeObservable
import org.mozilla.fenix.mvi.getManagedEmitter import org.mozilla.fenix.mvi.getManagedEmitter
import org.mozilla.fenix.settings.SupportUtils import org.mozilla.fenix.settings.SupportUtils
import org.mozilla.fenix.utils.Settings import kotlin.coroutines.CoroutineContext
import kotlin.math.roundToInt import kotlin.math.roundToInt
fun SessionBundleStorage.archive(sessionManager: SessionManager) {
save(sessionManager.createSnapshot())
sessionManager.sessions.filter { !it.private }.forEach {
sessionManager.remove(it)
}
new()
}
@SuppressWarnings("TooManyFunctions") @SuppressWarnings("TooManyFunctions")
class HomeFragment : Fragment() { class HomeFragment : Fragment(), CoroutineScope {
private val bus = ActionBusFactory.get(this) private val bus = ActionBusFactory.get(this)
private var sessionObserver: SessionManager.Observer? = null private var sessionObserver: SessionManager.Observer? = null
private var homeMenu: HomeMenu? = null private var homeMenu: HomeMenu? = null
private lateinit var tabsComponent: TabsComponent private lateinit var tabsComponent: TabsComponent
private lateinit var sessionsComponent: SessionsComponent private lateinit var sessionsComponent: SessionsComponent
private lateinit var job: Job
override val coroutineContext: CoroutineContext
get() = Dispatchers.Main + job
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, inflater: LayoutInflater,
container: ViewGroup?, container: ViewGroup?,
savedInstanceState: Bundle? savedInstanceState: Bundle?
): View? { ): View? {
job = Job()
val view = inflater.inflate(R.layout.fragment_home, container, false) val view = inflater.inflate(R.layout.fragment_home, container, false)
val sessionManager = requireComponents.core.sessionManager val sessionManager = requireComponents.core.sessionManager
tabsComponent = TabsComponent( tabsComponent = TabsComponent(
@ -174,8 +176,9 @@ class HomeFragment : Fragment() {
} }
override fun onDestroyView() { override fun onDestroyView() {
super.onDestroyView()
homeMenu = null homeMenu = null
job.cancel()
super.onDestroyView()
} }
override fun onResume() { override fun onResume() {
@ -191,7 +194,9 @@ class HomeFragment : Fragment() {
.subscribe { .subscribe {
when (it) { when (it) {
is TabsAction.Archive -> { is TabsAction.Archive -> {
requireComponents.core.sessionStorage.archive(requireComponents.core.sessionManager) launch {
requireComponents.core.sessionStorage.archive(requireComponents.core.sessionManager)
}
} }
is TabsAction.MenuTapped -> { is TabsAction.MenuTapped -> {
val isPrivate = (activity as HomeActivity).browsingModeManager.isPrivate val isPrivate = (activity as HomeActivity).browsingModeManager.isPrivate
@ -228,14 +233,18 @@ class HomeFragment : Fragment() {
.subscribe { .subscribe {
when (it) { when (it) {
is SessionsAction.Select -> { is SessionsAction.Select -> {
requireComponents.core.sessionStorage.archive(requireComponents.core.sessionManager) launch {
requireComponents.core.sessionStorage.archive(requireComponents.core.sessionManager)
}
it.archivedSession.bundle.restoreSnapshot()?.apply { it.archivedSession.bundle.restoreSnapshot()?.apply {
requireComponents.core.sessionManager.restore(this) requireComponents.core.sessionManager.restore(this)
homeScrollView.smoothScrollTo(0, 0) homeScrollView.smoothScrollTo(0, 0)
} }
} }
is SessionsAction.Delete -> { is SessionsAction.Delete -> {
requireComponents.core.sessionStorage.remove(it.archivedSession.bundle) launch(IO) {
requireComponents.core.sessionStorage.remove(it.archivedSession.bundle)
}
} }
is SessionsAction.MenuTapped -> is SessionsAction.MenuTapped ->
openSessionMenu(SessionBottomSheetFragment.SessionType.Archived(it.archivedSession)) openSessionMenu(SessionBottomSheetFragment.SessionType.Archived(it.archivedSession))
@ -358,17 +367,23 @@ class HomeFragment : Fragment() {
private fun openSessionMenu(sessionType: SessionBottomSheetFragment.SessionType) { private fun openSessionMenu(sessionType: SessionBottomSheetFragment.SessionType) {
SessionBottomSheetFragment.create(sessionType).apply { SessionBottomSheetFragment.create(sessionType).apply {
onArchive = { onArchive = {
requireComponents.core.sessionStorage.archive(requireComponents.core.sessionManager) launch {
requireComponents.core.sessionStorage.archive(requireComponents.core.sessionManager)
}
} }
onDelete = { onDelete = {
when (it) { when (it) {
is SessionBottomSheetFragment.SessionType.Archived -> { is SessionBottomSheetFragment.SessionType.Archived -> {
requireComponents.core.sessionStorage.remove(it.archivedSession.bundle) launch(IO) {
requireComponents.core.sessionStorage.remove(it.archivedSession.bundle)
}
} }
is SessionBottomSheetFragment.SessionType.Current -> { is SessionBottomSheetFragment.SessionType.Current -> {
requireComponents.useCases.tabsUseCases.removeAllTabsOfType.invoke(false) requireComponents.useCases.tabsUseCases.removeAllTabsOfType.invoke(false)
requireComponents.core.sessionStorage.current()?.apply { launch(IO) {
requireComponents.core.sessionStorage.remove(this) requireComponents.core.sessionStorage.current()?.apply {
requireComponents.core.sessionStorage.remove(this)
}
} }
} }
is SessionBottomSheetFragment.SessionType.Private -> { is SessionBottomSheetFragment.SessionType.Private -> {

View File

@ -68,5 +68,5 @@ task ktlint(type: JavaExec, group: "verification") {
description = "Check Kotlin code style." description = "Check Kotlin code style."
classpath = configurations.ktlint classpath = configurations.ktlint
main = "com.github.shyiko.ktlint.Main" main = "com.github.shyiko.ktlint.Main"
args "app/**/*.kt", "architecture/**/*.kt" args "app/src/**/*.kt", "architecture/src/**/*.kt"
} }

View File

@ -46,7 +46,7 @@ object Deps {
const val tools_appservicesgradle = "org.mozilla.appservices:gradle-plugin:${Versions.appservices_gradle_plugin}" const val tools_appservicesgradle = "org.mozilla.appservices:gradle-plugin:${Versions.appservices_gradle_plugin}"
const val kotlin_stdlib = "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${Versions.kotlin}" const val kotlin_stdlib = "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${Versions.kotlin}"
const val allopen = "org.jetbrains.kotlin:kotlin-allopen:${Versions.kotlin}" const val allopen = "org.jetbrains.kotlin:kotlin-allopen:${Versions.kotlin}"
const val rxKotlin = "io.reactivex.rxjava2:rxkotlin:${Versions.rxKotlin}" const val rxKotlin = "io.reactivex.rxjava2:rxkotlin:${Versions.rxKotlin}"
const val rxAndroid = "io.reactivex.rxjava2:rxandroid:${Versions.rxAndroid}" const val rxAndroid = "io.reactivex.rxjava2:rxandroid:${Versions.rxAndroid}"
@ -147,4 +147,3 @@ object Deps {
const val glide = "com.github.bumptech.glide:glide:${Versions.glide}" const val glide = "com.github.bumptech.glide:glide:${Versions.glide}"
const val glideAnnotationProcessor = "com.github.bumptech.glide:compiler:${Versions.glide}" const val glideAnnotationProcessor = "com.github.bumptech.glide:compiler:${Versions.glide}"
} }