Closed
Bug 1462772
Opened 7 years ago
Closed 7 years ago
route ServiceWorker state changes through ServiceWorkerRegistration
Categories
(Core :: DOM: Service Workers, enhancement, P2)
Core
DOM: Service Workers
Tracking
()
RESOLVED
FIXED
mozilla63
Tracking | Status | |
---|---|---|
firefox63 | --- | fixed |
People
(Reporter: bkelly, Assigned: bkelly)
References
Details
(Whiteboard: SW-MUST)
Attachments
(5 files, 15 obsolete files)
7.44 KB,
patch
|
mrbkap
:
review+
|
Details | Diff | Splinter Review |
10.54 KB,
patch
|
mrbkap
:
review+
|
Details | Diff | Splinter Review |
9.76 KB,
patch
|
mrbkap
:
review+
|
Details | Diff | Splinter Review |
8.56 KB,
patch
|
mrbkap
:
review+
|
Details | Diff | Splinter Review |
19.90 KB,
patch
|
bkelly
:
review+
|
Details | Diff | Splinter Review |
In bug 1462467 I added some code to bring the ServiceWorkerRegistration up-to-date. That code did a simple set to the latest value. That was not quite correct. There are still some problems:
1. registration.installing.state is "parsed" instead of "installing" immediately after a register() call
2. A ServiceWorker can transition straight from "parsed" or "installing" to "activated". This is incorrect. It must transition through "installed" and "activating".
3. The registration.installing, .waiting, and .active properties jump to their final state. Instead they should transition with the ServiceWorker.state values. So when a ServiceWorker.state is "installed", then that ServiceWorker must be set as the .waiting value.
Its easy to bring the registration and service worker objects incrementally up-to-date independently. They must be synchronized, though. That is going to be hard. Its extra hard considering that the ServiceWorker object can sometimes exist without it associated registration object (e.g. MessageEvent.source).
This will probably take a while to figure out.
Assignee | ||
Comment 1•7 years ago
|
||
Maybe I can make the ServiceWorker accept state updates from the ServiceWorkerRegistration as well. Then I could have that drive the state updates when its attached to the ServiceWorkerRegistration. If its not attached to the registration then it would get updates directly from its own actor. I'll have to think about this a bit more.
Updated•7 years ago
|
Priority: -- → P2
Assignee | ||
Comment 2•7 years ago
|
||
After thinking about this over the weekend I think I've settled on the following plan:
1. Every ServiceWorker binding object that might receive a state update will hold a reference to its associated ServiceWorkerRegistration.
2. On creation the ServiceWorker will try to get the SWR from the global's cache. If its not there, then it will request a ServiceWorkerRegistrationDescriptor be provided from the inner on creation.
3. Each ServiceWorker object will add itself as a state change listener on its associated ServiceWorkerRegistration. All state changes come through the registration.
4. The ServiceWorkerManager code will keep a state change list for each registration.
5. Changes will be tracked using a 64-bit serial number.
6. All ServiceWorkerRegistrationDescriptor and ServiceWorkerDescriptor objects will include the serial number representing the version of the object used to create the descriptor.
7. On creation the binding object will receive a list of changes to bring its serial number up-to-date.
8. The change list will be pruned opportunistically to remove changes that are considered "old". Here "old" probably means anything beyond a few seconds to a minute. We really just need to handle updating state across some race condition situations. So we don't need a hugely long history.
This will be slightly sub-optimal for the case where a client receives a postMessage from a service worker it has not otherwise interacted with. This is a somewhat rare case, though. In almost all cases the ServiceWorkerRegistration will already exist.
Assignee | ||
Comment 3•7 years ago
|
||
Assignee | ||
Comment 4•7 years ago
|
||
Assignee | ||
Comment 5•7 years ago
|
||
Assignee | ||
Comment 6•7 years ago
|
||
Assignee | ||
Comment 7•7 years ago
|
||
Work in progress.
Assignee | ||
Comment 8•7 years ago
|
||
Comment on attachment 8979619 [details] [diff] [review]
P4 Make ServiceWorker objects add themselves to the ServiceWorkerRegistration as a weak point back reference. r=baku
I don't think we need this one after all.
Attachment #8979619 -
Attachment is obsolete: true
Assignee | ||
Comment 9•7 years ago
|
||
Attachment #8979748 -
Attachment is obsolete: true
Assignee | ||
Comment 10•7 years ago
|
||
Attachment #8980097 -
Attachment is obsolete: true
Assignee | ||
Comment 11•7 years ago
|
||
Assignee | ||
Comment 12•7 years ago
|
||
Assignee | ||
Comment 13•7 years ago
|
||
This seems to fix most of the problems in my local testing.
Updated•7 years ago
|
Whiteboard: SW-MUST
Assignee | ||
Comment 14•7 years ago
|
||
I'm going to make this bug just about sending ServiceWorker state changes via the registration for now. Version list and whatnot will be in a follow-on bug.
https://treeherder.mozilla.org/#/jobs?repo=try&revision=4305bb0235b49322632f5857554a32721002c067
Attachment #8980319 -
Attachment is obsolete: true
Attachment #8980321 -
Attachment is obsolete: true
Attachment #8980382 -
Attachment is obsolete: true
Attachment #8980383 -
Attachment is obsolete: true
Assignee | ||
Updated•7 years ago
|
Summary: ServiceWorker and ServiceWorkerRegistration states are not updated properly on creation with e10s pref flipped → route ServiceWorker state changes through ServiceWorkerRegistration
Assignee | ||
Comment 15•7 years ago
|
||
Assignee | ||
Comment 16•7 years ago
|
||
Attachment #8979385 -
Attachment is obsolete: true
Attachment #8979386 -
Attachment is obsolete: true
Assignee | ||
Comment 17•7 years ago
|
||
Attachment #8979388 -
Attachment is obsolete: true
Assignee | ||
Comment 18•7 years ago
|
||
Attachment #8987981 -
Attachment is obsolete: true
Assignee | ||
Comment 19•7 years ago
|
||
Assignee | ||
Updated•7 years ago
|
Assignee | ||
Comment 20•7 years ago
|
||
Attachment #8988213 -
Attachment is obsolete: true
Assignee | ||
Comment 21•7 years ago
|
||
Attachment #8988214 -
Attachment is obsolete: true
Assignee | ||
Comment 22•7 years ago
|
||
Attachment #8988215 -
Attachment is obsolete: true
Assignee | ||
Comment 23•7 years ago
|
||
Comment on attachment 8988211 [details] [diff] [review]
P1 Add a fallible nsIGlobalObject::GetServiceWorkerRegistration() method. r=mrbkap
Blake, this patch adds a method to nsIGlobalObject to get the current ServiceWorkerRegistration binding object for a given descriptor. This is very similar to the existing GetOrCreate*() method, but it simply returns nullptr if there is no object instead of creating one automatically.
Attachment #8988211 -
Flags: review?(mrbkap)
Assignee | ||
Comment 24•7 years ago
|
||
Comment on attachment 8988212 [details] [diff] [review]
P2 Add the registration Id to the ServiceWorkerDescriptor. r=mrbkap
So, every ServiceWorker in the browser must belong to some registration. This patch adds the registration's ID value to the ServiceWorkerDescriptor. This allows the ServiceWorkerDescriptor to be mapped back to the exact registration for the given principal/scope. Without the id value it would be possible to get confused and return the wrong registration if the original was removed and a new registration created for the same scope.
Attachment #8988212 -
Flags: review?(mrbkap)
Assignee | ||
Comment 25•7 years ago
|
||
Comment on attachment 8988273 [details] [diff] [review]
P3 Make ServiceWorker binding objects get or create a handle to their associated registration. r=mrbkap
This patch uses the registration id on the ServiceWorkerDescriptor to make the ServiceWorker look-up and store a reference to its corresponding ServiceWorkerRegistration. This will create a ref-cycle, but the cycle collector knows about it and will cut it if neither binding object is otherwise referenced.
I'll go into why we want this reference in the next patch.
Attachment #8988273 -
Flags: review?(mrbkap)
Assignee | ||
Comment 26•7 years ago
|
||
Comment on attachment 8988274 [details] [diff] [review]
P4 Route ServiceWorker state changes through the ServiceWorkerRegistration. r=mrbkap
This patch is the main goal of this bug. It routes all state changes for a ServiceWorker through its corresponding ServiceWorkerRegistration.
Why do we want to do this? Well, it comes down to how to maintain the state of various binding objects when different events fire.
Consider, we have these properties that can change at various points:
* ServiceWorker.state
* ServiceWorkerRegistration.installing (null or a ServiceWorker)
* ServiceWorkerRegistration.waiting (null or a ServiceWorker)
* ServiceWorkerRegistration.active (null or a ServiceWorker)
We also have these events:
* "statechange" fired by ServiceWorker
* "updatefound" fired by ServiceWorkerRegistration
The spec and WPT tests expect the properties to be in specific states when the events are fired. Today this is achievable because we keep all this information in the main thread in the same process in the SWM. We don't expose ServiceWorker in worker globals yet, so we get a pass on OMT there.
With the new IPC model, however, things get a lot harder. My initial attempt was to simply update the ServiceWorker and ServiceWorkerRegistration independently like we have done in the past. As long as we fire updates in the correct order, then this should work.
The problem, however, is that we can't fire an update to a binding object if its doesn't exist yet. And the ServiceWorkerDescriptor used to create the binding object in the child-process may be out-of-date compared to the information stored in SWM in the parent process.
To deal with the "out-of-date on attachment" issue I tried making each binding object self-update. But we cannot update these objects independently. The tests require the registration and worker objects to be updated in lockstep together.
So this patch starts to fix this problem by routing all state changes through the ServiceWorkerRegistration. The ServiceWorkerRegistration then tells each of its ServiceWorker objects about the changes. After properties have been updated events are fired.
This patch only deals with statechange events so far. A later bug will incorporate updatefound event into this system as well.
Attachment #8988274 -
Flags: review?(mrbkap)
Assignee | ||
Comment 27•7 years ago
|
||
Comment on attachment 8988276 [details] [diff] [review]
P5 Remove now-unused Listener logic in ServiceWorkerInfo. r=mrbkap
This patch just removes the now-unused code for dispatching state changes from the ServiceWorkerInfo. These now all happen through ServiceWorkerRegistrationInfo instead.
Attachment #8988276 -
Flags: review?(mrbkap)
Updated•7 years ago
|
Attachment #8988211 -
Flags: review?(mrbkap) → review+
Updated•7 years ago
|
Attachment #8988212 -
Flags: review?(mrbkap) → review+
Comment 28•7 years ago
|
||
Comment on attachment 8988273 [details] [diff] [review]
P3 Make ServiceWorker binding objects get or create a handle to their associated registration. r=mrbkap
Review of attachment 8988273 [details] [diff] [review]:
-----------------------------------------------------------------
::: dom/serviceworkers/ServiceWorker.cpp
@@ +104,5 @@
> + nsIGlobalObject* global = self->GetParentObject();
> + NS_ENSURE_TRUE_VOID(global);
> + RefPtr<ServiceWorkerRegistration> reg =
> + global->GetOrCreateServiceWorkerRegistration(aDescriptor);
> + self->MaybeAttachToRegistration(reg);
I'm a bit wary about what happens in the time between when we post this and when we call MaybeAttachToRegistration. I guess we don't need it because there can't be any other service workers to confuse us with?
Attachment #8988273 -
Flags: review?(mrbkap) → review+
Comment 29•7 years ago
|
||
Comment on attachment 8988274 [details] [diff] [review]
P4 Route ServiceWorker state changes through the ServiceWorkerRegistration. r=mrbkap
Review of attachment 8988274 [details] [diff] [review]:
-----------------------------------------------------------------
::: dom/serviceworkers/ServiceWorkerRegistration.cpp
@@ +147,5 @@
> + // to be moved to the redundant state.
> + AutoTArray<RefPtr<ServiceWorker>, 3> oldWorkerList;
> + oldWorkerList.AppendElement(mInstallingWorker.forget());
> + oldWorkerList.AppendElement(mWaitingWorker.forget());
> + oldWorkerList.AppendElement(mActiveWorker.forget());
Can we use an initializer list here? `... oldWorkerList({ mInstallingWorker.forget(), ... });`?
Attachment #8988274 -
Flags: review?(mrbkap) → review+
Updated•7 years ago
|
Attachment #8988276 -
Flags: review?(mrbkap) → review+
Assignee | ||
Comment 30•7 years ago
|
||
(In reply to Blake Kaplan (:mrbkap) from comment #28)
> ::: dom/serviceworkers/ServiceWorker.cpp
> @@ +104,5 @@
> > + nsIGlobalObject* global = self->GetParentObject();
> > + NS_ENSURE_TRUE_VOID(global);
> > + RefPtr<ServiceWorkerRegistration> reg =
> > + global->GetOrCreateServiceWorkerRegistration(aDescriptor);
> > + self->MaybeAttachToRegistration(reg);
>
> I'm a bit wary about what happens in the time between when we post this and
> when we call MaybeAttachToRegistration. I guess we don't need it because
> there can't be any other service workers to confuse us with?
There are a couple things that can happen, but I think they are all ok:
1. The global is destroyed. This is caught by the NS_ENSURE_TRUE_VOID(global).
2. The ServiceWorker object is un-referenced and could be GC'd. The lambda captured self ref will hold it alive until we set the registration. It will then be destroyed immediately after. Kind of wasteful, but not critical.
All other state changes must come through the registration. The only thing that can initiate from the ServiceWorker object itself is a postMessage(), but that is unaffected by the registration attachment.
Assignee | ||
Comment 31•7 years ago
|
||
(In reply to Blake Kaplan (:mrbkap) from comment #29)
> ::: dom/serviceworkers/ServiceWorkerRegistration.cpp
> @@ +147,5 @@
> > + // to be moved to the redundant state.
> > + AutoTArray<RefPtr<ServiceWorker>, 3> oldWorkerList;
> > + oldWorkerList.AppendElement(mInstallingWorker.forget());
> > + oldWorkerList.AppendElement(mWaitingWorker.forget());
> > + oldWorkerList.AppendElement(mActiveWorker.forget());
>
> Can we use an initializer list here? `... oldWorkerList({
> mInstallingWorker.forget(), ... });`?
Wow, that works? I had no idea. I'll try it.
Assignee | ||
Comment 32•7 years ago
|
||
Attachment #8988274 -
Attachment is obsolete: true
Attachment #8989183 -
Flags: review+
Comment 33•7 years ago
|
||
Pushed by bkelly@mozilla.com:
https://hg.mozilla.org/integration/mozilla-inbound/rev/e79b0494417b
P1 Add a fallible nsIGlobalObject::GetServiceWorkerRegistration() method. r=mrbkap
https://hg.mozilla.org/integration/mozilla-inbound/rev/5a025ad59747
P2 Add the registration Id to the ServiceWorkerDescriptor. r=mrbkap
https://hg.mozilla.org/integration/mozilla-inbound/rev/f35e21f7239e
P3 Make ServiceWorker binding objects get or create a handle to their associated registration. r=mrbkap
https://hg.mozilla.org/integration/mozilla-inbound/rev/2ba0b36ac85d
P4 Route ServiceWorker state changes through the ServiceWorkerRegistration. r=mrbkap
https://hg.mozilla.org/integration/mozilla-inbound/rev/c9353d80e2f9
P5 Remove now-unused Listener logic in ServiceWorkerInfo. r=mrbkap
Comment 34•7 years ago
|
||
bugherder |
https://hg.mozilla.org/mozilla-central/rev/e79b0494417b
https://hg.mozilla.org/mozilla-central/rev/5a025ad59747
https://hg.mozilla.org/mozilla-central/rev/f35e21f7239e
https://hg.mozilla.org/mozilla-central/rev/2ba0b36ac85d
https://hg.mozilla.org/mozilla-central/rev/c9353d80e2f9
Status: ASSIGNED → RESOLVED
Closed: 7 years ago
status-firefox63:
--- → fixed
Resolution: --- → FIXED
Target Milestone: --- → mozilla63
Comment 35•7 years ago
|
||
bugherder |
You need to log in
before you can comment on or make changes to this bug.
Description
•