forked from mozilla/gecko-dev
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Bug 1667276 - Part 2: Add BackgroundTasksManager to invoke task defin…
…ed in JS. r=mossop Differential Revision: https://phabricator.services.mozilla.com/D97512
- Loading branch information
Showing
13 changed files
with
356 additions
and
5 deletions.
There are no files selected for viewing
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
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
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
12 changes: 12 additions & 0 deletions
12
toolkit/components/backgroundtasks/BackgroundTask_exception.jsm
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- | ||
* 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 = ["runBackgroundTask"]; | ||
|
||
async function runBackgroundTask() { | ||
console.error("runBackgroundTask: exception"); | ||
|
||
throw new Error("test"); | ||
} |
12 changes: 12 additions & 0 deletions
12
toolkit/components/backgroundtasks/BackgroundTask_failure.jsm
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- | ||
* 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 = ["runBackgroundTask"]; | ||
|
||
async function runBackgroundTask() { | ||
console.error("runBackgroundTask: failure"); | ||
|
||
return 1; | ||
} |
12 changes: 12 additions & 0 deletions
12
toolkit/components/backgroundtasks/BackgroundTask_success.jsm
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- | ||
* 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 = ["runBackgroundTask"]; | ||
|
||
async function runBackgroundTask() { | ||
console.error("runBackgroundTask: success"); | ||
|
||
return 0; | ||
} |
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
134 changes: 134 additions & 0 deletions
134
toolkit/components/backgroundtasks/BackgroundTasksManager.jsm
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- | ||
* 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 = ["BackgroundTasksManager"]; | ||
|
||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm"); | ||
const { XPCOMUtils } = ChromeUtils.import( | ||
"resource://gre/modules/XPCOMUtils.jsm" | ||
); | ||
|
||
XPCOMUtils.defineLazyGetter(this, "log", () => { | ||
let ConsoleAPI = ChromeUtils.import("resource://gre/modules/Console.jsm", {}) | ||
.ConsoleAPI; | ||
let consoleOptions = { | ||
// tip: set maxLogLevel to "debug" and use log.debug() to create detailed | ||
// messages during development. See LOG_LEVELS in Console.jsm for details. | ||
maxLogLevel: "error", | ||
maxLogLevelPref: "toolkit.backgroundtasks.loglevel", | ||
prefix: "BackgroundTasksManager", | ||
}; | ||
return new ConsoleAPI(consoleOptions); | ||
}); | ||
|
||
// Map resource://testing-common/ to the shared test modules directory. This is | ||
// a transliteration of `register_modules_protocol_handler` from | ||
// https://searchfox.org/mozilla-central/rev/f081504642a115cb8236bea4d8250e5cb0f39b02/testing/xpcshell/head.js#358-389. | ||
function registerModulesProtocolHandler() { | ||
let env = Cc["@mozilla.org/process/environment;1"].getService( | ||
Ci.nsIEnvironment | ||
); | ||
let _TESTING_MODULES_URI = env.get("XPCSHELL_TESTING_MODULES_URI", ""); | ||
if (!_TESTING_MODULES_URI) { | ||
return false; | ||
} | ||
|
||
let protocolHandler = Services.io | ||
.getProtocolHandler("resource") | ||
.QueryInterface(Ci.nsIResProtocolHandler); | ||
|
||
protocolHandler.setSubstitution( | ||
"testing-common", | ||
Services.io.newURI(_TESTING_MODULES_URI) | ||
); | ||
// Log loudly so that when testing, we always actually use the | ||
// console logging mechanism and therefore deterministically load that code. | ||
log.error( | ||
`Substitution set: resource://testing-common aliases ${_TESTING_MODULES_URI}` | ||
); | ||
|
||
return true; | ||
} | ||
|
||
/** | ||
* Find a JSM named like `backgroundtasks/BackgroundTask_${name}.jsm` | ||
* and return its `runBackgroundTask` function. | ||
* | ||
* When testing, allow to load from `XPCSHELL_TESTING_MODULES_URI`, | ||
* which is registered at `resource://testing-common`, the standard | ||
* location for test-only modules. | ||
* | ||
* @return {function} `runBackgroundTask` function. | ||
* @throws NS_ERROR_NOT_AVAILABLE if a background task with the given `name` is | ||
* not found. | ||
*/ | ||
function findRunBackgroundTask(name) { | ||
const subModules = [ | ||
"resource:///modules", // App-specific first. | ||
"resource://gre/modules", // Toolkit/general second. | ||
]; | ||
|
||
if (registerModulesProtocolHandler()) { | ||
subModules.push("resource://testing-common"); // Test-only third. | ||
} | ||
|
||
for (const subModule of subModules) { | ||
let URI = `${subModule}/backgroundtasks/BackgroundTask_${name}.jsm`; | ||
log.debug(`Looking for background task at URI: ${URI}`); | ||
|
||
try { | ||
const { runBackgroundTask } = ChromeUtils.import(URI); | ||
log.info(`Found background task at URI: ${URI}`); | ||
return runBackgroundTask; | ||
} catch (ex) { | ||
if (ex.result != Cr.NS_ERROR_FILE_NOT_FOUND) { | ||
throw ex; | ||
} | ||
} | ||
} | ||
|
||
log.warn(`No backgroundtask named '${name}' registered`); | ||
throw new Components.Exception( | ||
`No backgroundtask named '${name}' registered`, | ||
Cr.NS_ERROR_NOT_AVAILABLE | ||
); | ||
} | ||
|
||
var BackgroundTasksManager = { | ||
async runBackgroundTaskNamed(name, commandLine) { | ||
function addMarker(markerName) { | ||
return ChromeUtils.addProfilerMarker(markerName, undefined, name); | ||
} | ||
addMarker("BackgroundTasksManager:AfterRunBackgroundTaskNamed"); | ||
|
||
log.info( | ||
`Running background task named '${name}' (with ${commandLine.length} arguments)` | ||
); | ||
|
||
let exitCode = 2; | ||
try { | ||
let runBackgroundTask = findRunBackgroundTask(name); | ||
addMarker("BackgroundTasksManager:AfterFindRunBackgroundTask"); | ||
|
||
try { | ||
// TODO: timeout tasks that run too long. | ||
exitCode = await runBackgroundTask(commandLine); | ||
log.info( | ||
`Backgroundtask named '${name}' completed with exit code ${exitCode}` | ||
); | ||
} catch (e) { | ||
log.error(`Backgroundtask named '${name}' threw exception`, e); | ||
exitCode = 3; | ||
} | ||
} finally { | ||
addMarker("BackgroundTasksManager:AfterAwaitRunBackgroundTask"); | ||
|
||
log.info(`Invoking Services.startup.quit(..., ${exitCode})`); | ||
Services.startup.quit(Ci.nsIAppStartup.eForceQuit, exitCode); | ||
} | ||
|
||
return exitCode; | ||
}, | ||
}; |
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
28 changes: 28 additions & 0 deletions
28
toolkit/components/backgroundtasks/nsIBackgroundTasksManager.idl
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ | ||
/* 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/. */ | ||
|
||
#include "nsISupports.idl" | ||
|
||
interface nsICommandLine; | ||
|
||
/** | ||
* Import and run named backgroundtask implementations. | ||
*/ | ||
[scriptable, function, uuid(4d48c536-e16f-4699-8f9c-add4f28f92f0)] | ||
interface nsIBackgroundTasksManager : nsISupports | ||
{ | ||
/** | ||
* Run the named background task. | ||
* | ||
* @param aTaskName the name of the task to be run. | ||
* @param aCommandLine the command line of this invocation. | ||
* | ||
* This returns a promise which resolves to an integer exit code, 0 when the | ||
* task succeeded, >0 otherwise. The task manager will quit after this | ||
* promise resolves. | ||
*/ | ||
void runBackgroundTaskNamed(in AString aTaskName, | ||
in nsICommandLine aCommandLine); | ||
}; |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- | ||
* vim: sw=4 ts=4 sts=4 et | ||
* 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/. */ | ||
|
||
"use strict"; | ||
|
||
const { AppConstants } = ChromeUtils.import( | ||
"resource://gre/modules/AppConstants.jsm" | ||
); | ||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm"); | ||
const { Subprocess } = ChromeUtils.import( | ||
"resource://gre/modules/Subprocess.jsm" | ||
); | ||
|
||
function getFirefoxExecutableFilename() { | ||
if (AppConstants.platform === "win") { | ||
return AppConstants.MOZ_APP_NAME + ".exe"; | ||
} | ||
return AppConstants.MOZ_APP_NAME; | ||
} | ||
|
||
// Returns a nsIFile to the firefox.exe (really, application) executable file. | ||
function getFirefoxExecutableFile() { | ||
let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile); | ||
file = Services.dirsvc.get("GreBinD", Ci.nsIFile); | ||
|
||
file.append(getFirefoxExecutableFilename()); | ||
return file; | ||
} | ||
|
||
async function do_backgroundtask( | ||
task, | ||
options = { extraArgs: [], extraEnv: {} } | ||
) { | ||
options = Object.assign({}, options); | ||
options.extraArgs = options.extraArgs || []; | ||
options.extraEnv = options.extraEnv || {}; | ||
|
||
let command = getFirefoxExecutableFile().path; | ||
let args = ["--backgroundtask", task]; | ||
args.push(...options.extraArgs); | ||
|
||
// Ensure `resource://testing-common` gets mapped. | ||
let protocolHandler = Services.io | ||
.getProtocolHandler("resource") | ||
.QueryInterface(Ci.nsIResProtocolHandler); | ||
|
||
let uri = protocolHandler.getSubstitution("testing-common"); | ||
Assert.ok(uri, "resource://testing-common is not substituted"); | ||
|
||
// The equivalent of _TESTING_MODULES_DIR in xpcshell. | ||
options.extraEnv.XPCSHELL_TESTING_MODULES_URI = uri.spec; | ||
|
||
// Now we can actually invoke the process. | ||
info( | ||
`launching child process ${command} with args: ${args} and extra environment: ${JSON.stringify( | ||
options.extraEnv | ||
)}` | ||
); | ||
let proc = await Subprocess.call({ | ||
command, | ||
arguments: args, | ||
environment: options.extraEnv, | ||
environmentAppend: true, | ||
stderr: "stdout", | ||
}).then(p => { | ||
p.stdin.close(); | ||
const dumpPipe = async pipe => { | ||
let data = await pipe.readString(); | ||
while (data) { | ||
for (let line of data.split(/\r\n|\r|\n/).slice(0, -1)) { | ||
dump("> " + line + "\n"); | ||
} | ||
data = await pipe.readString(); | ||
} | ||
}; | ||
dumpPipe(p.stdout); | ||
|
||
return p; | ||
}); | ||
|
||
let { exitCode } = await proc.wait(); | ||
return exitCode; | ||
} |
Oops, something went wrong.