From 25ee61d3cb7fb7849502a20cf0c4ba76afa65b3a Mon Sep 17 00:00:00 2001 From: lilia Date: Wed, 1 Mar 2017 13:11:40 -0800 Subject: [PATCH] Fix timers after suspend/resume/pause We use timers to decide when to query and delete expired messages or when to perform signed key rotations. Internally, timers are counters that get updated when the CPU ticks, so if the CPU sleeps, the timer will stop counting, and start again after it wakes up, ignoring the intervening passage of wall clock time. To fix this, without having to query the database or other potentially high overhead operations too often, use an interval to frequently check the wall clock time. If time jumps forward, trigger a global event so other listeners can update their possibly-inaccurate timers. https://stackoverflow.com/questions/6346849/what-happens-to-settimeout-when-the-computer-goes-to-sleep https://stackoverflow.com/questions/4079115/can-any-desktop-browsers-detect-when-the-computer-resumes-from-sleep // FREEBIE --- background.html | 1 + js/background.js | 3 ++- js/expiring_messages.js | 4 ++++ js/rotate_signed_prekey_listener.js | 5 +++++ js/wall_clock_listener.js | 25 +++++++++++++++++++++++++ 5 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 js/wall_clock_listener.js diff --git a/background.html b/background.html index 0d7df041..897c12c9 100644 --- a/background.html +++ b/background.html @@ -541,6 +541,7 @@ + diff --git a/js/background.js b/js/background.js index a893a8d6..b1a74221 100644 --- a/js/background.js +++ b/js/background.js @@ -87,8 +87,9 @@ openInbox(); } + WallClockListener.init(); RotateSignedPreKeyListener.init(); - ExpiringMessagesListener.update(); + ExpiringMessagesListener.init(); }); window.getSyncRequest = function() { diff --git a/js/expiring_messages.js b/js/expiring_messages.js index 096d0dfb..0d96b5a6 100644 --- a/js/expiring_messages.js +++ b/js/expiring_messages.js @@ -37,6 +37,10 @@ } window.ExpiringMessagesListener = { + init: function() { + checkExpiringMessages(); + window.events.on('timetravel', checkExpiringMessages); + }, update: checkExpiringMessages }; diff --git a/js/rotate_signed_prekey_listener.js b/js/rotate_signed_prekey_listener.js index aab636ff..d39349b7 100644 --- a/js/rotate_signed_prekey_listener.js +++ b/js/rotate_signed_prekey_listener.js @@ -53,6 +53,11 @@ scheduleNextRotation(); setTimeoutForNextRun(); }); + window.events.on('timetravel', function() { + if (Whisper.Registration.isDone()) { + setTimeoutForNextRun(); + } + }); } }; }()); diff --git a/js/wall_clock_listener.js b/js/wall_clock_listener.js new file mode 100644 index 00000000..cf25da58 --- /dev/null +++ b/js/wall_clock_listener.js @@ -0,0 +1,25 @@ +/* + * vim: ts=4:sw=4:expandtab + */ + +;(function () { + 'use strict'; + + var lastTime; + var interval = 1000; + function checkTime() { + var currentTime = Date.now(); + if (currentTime > (lastTime + interval * 2)) { + console.log('time travel detected!'); + window.events.trigger('timetravel'); + } + lastTime = currentTime; + } + + window.WallClockListener = { + init: function() { + lastTime = Date.now(); + setInterval(checkTime, 1000); + } + }; +}());