-
Notifications
You must be signed in to change notification settings - Fork 56
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Inconsistency: Alarms API time slipping #433
Comments
Hi @bershanskiy! |
There is a bug filed (I need to find it).
Ideally, yes, there should be a standard reasonably simple behavior for all browsers. Unfortunately, extensions may have adopted to the current (in my opinion slightly odd) behavior and changing current implementation details might introduce some incompatibilities. |
Safari calculate alarms by always using wall clock no matter what type of alarm. And repeating alarms are off that original first fire wall clock, not chained from when it fires. |
Some more Chromium-specific context is available here: darkreader/darkreader#11307 (comment) The following Chromium patch replaces diff --git a/extensions/browser/api/alarms/alarm_manager.cc b/extensions/browser/api/alarms/alarm_manager.cc
index 48d7f83388..c008a5a090 100644
--- a/extensions/browser/api/alarms/alarm_manager.cc
+++ b/extensions/browser/api/alarms/alarm_manager.cc
@@ -357,7 +357,7 @@ void AlarmManager::ReadFromStorage(const std::string& extension_id,
void AlarmManager::SetNextPollTime(const base::Time& time) {
next_poll_time_ = time;
- timer_.Start(FROM_HERE, std::max(base::Seconds(0), time - clock_->Now()),
+ timer_.Start(FROM_HERE, time,
this, &AlarmManager::PollAlarms);
}
diff --git a/extensions/browser/api/alarms/alarm_manager.h b/extensions/browser/api/alarms/alarm_manager.h
index c23f78a457..1f223f9eb7 100644
--- a/extensions/browser/api/alarms/alarm_manager.h
+++ b/extensions/browser/api/alarms/alarm_manager.h
@@ -19,6 +19,7 @@
#include "base/scoped_observation.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
+#include "base/timer/wall_clock_timer.h"
#include "extensions/browser/browser_context_keyed_api_factory.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/extension_registry_observer.h"
@@ -245,7 +246,7 @@ class AlarmManager : public BrowserContextKeyedAPI,
extension_registry_observation_{this};
// The timer for this alarm manager.
- base::OneShotTimer timer_;
+ base::WallClockTimer timer_;
// A map of our pending alarms, per extension.
// Invariant: None of the AlarmLists are empty. |
The following describes experiment in Chrome and in Firefox, and then provides explanation for this behavior in Chrome. Experiment 1Consider an empty extension which just has Run this to log all alarms as they fire (alarm and the moment it fires): chrome.alarms.onAlarm.addListener((a) => console.log(Date.now(), a)) Then create one alarm which is supposed to fire in chrome.alarms.create('test', {when: Date.now() + 1000 * 60 * 5}); Then put your laptop to sleep (best to activate sleep mode explicitly) Then wait for Calculate alarm delay which is the difference of logged of Experiment 2Do all the steps in experiment 1 until waking up, and then after wake up run chrome.alarms.create('reset', {when: 0}); Observe that Experiment 3This time install two extensions like this (just use a different extension file path and name in manifest to differentiate the two). Register the alarm from the experiment 1 in one extension, then suspend and wake up, then schedule Explanation for ChromeAlarms API is implemented by
[1] https://github.com/chromium/chromium/blob/main/extensions/browser/api/alarms/alarm_manager.h#L248 |
During today's meeting I believe we identified two main questions that need to be resolved.
With regard to Question 1, I see two possible interpretations of the intent of
If the platform only supported one of these behaviors, developers could implement their own solutions to provide the other behavior. That said, I believe shimming B would be more resource intensive to implement in userland. |
I do worry Interpretation B is too subtle, and can be a footman for developers that don't know the difference. |
At TPAC, we decided we wanted to look at the behaviour of setTimeout and setInterval for past precedence. setTimeout seems to be in the spec here, which links to timer initialization steps, which links to run steps after a timeout. Here it says the following:
Fully active is defined as follows:
It's unclear if a document is "fully active" or a worker is "not suspended" when the device is asleep. Looking at the HTML spec repo, there is an issue discussing this problem. It seems like the behaviour is usually to use monotonic (non wall-clock time) but it is platform specific. We saw similar results testing at TPAC although Devlin did seem to see wall-clock time being used at one point - it's unclear what happened there. TLDR: It doesn't seem like there's a lot of clarity around this on the web either. I'll ask on the Google side to check the above summary is accurate, but I'm not sure that's going to give us an easy answer unfortunately. |
I spoke to some engineers on our side and confirmed that the behaviour documented here matches our understanding (all browsers seem to pause timers on sleep except on Windows). There isn't much consensus beyond that and this isn't covered by the spec. Since the most common implementation for Personally, I'm currently leaning towards always using wall clock time. That would be the opposite of what the web seems to do most often but would mean we could use the same clock for For repeating alarms that have fired more than once while a device was asleep, firing multiple seems undesirable so a good option could be firing once when the device wakes up (the explanation for this would be that the next instance only gets scheduled when the previous one fires). All of this is just my thoughts and thinking out loud though 🤷. I haven't spoken to the wider Chrome team for thoughts, although at TPAC we seemed generally open to anything reasonable that we could agree on. |
Following our latest public meeting and some discussion async, everyone seems aligned on the following behaviour:
|
Safari / WebKit bug: https://bugs.webkit.org/show_bug.cgi?id=265583 |
I just updated the WHATWG issue that Oliver linked with the following comment:
I wanted to share it here as I think it neatly summarizes my understanding of our current thinking. |
@bershanskiy, I was briefly looking at the Chromium implementation and it seems like we do have some logic for this here. However, you mentioned in a CL a while back that you thought Chromium still violated it. Is it possible none of us had noticed that code existed or is there still a reason why this isn't the case in Chromium? |
TL;DR
Alarms API alarm timing is not guaranteed when devices go to sleep.
Details
The documentation on Alarms API implies/suggests that the alarms internally uses absolute timestamps, fire nearly exactly at specified timestamps, and are independent from one another. In reality, the situation is a bit different:
This gives a rise to a few curious behaviors:
The text was updated successfully, but these errors were encountered: