Skip to content

Instantly share code, notes, and snippets.

@rhelmer
Last active April 26, 2024 21:54
Show Gist options
  • Save rhelmer/501b8badb93fa270dbc642953889f754 to your computer and use it in GitHub Desktop.
Save rhelmer/501b8badb93fa270dbc642953889f754 to your computer and use it in GitHub Desktop.
# HG changeset patch
# User Robert Helmer <[email protected]>
# Date 1566713264 25200
# Sat Aug 24 23:07:44 2019 -0700
# Node ID fff97a76d75a6d0cd71e6c3dc30fe9d02bf0010c
# Parent 5c329d928cb98e1d7e5973490a2e1592500f0ce5
Bug WIP - add new FirstStartup service and --first-startup post-install flag.
FirstStartup provides an optional mechanism to run synchronous services
before the UI appears. This is intended to be called as a post-install
action from an installer, such as the Windows Stub Installer, to allow
for downloading critical data and performance tuning before the first
run of a new Firefox install.
diff --git a/browser/components/BrowserContentHandler.jsm b/browser/components/BrowserContentHandler.jsm
--- a/browser/components/BrowserContentHandler.jsm
+++ b/browser/components/BrowserContentHandler.jsm
@@ -19,6 +19,7 @@ XPCOMUtils.defineLazyModuleGetters(this,
BrowserWindowTracker: "resource:///modules/BrowserWindowTracker.jsm",
HeadlessShell: "resource:///modules/HeadlessShell.jsm",
HomePage: "resource:///modules/HomePage.jsm",
+ FirstStartup: "resource://gre/modules/FirstStartup.jsm",
LaterRun: "resource:///modules/LaterRun.jsm",
PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.jsm",
SessionStartup: "resource:///modules/sessionstore/SessionStartup.jsm",
@@ -558,6 +559,10 @@ nsBrowserContentHandler.prototype = {
ShellService.setDefaultBrowser(true, true);
}
+ if (cmdLine.handleFlag("first-startup", false)) {
+ FirstStartup.init();
+ }
+
var fileParam = cmdLine.handleFlagWithParam("file", false);
if (fileParam) {
var file = cmdLine.resolveFile(fileParam);
@@ -599,6 +604,8 @@ nsBrowserContentHandler.prototype = {
info +=
" --search <term> Search <term> with your default search engine.\n";
info += " --setDefaultBrowser Set this app as the default browser.\n";
+ info +=
+ " --first-startup Run post-install actions before opening a new window.\n";
return info;
},
diff --git a/toolkit/modules/FirstStartup.jsm b/toolkit/modules/FirstStartup.jsm
new file mode 100644
--- /dev/null
+++ b/toolkit/modules/FirstStartup.jsm
@@ -0,0 +1,33 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+var EXPORTED_SYMBOLS = ["FirstStartup"];
+
+/**
+ * Service for blocking Firefox startup, to be used on the first install. The intended
+ * use case is for `FirstStartup` to be invoked when Firefox is called by an installer,
+ * such as the Windows Stub Installer, to allow Firefox to do some first-install tasks
+ * such as performance tuning and downloading critical data.
+ *
+ * In this scenario, the installer does not exit until the first Firefox window appears,
+ * which gives the user experience of Firefox starting up quickly on first install, and
+ * subsequent startups can defer such activities until after the window has appeared.
+ */
+var FirstStartup = {
+ initialied: false,
+ /**
+ * Initialize and run first-startup services. This will always run synchronously
+ * and spin the event loop until either all required services have
+ * completed, or until a timeout is reached.
+ *
+ * In the latter case, servies are expected to run post-UI instead as usual.
+ */
+ init() {
+ this.initialied = true;
+ },
+
+ get isInitialized() {
+ return this.initialied;
+ },
+};
diff --git a/toolkit/modules/moz.build b/toolkit/modules/moz.build
--- a/toolkit/modules/moz.build
+++ b/toolkit/modules/moz.build
@@ -188,6 +188,7 @@ EXTRA_JS_MODULES += [
'FinderHighlighter.jsm',
'FinderIterator.jsm',
'FinderParent.jsm',
+ 'FirstStartup.jsm',
'FormLikeFactory.jsm',
'Geometry.jsm',
'GMPExtractorWorker.js',
# HG changeset patch
# User Robert Helmer <[email protected]>
# Date 1566713754 25200
# Sat Aug 24 23:15:54 2019 -0700
# Node ID ba5d2eecc80d01eda01886c26b4d44ca63dccc69
# Parent fff97a76d75a6d0cd71e6c3dc30fe9d02bf0010c
Bug NNN - skip Normandy recipes with filter expressions incompatible with first-run.
diff --git a/toolkit/components/normandy/lib/RecipeRunner.jsm b/toolkit/components/normandy/lib/RecipeRunner.jsm
--- a/toolkit/components/normandy/lib/RecipeRunner.jsm
+++ b/toolkit/components/normandy/lib/RecipeRunner.jsm
@@ -30,6 +30,7 @@ XPCOMUtils.defineLazyModuleGetters(this,
CleanupManager: "resource://normandy/lib/CleanupManager.jsm",
Uptake: "resource://normandy/lib/Uptake.jsm",
ActionsManager: "resource://normandy/lib/ActionsManager.jsm",
+ FirstStartup: "resource://gre/modules/FirstStartup.jsm",
});
var EXPORTED_SYMBOLS = ["RecipeRunner"];
@@ -429,6 +430,33 @@ var RecipeRunner = {
* if an error occurred during evaluation.
*/
async shouldRunRecipe(recipe) {
+ /*
+ * TODO
+ *
+ * `normandy.os` currently depends on Telemetry Environment, which is not present at first-run,
+ * since Normandy uses the last archived Telemetry ping. If Normandy is starting by Firefox
+ * FirstStartup, then Telmementry Environment won't be initialized yet.
+ *
+ * Instead, this OS-specific info should be provided by the `CurrentEnvironment` directly
+ * and not depend on Telemetry.
+ *
+ * For a more complete solution, look into:
+ * 1) if Normandy can current environment instead of archived ping
+ * 2) if TelemetryEnvironment can run earlier (before the first window, at least)
+ */
+ if (
+ (FirstStartup.isInitialized &&
+ /normandy\.os/.test(recipe.filter_expression)) ||
+ /normandy\.telemetry\.main\.environment/.test(recipe.filter_expression)
+ ) {
+ log.debug(
+ `Skipping ${
+ recipe.name
+ } due to incompatible first-startup filter expression(s).`
+ );
+ return false;
+ }
+
const runnerCapabilities = this.getCapabilities();
if (Array.isArray(recipe.capabilities)) {
for (const recipeCapability of recipe.capabilities) {
# HG changeset patch
# User Robert Helmer <[email protected]>
# Date 1566714791 25200
# Sat Aug 24 23:33:11 2019 -0700
# Node ID c3d6242ea5a8073023ef086e5dad7632a6ba3238
# Parent ba5d2eecc80d01eda01886c26b4d44ca63dccc69
Bug NNN - add Normandy to FirstStartup service.
diff --git a/toolkit/modules/FirstStartup.jsm b/toolkit/modules/FirstStartup.jsm
--- a/toolkit/modules/FirstStartup.jsm
+++ b/toolkit/modules/FirstStartup.jsm
@@ -4,6 +4,18 @@
var EXPORTED_SYMBOLS = ["FirstStartup"];
+const { AppConstants } = ChromeUtils.import(
+ "resource://gre/modules/AppConstants.jsm"
+);
+const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
+const { XPCOMUtils } = ChromeUtils.import(
+ "resource://gre/modules/XPCOMUtils.jsm"
+);
+
+XPCOMUtils.defineLazyModuleGetters(this, {
+ Normandy: "resource://normandy/Normandy.jsm",
+});
+
/**
* Service for blocking Firefox startup, to be used on the first install. The intended
* use case is for `FirstStartup` to be invoked when Firefox is called by an installer,
@@ -25,6 +37,25 @@ var FirstStartup = {
*/
init() {
this.initialied = true;
+ const budget = 5 * 1000;
+ let expiredTime = Date.now() + budget;
+
+ if (AppConstants.MOZ_NORMANDY) {
+ let normandyInitialized = false;
+
+ Normandy.init().then(() => {
+ Normandy.finishInit().then(() => {
+ normandyInitialized = true;
+ });
+ });
+
+ Services.tm.spinEventLoopUntil(() => {
+ if (Date.now() >= expiredTime || normandyInitialized) {
+ return true;
+ }
+ return false;
+ });
+ }
},
get isInitialized() {
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment