Bug 233088 - Add support for onpushsubscriptionchange event handler
Summary: Add support for onpushsubscriptionchange event handler
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: New Bugs (show other bugs)
Version: WebKit Nightly Build
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Ben Nham
URL:
Keywords: InRadar
Depends on:
Blocks:
 
Reported: 2021-11-13 12:09 PST by Ben Nham
Modified: 2021-11-18 20:18 PST (History)
12 users (show)

See Also:


Attachments
Patch (33.41 KB, patch)
2021-11-13 12:12 PST, Ben Nham
no flags Details | Formatted Diff | Diff
Patch (32.30 KB, patch)
2021-11-13 12:14 PST, Ben Nham
no flags Details | Formatted Diff | Diff
Patch (43.54 KB, patch)
2021-11-17 07:14 PST, Ben Nham
no flags Details | Formatted Diff | Diff
Patch (44.35 KB, patch)
2021-11-17 10:30 PST, Ben Nham
no flags Details | Formatted Diff | Diff
Patch (46.59 KB, patch)
2021-11-17 16:23 PST, Ben Nham
no flags Details | Formatted Diff | Diff
Patch (48.62 KB, patch)
2021-11-17 17:27 PST, Ben Nham
no flags Details | Formatted Diff | Diff
patch for landing (48.09 KB, patch)
2021-11-18 10:00 PST, Ben Nham
no flags Details | Formatted Diff | Diff
rebased patch for landing (47.96 KB, patch)
2021-11-18 12:10 PST, Ben Nham
no flags Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Ben Nham 2021-11-13 12:09:32 PST
Add support for onpushsubscriptionchange event handler
Comment 1 Ben Nham 2021-11-13 12:12:28 PST
Created attachment 444145 [details]
Patch
Comment 2 Radar WebKit Bug Importer 2021-11-13 12:13:30 PST
<rdar://problem/85378345>
Comment 3 Ben Nham 2021-11-13 12:14:28 PST
Created attachment 444146 [details]
Patch
Comment 4 Ben Nham 2021-11-15 22:22:18 PST
Comment on attachment 444146 [details]
Patch

I can't repro the timeout in the ios-wk2 tests locally. Maybe there's something inherently flaky in the way I wrote the test that I'm not seeing yet.

I'd still like to get some feedback, so setting the r? flag.
Comment 5 youenn fablet 2021-11-16 00:37:56 PST
Comment on attachment 444146 [details]
Patch

Some comments below.
As of the test failures for iOS, it seems all spin tests have this issue on iOS simulator.
This might be worth some investigations.

View in context: https://bugs.webkit.org/attachment.cgi?id=444146&action=review

> Source/WebCore/testing/ServiceWorkerInternals.cpp:85
> +void ServiceWorkerInternals::schedulePushSubscriptionChangeEvent(RefPtr<PushSubscription> newSubscription, RefPtr<PushSubscription> oldSubscription)

I don't think this is good to directly use PushSubscription objects in SWContextManager::firePushSubscriptionChangeEvent.
PushSubscription should be created and live in worker thread. For instance it is refcounted, not thread safe refcounted.
And it has a ref to an ActiveDOMObject.

What can be done is to hop to the main thread with the necessary data to reconstruct PushSubscription objects at the time we fire the event.
This will also make SWContextManager::firePushSubscriptionChangeEvent easier to use when network process will send IPC messages.

One model is to reuse what we do for ServiceWorkerRegistration:
- Add a PushSubscriptionData similarly to ServiceWorkerRegistrationData. It should be encodable/decodable through IPC, and also have a cross thready copier.
- Pass PushSubscriptionData for old and new to SWContextManager::firePushSubscriptionChangeEvent, hop to worker thread and create PushSubscriptions from PushSubscriptionData.
- PushSubscription is fired on a service worker so I would guess the old registration has no ServiceWorkerRegistration and the new registration if not null would have the registration of the given worker, so no need to pass any info for the registration.

