Skip to content

Commit

Permalink
Closes mozilla-mobile#7450: Lazy storage initialization
Browse files Browse the repository at this point in the history
Make sure that we actually lazily initialize our storage layers.

With this patch applied, storage layers (history, logins, bookmarks) will be initialized when first
accessed. We will no longer block GeckoEngine init, for example, on waiting for the logins storage
to initialize (which needs to access the costly securePrefStorage).
Similarly, BackgroundServices init will no longer require initialized instances of the storage
components - references to their "lazy wrappers" will suffice.

In practice, this change changes when our storage layers are initialized in the following ways.
Currently, we will initialize everything on startup. This includes loading our megazord, as well.

With this change, init path depends on if the user is signed-into FxA or not.

If user is not an FxA user:
- on startup, none of the storage layers are initialized
- history storage will be initialized once, whenever:
  - first non-customTab page is loaded (access to the HistoryDelegate)
  - first interaction with the awesomebar
  - history UI is accessed
- bookmarks storage will be initialized once, whenever:
  - something is bookmarked, or we need to figure out if something's bookmarked
  - bookmarks UI is accessed
- logins storage will be initialized once, whenever:
  - first page is loaded with a login/password fields that can be autofilled
  - (or some other interaction by GV with the autofill/loginStorage delegates)
  - logins UI is accessed
- all of these storages will be initialized if the user logs into FxA and starts syncing data
  - except, if a storage is not chosen to be synced, it will not be initialized

If user is an FxA user:
- on startup, none of the storage layers are initialized
- sometime shortly after startup is complete, when a sync worker runs in the background, all storage
layers that are enabled to sync will be initialized.

This change also means that we delay loading the megazord until first access (as described above).
  • Loading branch information
