To help diagnosing further issues with the Settings API getting blocked,
we add some tracking of the tasks and locks queue vivacity. We ensure to
keep track of the last lock id at the head of the queue, and we verify
whether it does not stays on top of it for too long.
Whenever a settings lock does only read operations (i.e. lock.get()),
there is no need that the underlying indexedDB transaction should be
opened as readwrite. Doing so, we will be able to parallelize some
request and avoid locking that should in the end allow for faster
operations. Enabling this feature is controlled by the preference
dom.mozSettings.allowForceReadOnly, defaulting to false for now.
We want to have a better breakdown of how many get/set operations we are
doing for each setting lock. Given that we keep track of all locks, this
may consume quite some memory, so we introduce a new preference to
enable this feature. We also add memory reporting for the SettingService
lock.
While I was debugging bug 1105511, khuey noticed that one case was
missing a removeLock call. We should add it; it seems like if we ever
hit this error case, the settings lock queue would get stuck. It's not
clear whether this is actually the cause of bug 1105511, so I'm putting
it in a separate bug.
We break down the logging capabilities into two classes: debug and
verbose. Verbose will help to track everything that happens, while debug
should just report error cases. We also augment memory reports with
values to help tracking potential issues like: queue blockage, leaking,
etc.
Service locks for settings are locks created from chrome code and not
attached to any window. Since the windowID is used in other cases for
the Settings:CreateLock message, we should at least pass an undefined
value to avoid unneccessary JS warning.
From bug 1065128 SettingsManager has been changed to listen the
dom-window-destroyed event for its cleanup. However, when running Gaia
in Mulet, a race condition is exposed. For B2G, when loading a page,
about:blank is first used. This means that window destroyed events will
be triggered. However, from the dom-window-destroyed event we cannot
distinguish whether this is about:blank or a legit application being
closed. SettingsManager gets initialized (i.e., init() called) when the
application makes use of navigator.mozSettings. So the chain of event is
that we have a SettingsManager living because System app did some
request. At this time, about:blank is being unloaded and triggers a
dom-window-destroyed event. This makes SettingsManager doing its
cleanup, especially freeing the window reference. Then in the meantime,
we have the navigator.mozSettings use that is progressing. At some
point, SettingsManager has no more window to send messages to, and Gaia
is not able to even start.
SettingsRequestManager lives on the parent process and SettingsManager
lives on the child side. Part of the cleanup performed by
SettingsManager was to ensure pending locks on the parent process would
be forced to finalize to make sure those are being properly committed.
We move this cleanup to SettingsRequestManager and we augment the lock
informations with the proper inner window id. This way we can track
which lock is attached to which inner window when the lock gets created.
And thus we can listen on inner-window-destroyed from
SettingsRequestManager to be able to force finalize on any pending lock.
Impacted code path are those were we are not running out of process.
When we are running out of process, SettingsRequestManager already
listens on the child-process-shutdown event to perform the lock
finalization.
When child message manager dies, it sends a child-process-shutdown
message to the SettingsRequestManager. This would just close the locks
and tasks of this message manager. The race happens when some
applications can shutdown quickly: settings requests will never be
committed to the database. One example is the callscreen. The fix,
provided by qDot, simply put those tasks in a finalize state to make
sure they are properly executed and committed.