Skip to content
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

Avoid unnecessarily reopening the welcome page because of idle background process termination #2908

Merged
merged 2 commits into from
Sep 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions doc/permissions.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,6 @@ These permissions allow Privacy Badger to use the WebRequest and WebRequestBlock

## Tabs
Privacy Badger needs access to the tabs API so that the extension can detect which tab is active and which tabs are simply present in the background. The extension icon, badge and popup update to reflect the state of Privacy Badger. This often requires knowing the tab's URL. For example, updating the icon requires the URL in order to determine whether Privacy Badger should be shown as disabled on that tab. Privacy Badger also uses the tabs API for miscellaneous tasks such as opening or switching to the already open new user welcome page.

## Alarms
Privacy Badger uses the Alarms API to temporarily ensure the background process does not get terminated as idle when Privacy Badger needs it to perform some longer running asynchronous task. This workaround is used to help reopen the welcome page when it appears that the extension has been restarted because of interaction with the Private/Incognito browsing permision prompt, but not because of idle background process termination.
86 changes: 85 additions & 1 deletion src/js/background.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,13 @@ function Badger(from_qunit) {
self.isFirstRun = false;
self.isUpdate = false;

(function () {
let manifestJson = chrome.runtime.getManifest();
self.manifestVersion = manifestJson.manifest_version;
self.isEventPage = (utils.hasOwn(manifestJson.background, "persistent") &&
manifestJson.background.persistent === false);
}());

self.firstPartyDomainPotentiallyRequired = testCookiesFirstPartyDomain();

self.widgetList = [];
Expand Down Expand Up @@ -344,6 +351,79 @@ Badger.prototype = {
});
},

/**
* If the background process is an event page or a service worker,
* it can get terminated while the user is still on the welcome page.
*
* When the user spends >= 30s on the welcome page, the background process
* will get terminated and another welcome page will unexpectedly appear
* following any user action that restarts the background process.
*
* (We reopen the welcome page via firstRunTimerFinished, our workaround
* for restoring the welcome page when Firefox restarts the extension
* in response to interaction with the private browsing permission hanger.)
*
* Let's periodically call a low-overhead, no-side effects API to keep
* the background process running as long as the welcome page stays open.
*
* While extension alarm events reset the idle timer in both Firefox and
* Chrome, Chrome enforces a minimum resolution of one minute. However,
* since most extension API calls also reset the idle timer in Chrome,
* simply looking up whether the welcome page is still open is enough
* to reset the idle timer.
*/
keepBackgroundAliveForWelcomePage: function () {
let ALARM_NAME = "welcome-page-keepalive",
INTERVAL = 10000; // 10 secs

if (badger.manifestVersion == 2 && !badger.isEventPage) {
return; // noop
}

function getWelcomeTab(callback) {
chrome.tabs.query({
url: chrome.runtime.getURL("/skin/firstRun.html")
}, function (tabs) {
callback(tabs[0]);
});
}

function workaroundForChrome() {
setTimeout(function () {
getWelcomeTab(function (tab) {
if (tab) {
workaroundForChrome();
}
});
}, INTERVAL);
}

if (!badger.isEventPage) {
workaroundForChrome();
return;
}

// create an alarm that will reset the idle timer in Firefox
chrome.alarms.create(ALARM_NAME, {
when: Date.now() + INTERVAL
});

chrome.alarms.onAlarm.addListener(alarm => {
if (alarm.name != ALARM_NAME) {
return;
}
getWelcomeTab(function (tab) {
// if the welcome page is still open
if (tab) {
// create another alarm
chrome.alarms.create(ALARM_NAME, {
when: Date.now() + INTERVAL
});
}
});
});
},

initWelcomePage: function () {
let self = this,
privateStore = self.getPrivateSettings();
Expand All @@ -365,10 +445,14 @@ Badger.prototype = {
},

showWelcomePage: function () {
let settings = this.getSettings();
let self = this,
settings = self.getSettings();

if (settings.getItem("showIntroPage")) {
chrome.tabs.create({
url: chrome.runtime.getURL("/skin/firstRun.html")
}, function () {
self.keepBackgroundAliveForWelcomePage();
});
} else {
// don't remind users to look at the intro page either
Expand Down
1 change: 1 addition & 0 deletions src/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
},
"incognito": "spanning",
"permissions": [
"alarms",
"tabs",
"http://*/*",
"https://*/*",
Expand Down
17 changes: 9 additions & 8 deletions src/skin/js/firstRun.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@ $(function () {
$(".scroll-it").smoothScroll();

$(window).scroll(function () {
if (!already_set) {
if ($(window).scrollTop() > 400) {
already_set = true;
chrome.runtime.sendMessage({
type: "updateSettings",
data: { seenComic: true }
});
}
if (already_set) {
return;
}
if ($(window).scrollTop() > 400) {
already_set = true;
chrome.runtime.sendMessage({
type: "updateSettings",
data: { seenComic: true }
});
}
});
});