jrconlin / WebPushDataTestPage

Web Push Data Encryption Test Page
Mozilla Public License 2.0
15 stars 11 forks source link

A subscription with a different application server key already exists #26

Closed whoisterencelee closed 4 years ago

whoisterencelee commented 4 years ago

I tried the demo page on a mobile phone using Android Firefox 68.7

When I click subscription info, I get an error: "A subscription with a different application server key already exists"

I've never visited the demo page before.

BTW, this is the same error I get on my site as well.

I think the problem is on Android Firefox side. I tried to track down the problem: https://searchfox.org/mozilla-central/rev/97cb0a90bd053de87cd1ab7646d5565809166bb1/dom/push/Push.jsm#291 https://searchfox.org/mozilla-central/rev/97cb0a90bd053de87cd1ab7646d5565809166bb1/dom/push/PushService.jsm#1200 https://searchfox.org/mozilla-central/rev/97cb0a90bd053de87cd1ab7646d5565809166bb1/dom/push/PushRecord.jsm#262 https://searchfox.org/mozilla-central/source/dom/push/PushService.jsm#1166 https://searchfox.org/mozilla-central/source/dom/push/PushDB.jsm#273

I think this particular mobile brand isn't saving anything on the pushDB, but I haven't no idea how to continue.

jrconlin commented 4 years ago

Ok, weird. I do know that there are some issues with the test page, but those are more around getting the new permissions working, which are definitely not a problem for your version of firefox.

I've filed https://bugzilla.mozilla.org/show_bug.cgi?id=1630834 which should get picked up by the Android dev team. They may have more answers than I do. If you like, feel free to add yourself as a "cc:" and you'll stay up-to-date on it. They may have questions as well and it would be easiest for them to reach you that way.

whoisterencelee commented 4 years ago

Thanks. Yeah, it's weird, but it's super frustrating. I tried it on a bunch of phones and all the ones without Play Store seems to have this problem.

jrconlin commented 4 years ago

Oh, wait, the device doesn't have Google Play installed? That definitely explains what's going on (but not the error you're seeing).

FCM changed policies a year or so ago to only work on devices that support Google Play. I think the predecessor GCM was a bit more forgiving. That's why you're not able to connect. What's confusing, though, is the error message that you're seeing. The registration call should fail, but the return status code should indicate that the FCM service is unavailable for that device.

Sadly, i don't believe that there's support for websocket push on android. Mostly because it would drain your device's battery really fast since it would keep the device CPU and radio active pretty much non-stop.

I'll follow up on the bug I filed explaining this and hopefully get them to change the return error code to be a bit more clear about what's going on.

Sorry, but thanks!

whoisterencelee commented 4 years ago

That explains it, I wish the error code would explain it not as if I made a mistake, but that the system doesn't support it.

I heard about the websocket solution which I think is being used by some push service providers, but additional battery drain is not acceptable.

The thing is a lot of phones in Asia and especially in China doesn't have Play. I still haven't figured out a good way to do push. One thing I don't quite understand is that Firefox uses it's own push service for endpoints, but is it true the notification is still sent to the devices using FCM?

jrconlin commented 4 years ago

So, i've been thinking about that a lot, since a bunch of folks keep asking. I really ought to put up a blog post about it.

In lieu of that, let me write down what I've been thinking about.

What WebPush is

Yeah, I know you probably understand, but I want to write down what I'm thinking so that there's less confusion. A WebPush message is a short message that's sent from some server to your device. There are a bunch of extra bits that can be layered on, like encryption, quick delivery, bi-directional support, but ultimately, it's "here's a message, please send it to this user".

How it works for desktop

Desktop is really simple, mostly because there are no strict power concerns and for the most part, machines aren't constantly moving around. Those machines can set up semi-permanent bi-directional connections to a bank of well known servers. (Mozilla runs autopush on a swarm of boxes. We use websocket. Google has something similar but uses gRPC. Apple does HTTP2, etc.) For the most part, these connections are idle since folks aren't getting a ton of messages send to them.

How it works for mobile

Mobile devices don't want to be on. They're very aggressive about trimming battery use. They will shut down the CPU and the radio at any opportunity. They'll also point and howl at any app that they feel is using "too much battery". The problem there is that if your app keeps a constant connection open back to a server, the CPU and radio won't go to sleep (since that would break the connection) and the OS will howl about how your app is terrible. Users will shut it down.

The "solution" is to use whatever native Push system is provided on your device. Device makers can and do use all sorts of internal tricks to keep that connection open, and they're very forgiving about their own actions. The problem is that since it costs money to provide that sort of thing, as in someone in Accounts Payable screaming about why their bill has so many zeros.

(By the way, it's not free for us to provide it either. So next time you want to buy something online, if you'd do a search for it in the AwesomeBar, click through one of the ads, and buy it that way, we'd REALLY appreciate it.)

That's why Google moved their messaging systems (and a lot of other features) under the Google Play app. They have to pay to keep the machines that devices connect to, so they want some form of payment.

Alternate solutions

So, if you've got an off-brand Android phone, it's probably using the Open Source release of Android, which does not have Google Play. Honestly, it probably doesn't have a lot of services. So what options are there?

1) Polling. This is probably the easiest. When your app is active (or if you set up a timer) you could have it poll a well known server address and check to see if there are any messages. You want to be careful with this, to avoid "stampedes" where all the devices suddenly check at once and swamp your servers. You can randomize things a bit, but I've also seen some devices that "helpfully" round sleep timers to a nearest interval (e.g. you thought you said sleep for 5 minutes? Oh, well, we slept for 15 since that means less CPU.) Some experimentation and monitoring your servers may be required. Pro: here is that it's fairly straightforward and simple to do. Con: it's not exactly "timely". Good for "Remember John's Birthday tomorrow" less for "your tea kettle is boiling".

2) Active Reception This one is a bit trickier. Basically, when your app is active, it connects to your servers using WebSocket, HTTP/2 or whatever protocol and actively pulls and listens for messages. This can provide much faster message deliveries while the user is present and attentive. Pro: Quick message delivery with feedback. Con: Could be complex and doesn't work when the device is sleeping.

3) Combo This one combines the two above steps. You have a small stub program that checks a URL to see if there are any messages pending, and if so, spins up your app to do a full connection. The connection processes everything, then lets the device go back to sleep. Pro: Almost exactly like Push, sort of. Con: Complex, and probably buggy. Dances the line between "efficient" and "here come the howler monkeys"

Not sure if this really helps, but hopefully gives y'all something to think about.

whoisterencelee commented 4 years ago

Very good explanation, I guess use webpush for desktop, and for mobile maybe piggyback on email or some other chat service.