Last active
April 26, 2024 21:54
-
-
Save rhelmer/501b8badb93fa270dbc642953889f754 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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