> Source/WebCore/testing/ServiceWorkerInternals.h:59
> +    void schedulePushSubscriptionChangeEvent(RefPtr<PushSubscription> newSubscription, RefPtr<PushSubscription> oldSubscription);

I would tend to use RefPtr<>&& instead of RefPtr<>
Comment 6 Ben Nham 2021-11-16 08:56:56 PST
(In reply to youenn fablet from comment #5)
> Comment on attachment 444146 [details]
> Patch
> 
> Some comments below.
> As of the test failures for iOS, it seems all spin tests have this issue on
> iOS simulator.
> This might be worth some investigations.

I've been looking into it, but I can only repro it locally right now if I run all the layout tests, not when I just run the tests in http/wpt/service-workers. This makes it pretty challenging to investigate.

> View in context:
> https://bugs.webkit.org/attachment.cgi?id=444146&action=review
> 
> > Source/WebCore/testing/ServiceWorkerInternals.cpp:85
> > +void ServiceWorkerInternals::schedulePushSubscriptionChangeEvent(RefPtr<PushSubscription> newSubscription, RefPtr<PushSubscription> oldSubscription)
> 
> I don't think this is good to directly use PushSubscription objects in
> SWContextManager::firePushSubscriptionChangeEvent.
> PushSubscription should be created and live in worker thread. For instance
> it is refcounted, not thread safe refcounted.
> And it has a ref to an ActiveDOMObject.
> 
> What can be done is to hop to the main thread with the necessary data to
> reconstruct PushSubscription objects at the time we fire the event.
> This will also make SWContextManager::firePushSubscriptionChangeEvent easier
> to use when network process will send IPC messages.
>
> One model is to reuse what we do for ServiceWorkerRegistration:
> - Add a PushSubscriptionData similarly to ServiceWorkerRegistrationData. It
> should be encodable/decodable through IPC, and also have a cross thready
> copier.
> - Pass PushSubscriptionData for old and new to
> SWContextManager::firePushSubscriptionChangeEvent, hop to worker thread and
> create PushSubscriptions from PushSubscriptionData.
> - PushSubscription is fired on a service worker so I would guess the old
> registration has no ServiceWorkerRegistration and the new registration if
> not null would have the registration of the given worker, so no need to pass
> any info for the registration.

I see, that makes sense. I already created a PushSubscriptionData in a previous patch for cross-thread copying so I'll use that instead.
Comment 7 Ben Nham 2021-11-17 07:14:50 PST
Created attachment 444518 [details]
Patch
Comment 8 youenn fablet 2021-11-17 08:12:01 PST
Comment on attachment 444518 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=444518&action=review

> Source/WebCore/Modules/push-api/PushSubscription.h:70
>      String m_endpoint;

Would it make sense to store a PushSubscriptionData in PushSubscription?
Then we could have a data() getter, and constructor would take less parameters.

> Source/WebCore/Modules/push-api/PushSubscriptionData.h:47
> +    WEBCORE_EXPORT static PushSubscriptionData create(const PushSubscription&);

No longer needed if we add a const PushSubscriptionData& data() const (or  PushSubscriptionData data() const) to PushSubscription.

> Source/WebCore/Modules/push-api/PushSubscriptionData.h:55
> +Ref<PushSubscription> createPushSubscriptionFromData(RefPtr<ServiceWorkerRegistration>, PushSubscriptionData&&);

If we pass to the constructor/create a PushSubscriptionData, we no longer need that method.

> Source/WebCore/testing/ServiceWorkerInternals.cpp:86
> +void ServiceWorkerInternals::schedulePushSubscriptionChangeEvent(RefPtr<PushSubscription>&& newSubscription, RefPtr<PushSubscription>&& oldSubscription)

Can we just take PushSubscription* parameters?

> Source/WebCore/workers/service/context/ServiceWorkerThread.cpp:252
> +            oldSubscription = createPushSubscriptionFromData(nullptr, WTFMove(*oldSubscriptionData));

Seems a bit strange to have nullptr here.
I guess we could have a PushSubscription::create(PushSubscriptionData&&, RefPtr<>&& = nulltr);
Also, we should be able to call unsubscribe on the new subscription, which probably requires to pass a ServiceWorkerRegistration.
In that case, we should be able to get it from the ServiceWorkerGlobalScope.

> Source/WebCore/workers/service/context/ServiceWorkerThreadProxy.cpp:328
> +        oldSubscriptionData = oldSubscriptionData->isolatedCopy();

I am not sure this is needed. If the issue is about std::optional, we can hopefully use crossThreadCopy.
Something like:
thread().runLoop().postTask([this, protectedThis = Ref { *this }, newSubscriptionData = crossThreadCopy(WTFMove(newSubscriptionData)), ...
Comment 9 Ben Nham 2021-11-17 10:30:16 PST
Created attachment 444534 [details]
Patch
Comment 10 Ben Nham 2021-11-17 16:23:25 PST
Created attachment 444597 [details]
Patch
Comment 11 Ben Nham 2021-11-17 17:27:44 PST
Created attachment 444615 [details]
Patch
Comment 12 Ben Nham 2021-11-17 20:02:36 PST
Comment on attachment 444615 [details]
Patch

I think I addressed all the feedback. One difference is that I kept two PushSubscription constructors rather than using a default parameter. This is mainly because Internals calls the constructor and calling the constructor with a RefPtr<ServiceWorkerRegistration> parameter would require us to export ServiceWorkerRegistration due to the way RefPtr works. It seems cleaner to not export that object purely for testing purposes (although i could do that instead if you prefer).
Comment 13 youenn fablet 2021-11-17 22:48:20 PST
Comment on attachment 444615 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=444615&action=review

> Source/WebCore/Modules/push-api/PushSubscription.cpp:50
> +    , m_serviceWorkerRegistration(WTFMove(registration))

Let's have just one constructor, taking a RefPtr<>

> Source/WebCore/Modules/push-api/PushSubscription.h:70
> +    PushSubscription(PushSubscriptionData&&, Ref<ServiceWorkerRegistration>&&);

I am not sure why we want to limit exporting.
If we want that, I would tend to have a dedicated create method:
WEBCORE_EXPORT static Ref<PushSubscription> create(PushSubscriptionData&&) instead of two constructors.

> Source/WebCore/Modules/push-api/PushSubscriptionData.cpp:31
> +#include "ServiceWorkerRegistration.h"

No longer needed?

> Source/WebCore/Modules/push-api/PushSubscriptionData.cpp:-41
> -

No longer needed?

> Source/WebCore/Modules/push-api/PushSubscriptionData.h:32
> +#include <wtf/Forward.h>

No longer needed?

> Source/WebCore/Modules/push-api/PushSubscriptionData.h:39
> +

No longer needed?

> Source/WebCore/workers/service/context/ServiceWorkerThreadProxy.cpp:327
> +    thread().runLoop().postTask([this, protectedThis = Ref { *this }, newSubscriptionData = crossThreadCopy(newSubscriptionData), oldSubscriptionData = crossThreadCopy(oldSubscriptionData)](auto&) mutable {

We would write it as newSubscriptionData = crossThreadCopy(WTFMove(newSubscriptionData)), in case we want to have an optimised isolatedCopy() && on PushSubscriptionData in the future.
Comment 14 Ben Nham 2021-11-18 10:00:18 PST
Created attachment 444694 [details]
patch for landing
Comment 15 Ben Nham 2021-11-18 12:10:53 PST
Created attachment 444714 [details]
rebased patch for landing
Comment 16 EWS 2021-11-18 20:18:21 PST
Committed r286044 (244431@main): <https://commits.webkit.org/244431@main>

All reviewed patches have been landed. Closing bug and clearing flags on attachment 444714 [details].