Grisha Kruglov committed Mar 18, 2020
1 parent b4e1360 commit d308742
Show file tree
Hide file tree
Showing 5 changed files with 37 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import mozilla.components.concept.storage.LoginsStorage
import mozilla.components.lib.crash.handler.CrashHandlerService
import mozilla.components.service.experiments.Experiments
import mozilla.components.service.sync.logins.GeckoLoginStorageDelegate
import mozilla.components.support.base.log.logger.Logger
import org.mozilla.fenix.Config
import org.mozilla.fenix.ext.settings
import org.mozilla.fenix.utils.Settings
Expand All @@ -23,7 +24,7 @@ object GeckoProvider {
@Synchronized
fun getOrCreateRuntime(
context: Context,
storage: LoginsStorage
storage: Lazy<LoginsStorage>
): GeckoRuntime {
if (runtime == null) {
runtime = createRuntime(context, storage)
Expand All @@ -34,7 +35,7 @@ object GeckoProvider {

private fun createRuntime(
context: Context,
storage: LoginsStorage
storage: Lazy<LoginsStorage>
): GeckoRuntime {
val builder = GeckoRuntimeSettings.Builder()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,7 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Session
customTabId = customTabSessionId,
fragmentManager = parentFragmentManager,
loginValidationDelegate = DefaultLoginValidationDelegate(
context.components.core.passwordsStorage
context.components.core.lazyPasswordsStorage
),
isSaveLoginEnabled = {
context.settings().shouldPromptToSaveLogins
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,9 @@ class BackgroundServices(
private val context: Context,
private val push: Push,
crashReporter: CrashReporter,
historyStorage: PlacesHistoryStorage,
bookmarkStorage: PlacesBookmarksStorage,
passwordsStorage: SyncableLoginsStorage
historyStorage: Lazy<PlacesHistoryStorage>,
bookmarkStorage: Lazy<PlacesBookmarksStorage>,
passwordsStorage: Lazy<SyncableLoginsStorage>
) {
fun defaultDeviceName(context: Context): String =
context.getString(
Expand Down
6 changes: 3 additions & 3 deletions app/src/main/java/org/mozilla/fenix/components/Components.kt
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ class Components(private val context: Context) {
context,
push,
analytics.crashReporter,
core.historyStorage,
core.bookmarksStorage,
core.passwordsStorage
core.lazyHistoryStorage,
core.lazyBookmarksStorage,
core.lazyPasswordsStorage
)
}
val services by lazy { Services(context, backgroundServices.accountManager) }
Expand Down
38 changes: 27 additions & 11 deletions app/src/main/java/org/mozilla/fenix/components/Core.kt
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import mozilla.components.feature.webnotifications.WebNotificationFeature
import mozilla.components.lib.dataprotect.SecureAbove22Preferences
import mozilla.components.lib.dataprotect.generateEncryptionKey
import mozilla.components.service.sync.logins.SyncableLoginsStorage
import mozilla.components.support.base.log.logger.Logger
import org.mozilla.fenix.AppRequestInterceptor
import org.mozilla.fenix.Config
import org.mozilla.fenix.FeatureFlags
Expand All @@ -52,6 +53,8 @@ import java.util.concurrent.TimeUnit
*/
@Mockable
class Core(private val context: Context) {
private val logger = Logger("Core")

/**
* The browser engine component initialized based on the build
* configuration (see build variants).
Expand All @@ -62,7 +65,7 @@ class Core(private val context: Context) {
remoteDebuggingEnabled = context.settings().isRemoteDebuggingEnabled,
testingModeEnabled = false,
trackingProtectionPolicy = trackingProtectionPolicyFactory.createTrackingProtectionPolicy(),
historyTrackingDelegate = HistoryDelegate(historyStorage),
historyTrackingDelegate = HistoryDelegate(lazyHistoryStorage),
preferredColorScheme = getPreferredColorScheme(),
automaticFontSizeAdjustment = context.settings().shouldUseAutoSize,
fontInflationEnabled = context.settings().shouldUseAutoSize,
Expand All @@ -73,7 +76,7 @@ class Core(private val context: Context) {
GeckoEngine(
context,
defaultSettings,
GeckoProvider.getOrCreateRuntime(context, passwordsStorage)
GeckoProvider.getOrCreateRuntime(context, lazyPasswordsStorage)
).also {
WebCompatFeature.install(it)
}
Expand All @@ -85,7 +88,7 @@ class Core(private val context: Context) {
val client: Client by lazy {
GeckoViewFetchClient(
context,
GeckoProvider.getOrCreateRuntime(context, passwordsStorage)
GeckoProvider.getOrCreateRuntime(context, lazyPasswordsStorage)
)
}

Expand Down Expand Up @@ -184,15 +187,28 @@ class Core(private val context: Context) {
)
}

/**
* The storage component to persist browsing history (with the exception of
* private sessions).
*/
val historyStorage by lazy { PlacesHistoryStorage(context) }

val bookmarksStorage by lazy { PlacesBookmarksStorage(context) }
// Lazy wrappers around storage components are used to pass references to these components without
// initializing them until they're accessed.
// Use these for startup-path code, where we don't want to do any work that's not strictly necessary.
// For example, this is how the GeckoEngine delegates (history, logins) are configured.
// We can fully initialize GeckoEngine without initialized our storage.
val lazyHistoryStorage = lazy {
logger.info("Initializing history storage")
PlacesHistoryStorage(context)
}
val lazyBookmarksStorage = lazy {
logger.info("Initializing bookmarks storage")
PlacesBookmarksStorage(context)
}
val lazyPasswordsStorage = lazy {
logger.info("Initializing logins storage")
SyncableLoginsStorage(context, passwordsEncryptionKey)
}

val passwordsStorage by lazy { SyncableLoginsStorage(context, passwordsEncryptionKey) }
// For most other application code (non-startup), these wrappers are perfectly fine and more ergonomic.
val historyStorage by lazy { lazyHistoryStorage.value }
val bookmarksStorage by lazy { lazyBookmarksStorage.value }
val passwordsStorage by lazy { lazyPasswordsStorage.value }

val tabCollectionStorage by lazy { TabCollectionStorage(context, sessionManager) }

Expand Down

0 comments on commit d308742

Please sign in to comment.